Skip to content

Commit 736b9b8

Browse files
committed
Enhance examples and core functionality with type consistency and new features
- Updated ObservableAnalogInput to use template for type flexibility - Added automatic update method to ObservableAnalogInput example - Improved accelerometer example with helper functions for clarity - Refactored PID examples to ensure consistent use of ObservableAnalogInput - Introduced new OperatorSelect for enhanced data transformation - Added comparison operators to data structures for better functionality - Updated main workflow to streamline build process - Created .gitignore for better repository management
1 parent 60af99c commit 736b9b8

File tree

18 files changed

+405
-89
lines changed

18 files changed

+405
-89
lines changed

.github/workflows/main.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ jobs:
44
build:
55
name: Build Examples
66
runs-on: ubuntu-latest
7+
env:
8+
pio-env: 'esp12e'
79
strategy:
810
matrix:
9-
pio-env: ['esp12e', 'esp32dev', 'uno', 'nanoatmega328']
1011
example: [
1112
'Blink/Blink.cpp',
1213
'Do/Do.cpp',
@@ -34,4 +35,4 @@ jobs:
3435
- name: Install PlatformIO
3536
run: python -m pip install platformio
3637
- name: Build firmware
37-
run: pio ci --lib="." --board ${{matrix.pio-env}} "examples/${{matrix.example}}"
38+
run: pio ci --lib="." --board ${{pio-env}} "examples/${{matrix.example}}"

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.pio
2+
.vscode/*

README.md

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,65 @@ More examples in Wiki/[Examples](https://github.com/luisllamasbinaburo/Arduino-R
5353
### Observable, observers and operators legend
5454
More info about the Observables, Observers, and Operators available in the [Wiki](https://github.com/luisllamasbinaburo/Arduino-ReactiveArduino/wiki)
5555
56-
![alt text](https://github.com/luisllamasbinaburo/Arduino-ReactiveArduino/blob/master/ReactiveArduino%20Legend.png "Legend")
56+
```
57+
┌─────────────────────────────────────────────────────────────────────────────────────┐
58+
│ 🔄 REACTIVE ARDUINO COMPONENT LEGEND 🔄 │
59+
├─────────────────────────────────────────────────────────────────────────────────────┤
60+
│ │
61+
│ 📡 OBSERVABLES (Data Sources) │
62+
│ ┌─────────────────────────────────────────────────────────────────────────────┐ │
63+
│ │ • FromArray() • FromProperty() • FromSerial() │ │
64+
│ │ • FromRange() • AnalogInput() • DigitalInput() │ │
65+
│ │ • TimerMillis() • TimerMicros() • IntervalMillis() │ │
66+
│ │ • Property<T>() • ManualDefer() • IntervalMicros() │ │
67+
│ └─────────────────────────────────────────────────────────────────────────────┘ │
68+
│ ⬇️ │
69+
│ 🔧 OPERATORS (Data Processing) │
70+
│ ┌─────────────────────────────────────────────────────────────────────────────┐ │
71+
│ │ • Where() • Distinct() • DistinctUntilChanged() │ │
72+
│ │ • First() • Last() • Skip() / Take() │ │
73+
│ │ • SkipWhile() • TakeWhile() • SkipUntil() / TakeUntil() │ │
74+
│ │ • Batch() • Repeat() • Loop() │ │
75+
│ └─────────────────────────────────────────────────────────────────────────────┘ │
76+
│ ⬇️ │
77+
│ 🔄 TRANSFORMATIONS (Data Conversion) │
78+
│ ┌─────────────────────────────────────────────────────────────────────────────┐ │
79+
│ │ • Select() • Map<T>() • Cast<T>() │ │
80+
│ │ • SelectTo<T>() • Reduce() • Scale() │ │
81+
│ │ • Limit() • LimitUpper() • LimitLower() │ │
82+
│ │ • Millis() • Micros() • Timestamp() │ │
83+
│ └─────────────────────────────────────────────────────────────────────────────┘ │
84+
│ ⬇️ │
85+
│ 🌡️ FILTERS (Conditional Processing) │
86+
│ ┌─────────────────────────────────────────────────────────────────────────────┐ │
87+
│ │ • IsEqual() • IsNotEqual() • IsGreater() / IsLess() │ │
88+
│ │ • IsZero() • IsNotZero() • OnRising() / OnFalling() │ │
89+
│ │ • DebounceMillis() • LowPass() • HighPass() │ │
90+
│ │ • MovingAverage() • Median3/5() • WindowMillis() │ │
91+
│ └─────────────────────────────────────────────────────────────────────────────┘ │
92+
│ ⬇️ │
93+
│ 📊 AGGREGATES (Statistical Operations) │
94+
│ ┌─────────────────────────────────────────────────────────────────────────────┐ │
95+
│ │ • Count() • CountDown() • Sum() │ │
96+
│ │ • Min() / Max() • Average() • RMS() │ │
97+
│ │ • Any() • All() • None() │ │
98+
│ └─────────────────────────────────────────────────────────────────────────────┘ │
99+
│ ⬇️ │
100+
│ 🎯 OBSERVERS (Data Consumers) │
101+
│ ┌─────────────────────────────────────────────────────────────────────────────┐ │
102+
│ │ • Do() • Finally() • DoAndFinally() │ │
103+
│ │ • ToSerial() • ToProperty() • ToArray() │ │
104+
│ │ • ToDigitalOutput() • ToAnalogOutput() • ToCircularBuffer() │ │
105+
│ │ • DoNothing() • (Custom Actions) │ │
106+
│ └─────────────────────────────────────────────────────────────────────────────┘ │
107+
│ │
108+
│ 💡 USAGE PATTERN: Observable → [Operators][Transformations][Filters] → │
109+
[Aggregates] → Observer │
110+
│ │
111+
│ Example: FromArray(data, size).Where(condition).Select(transform).ToSerial() │
112+
│ │
113+
└─────────────────────────────────────────────────────────────────────────────────────┘
114+
```
57115
58116
### Creating Observables
59117
Observables are generally generated through factory methods provided by the Reactive class.

examples/AccelerometerExample/AccelerometerExample.cpp

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,35 @@ Unless required by applicable law or agreed to in writing, software distributed
1010
#include "ReactiveArduinoLib.h"
1111
using namespace Reactive;
1212

13+
// Helper functions for type conversion
14+
float getMagnitude(AccelerometerData data) {
15+
return data.magnitude;
16+
}
17+
18+
float getTiltAngle(AccelerometerData data) {
19+
return atan2(data.y, data.x) * 180.0 / PI;
20+
}
21+
22+
bool magnitudeThreshold(float magnitude) {
23+
return magnitude > 1.2;
24+
}
25+
26+
void printStepCount(float magnitude) {
27+
static int stepCount = 0;
28+
stepCount++;
29+
Serial.print("Steps counted: ");
30+
Serial.println(stepCount);
31+
}
32+
33+
void printTiltBrightness(float mappedAngle) {
34+
int intAngle = (int)mappedAngle;
35+
Serial.print("Tilt mapped to LED brightness: ");
36+
Serial.println(intAngle);
37+
analogWrite(9, intAngle);
38+
}
39+
1340
// Example demonstrating accelerometer observable and scan operator
14-
auto accelerometer = ObservableAccelerometer<AccelerometerData>(A0, A1, A2, 100); // X, Y, Z pins, 100ms interval
15-
int stepCount = 0;
41+
auto accelerometer = Reactive::ObservableAccelerometer<AccelerometerData>(A3, A4, A5, 100); // X, Y, Z pins, 100ms interval
1642

1743
void setup()
1844
{
@@ -24,26 +50,16 @@ void setup()
2450

2551
// Step counter using scan operator
2652
accelerometer
27-
.Select([](AccelerometerData data) { return data.magnitude; })
28-
.Where([](float magnitude) { return magnitude > 1.2; }) // Motion threshold
53+
.Select(getMagnitude)
54+
.Where(magnitudeThreshold)
2955
.DistinctUntilChanged() // Only count distinct movements
30-
.Do([](float magnitude) {
31-
stepCount++; // Manual step counting for now
32-
Serial.print("Steps counted: ");
33-
Serial.println(stepCount);
34-
});
56+
.Do(printStepCount);
3557

3658
// Tilt detection
3759
accelerometer
38-
.Select([](AccelerometerData data) {
39-
return atan2(data.y, data.x) * 180.0 / PI; // Calculate tilt angle
40-
})
60+
.Select(getTiltAngle)
4161
.Scale(-90.0, 90.0, 0, 255) // Map angle to 0-255 range
42-
.Do([](int mappedAngle) {
43-
Serial.print("Tilt mapped to LED brightness: ");
44-
Serial.println(mappedAngle);
45-
analogWrite(9, mappedAngle); // Control LED brightness with tilt
46-
});
62+
.Do(printTiltBrightness);
4763
}
4864

4965
void loop()
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/***************************************************
2+
Copyright (c) 2019 Luis Llamas
3+
(www.luisllamas.es)
4+
5+
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6+
7+
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License
8+
****************************************************/
9+
10+
#include "ReactiveArduinoLib.h"
11+
using namespace Reactive;
12+
13+
// ObservableAnalogInput Update() Method Example
14+
// Demonstrates automatic timer-based analog input reading
15+
16+
// Create analog input observable with automatic 500ms update interval
17+
auto analogSensor = ObservableAnalogInput<int>(A0, 500);
18+
19+
// Helper function for printing values
20+
void printAnalogValue(int value) {
21+
Serial.print("Analog Value: ");
22+
Serial.print(value);
23+
Serial.print(" (");
24+
Serial.print((value / 1023.0) * 100.0);
25+
Serial.println("%)");
26+
}
27+
28+
// Helper function for voltage conversion
29+
float convertToVoltage(int adcValue) {
30+
return (adcValue / 1023.0) * 5.0; // Assuming 5V reference
31+
}
32+
33+
// Helper function for printing voltage
34+
void printVoltage(float voltage) {
35+
Serial.print("Voltage: ");
36+
Serial.print(voltage);
37+
Serial.println("V");
38+
}
39+
40+
// Helper function for printing smoothed voltage
41+
void printSmoothedVoltage(float smoothedVoltage) {
42+
Serial.print("Smoothed Voltage: ");
43+
Serial.print(smoothedVoltage);
44+
Serial.println("V (5-sample average)");
45+
}
46+
47+
void setup()
48+
{
49+
Serial.begin(115200);
50+
while (!Serial) delay(1);
51+
52+
Serial.println("=== ObservableAnalogInput Update() Example ===");
53+
Serial.println("Reading A0 every 500ms automatically using Update() method");
54+
Serial.println("Raw ADC values and voltage conversion will be displayed");
55+
56+
// Chain 1: Display raw ADC values
57+
analogSensor
58+
.Do(printAnalogValue);
59+
60+
// Chain 2: Convert to voltage and display
61+
analogSensor
62+
.Map<float>(convertToVoltage)
63+
.Do(printVoltage);
64+
65+
// Chain 3: Demonstrate filtering with automatic updates
66+
analogSensor
67+
.Map<float>(convertToVoltage)
68+
.MovingAverage(5) // 5-sample moving average
69+
.Do(printSmoothedVoltage);
70+
71+
Serial.println("Setup complete. Automatic updates every 500ms...");
72+
}
73+
74+
void loop()
75+
{
76+
// Call Update() to trigger automatic timer-based reading
77+
analogSensor.Update();
78+
79+
// You can also manually trigger readings using Next()
80+
// analogSensor.Next(); // Immediate reading, ignoring timer
81+
82+
// Change interval dynamically if needed
83+
static unsigned long lastIntervalChange = 0;
84+
if (millis() - lastIntervalChange > 10000) { // Every 10 seconds
85+
static bool fastMode = false;
86+
fastMode = !fastMode;
87+
88+
if (fastMode) {
89+
analogSensor.SetInterval(100); // Fast: 100ms
90+
Serial.println(">> Switched to FAST mode (100ms intervals)");
91+
} else {
92+
analogSensor.SetInterval(1000); // Slow: 1000ms
93+
Serial.println(">> Switched to SLOW mode (1000ms intervals)");
94+
}
95+
96+
lastIntervalChange = millis();
97+
}
98+
99+
// The loop can do other work while analog reading happens automatically
100+
delay(10); // Small delay to prevent tight loop
101+
}

examples/DistinctExample/DistinctExample.cpp

Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,21 @@ Unless required by applicable law or agreed to in writing, software distributed
1010
#include "ReactiveArduinoLib.h"
1111
using namespace Reactive;
1212

13+
// Helper functions for actions
14+
void printValue(int value) {
15+
Serial.print(value);
16+
Serial.print(" ");
17+
}
18+
19+
void printNewline() {
20+
Serial.println();
21+
}
22+
23+
void printUniqueValue(int uniqueValue) {
24+
Serial.print("New unique sensor value: ");
25+
Serial.println(uniqueValue);
26+
}
27+
1328
// Example demonstrating the difference between Distinct and DistinctUntilChanged
1429
int values[] = { 1, 2, 3, 2, 4, 1, 5, 3, 6, 2, 1 };
1530
int valuesLength = sizeof(values) / sizeof(values[0]);
@@ -23,35 +38,17 @@ void setup()
2338

2439
Serial.println("\nOriginal sequence:");
2540
FromArray(values, valuesLength)
26-
.Do([](int value) {
27-
Serial.print(value);
28-
Serial.print(" ");
29-
})
30-
.Finally([]() {
31-
Serial.println();
32-
});
41+
.DoAndFinally(printValue, printNewline);
3342

3443
Serial.println("\nWith Distinct() - removes ALL duplicates:");
3544
FromArray(values, valuesLength)
3645
.Distinct() // New operator: removes all duplicate values
37-
.Do([](int value) {
38-
Serial.print(value);
39-
Serial.print(" ");
40-
})
41-
.Finally([]() {
42-
Serial.println();
43-
});
46+
.DoAndFinally(printValue, printNewline);
4447

4548
Serial.println("\nWith DistinctUntilChanged() - removes consecutive duplicates only:");
4649
FromArray(values, valuesLength)
4750
.DistinctUntilChanged() // Existing operator: removes only consecutive duplicates
48-
.Do([](int value) {
49-
Serial.print(value);
50-
Serial.print(" ");
51-
})
52-
.Finally([]() {
53-
Serial.println();
54-
});
51+
.DoAndFinally(printValue, printNewline);
5552

5653
Serial.println("\n=== Sensor Reading Example ===");
5754
Serial.println("Simulating sensor with noise and repeated readings...");
@@ -71,15 +68,11 @@ void loop()
7168
int currentReading = sensorReadings[readingIndex];
7269

7370
// Process with Distinct to get unique values only
74-
auto obs = Property<int>();
75-
obs.SetValue(currentReading);
71+
auto obs = FromArray(&currentReading, 1);
7672

7773
obs
7874
.Distinct()
79-
.Do([](int uniqueValue) {
80-
Serial.print("New unique sensor value: ");
81-
Serial.println(uniqueValue);
82-
});
75+
.Do(printUniqueValue);
8376

8477
readingIndex++;
8578
lastReading = millis();

examples/PIDMotorSpeedControl/PIDMotorSpeedControl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ using namespace Reactive;
1414
// Hardware: Encoder on pins 2&3, motor driver on pin 9, potentiometer on A0
1515

1616
auto encoder = ObservableRotaryEncoder<RotaryEncoderData>(2, 3);
17-
auto potentiometer = ObservableAnalogInput(A0, 100); // Read setpoint every 100ms
17+
auto potentiometer = ObservableAnalogInput<int>(A0, 100); // Read setpoint every 100ms
1818
auto speedTimer = IntervalMillis(250); // Calculate speed every 250ms
1919

2020
auto pidController = FilterPID<float>(0, 1.5, 0.2, 0.1, -255, 255);

0 commit comments

Comments
 (0)