Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/RELEASE_PROCESS.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ The release process is as follows:
8. All that remains is to update the master branch. Create a new `release_x.y.z_to_master` branch based
on `latest`. Run

bumpversion release
bumpversion patch

to bump the version to `x.y.z+1-alpha`.

Expand Down
15 changes: 12 additions & 3 deletions examples/analog_input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@
using namespace sensesp;

// SensESP builds upon the ReactESP framework. Every ReactESP application
// defines an "app" object vs defining a "main()" method.
ReactESP app([]() {
// must instantiate the "app" object.
reactesp::ReactESP app;

// The setup function performs one-time application initialization.
void setup() {

// Some initialization boilerplate when in debug mode...
#ifndef SERIAL_DEBUG_DISABLED
Expand Down Expand Up @@ -73,4 +76,10 @@ ReactESP app([]() {

// Start the SensESP application running
sensesp_app->start();
});
}

// The loop function is called in an endless loop during program execution.
// It simply calls `app.tick()` which will then execute all reactions as needed.
void loop() {
app.tick();
}
224 changes: 115 additions & 109 deletions examples/chain_counter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

#include "sensesp_app.h"
#include "sensesp_app_builder.h"
#include "system/lambda_consumer.h"
#include "sensors/digital_input.h"
#include "transforms/integrator.h"
#include "transforms/debounce.h"
#include "signalk/signalk_output.h"
#include "system/lambda_consumer.h"
#include "transforms/debounce.h"
#include "transforms/integrator.h"

using namespace sensesp;

Expand All @@ -24,14 +24,15 @@ using namespace sensesp;
* A bi-directional chain counter is possible, but this is not one.
*/

ReactESP app([]() {
ReactESP app;

void setup() {
SetupSerialDebug(115200);

SensESPAppBuilder builder;
sensesp_app = builder
.set_hostname("ChainCounter")
->set_wifi("YourSSID", "YourPassword")
->get_app();
sensesp_app = builder.set_hostname("ChainCounter")
->set_wifi("YourSSID", "YourPassword")
->get_app();

#ifdef ESP8266
uint8_t COUNTER_PIN = D7;
Expand All @@ -41,115 +42,120 @@ ReactESP app([]() {
uint8_t BUTTON_PIN = 34;
#endif

/**
* DigitalInputCounter will count the revolutions of the windlass with a
* Hall Effect Sensor connected to COUNTER_PIN. It will output its count
* every counter_read_delay ms, which can be configured in the Config UI at
* counter_config_path.
*/
unsigned int counter_read_delay = 1000;
String counter_config_path = "/chain_counter/read_delay";
auto *chain_counter = new DigitalInputCounter(COUNTER_PIN, INPUT_PULLUP, RISING,
counter_read_delay, counter_config_path);

/**
* An IntegratorT<int, float> called "accumulator" adds up all the counts it
* receives (which are ints) and multiplies each count by gypsy_circum, which is the
* amount of chain, in meters, that is moved by each revolution of the windlass. (Since
* gypsy_circum is a float, the output of this transform must be a float, which is why
* we use IntegratorT<int, float>). It can be configured in the Config UI at accum_config_path.
*/
float gypsy_circum = 0.32;
String accum_config_path = "/accumulator/circum";
auto* accumulator = new IntegratorT<int, float>(gypsy_circum, 0.0, accum_config_path);

/**
* There is no path for the amount of anchor rode deployed in the current Signal K
* specification. By creating an instance of SKMetaData, we can send a partial or full
* defintion of the metadata that other consumers of Signal K data might find useful.
* (For example, Instrument Panel will benefit from knowing the units to be displayed.)
* The metadata is sent only the first time the data value is sent to the server.
*/
SKMetadata* metadata = new SKMetadata();
/**
* DigitalInputCounter will count the revolutions of the windlass with a
* Hall Effect Sensor connected to COUNTER_PIN. It will output its count
* every counter_read_delay ms, which can be configured in the Config UI at
* counter_config_path.
*/
unsigned int counter_read_delay = 1000;
String counter_config_path = "/chain_counter/read_delay";
auto* chain_counter =
new DigitalInputCounter(COUNTER_PIN, INPUT_PULLUP, RISING,
counter_read_delay, counter_config_path);

/**
* An IntegratorT<int, float> called "accumulator" adds up all the counts it
* receives (which are ints) and multiplies each count by gypsy_circum, which
* is the amount of chain, in meters, that is moved by each revolution of the
* windlass. (Since gypsy_circum is a float, the output of this transform must
* be a float, which is why we use IntegratorT<int, float>). It can be
* configured in the Config UI at accum_config_path.
*/
float gypsy_circum = 0.32;
String accum_config_path = "/accumulator/circum";
auto* accumulator =
new IntegratorT<int, float>(gypsy_circum, 0.0, accum_config_path);

/**
* There is no path for the amount of anchor rode deployed in the current
* Signal K specification. By creating an instance of SKMetaData, we can send
* a partial or full defintion of the metadata that other consumers of Signal
* K data might find useful. (For example, Instrument Panel will benefit from
* knowing the units to be displayed.) The metadata is sent only the first
* time the data value is sent to the server.
*/
SKMetadata* metadata = new SKMetadata();
metadata->units_ = "m";
metadata->description_ = "Anchor Rode Deployed";
metadata->display_name_ = "Rode Deployed";
metadata->short_name_ = "Rode Out";

/**
* chain_counter is connected to accumulator, which is connected to an SKOutputNumber,
* which sends the final result to the indicated path on the Signal K server. (Note that
* each data type has its own version of SKOutput: SKOutputNumber for floats, SKOutputInt,
* SKOutputBool, and SKOutputString.)
*/
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't you eliminate the specific types of SKOutput, by making it a template type?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a template type, but for convenience, those specific types are still defined at the end of signalk_output.h:

typedef SKOutputNumeric<float> SKOutputFloat;
typedef SKOutputNumeric<int> SKOutputInt;
typedef SKOutput<bool> SKOutputBool;
typedef SKOutput<String> SKOutputString;

If it was just up to me, I would indeed have a mild preference for ditching those typedefs and just using the template syntax, but I've accepted the notion that there are SensESP users who're not comfortable with the C++ template class syntax and it's better to have the typedefs around. :-)

/**
* chain_counter is connected to accumulator, which is connected to an
* SKOutputNumber, which sends the final result to the indicated path on the
* Signal K server. (Note that each data type has its own version of SKOutput:
* SKOutputNumber for floats, SKOutputInt, SKOutputBool, and SKOutputString.)
*/
String sk_path = "navigation.anchor.rodeDeployed";
String sk_path_config_path = "/rodeDeployed/sk";

chain_counter->connect_to(accumulator)
->connect_to(new SKOutputFloat(sk_path, sk_path_config_path, metadata));



/**
* DigitalInputChange monitors a physical button connected to BUTTON_PIN. Because
* its interrupt type is CHANGE, it will emit a value when the button is pressed,
* and again when it's released, but that's OK - our LambdaConsumer function will
* act only on the press, and ignore the release. DigitalInputChange looks for a change
* every read_delay ms, which can be configured at read_delay_config_path in the Config UI.
*/
int read_delay = 10;
String read_delay_config_path = "/button_watcher/read_delay";
auto* button_watcher = new DigitalInputChange(BUTTON_PIN, INPUT, CHANGE, read_delay, read_delay_config_path);


/**
* Create a DebounceInt to make sure we get a nice, clean signal from the button.
* Set the debounce delay period to 15 ms, which can be configured at debounce_config_path
* in the Config UI.
*/
int debounce_delay = 15;
String debounce_config_path = "/debounce/delay";
auto* debounce = new DebounceInt(debounce_delay, debounce_config_path);


/**
* When the button is pressed (or released), it will call the lambda expression
* (or "function") that's called by the LambdaConsumer. This is the function - notice
* that it calls reset() only when the input is 1, which indicates a button press. It
* ignores the button release.
* If your button goes to GND when pressed, make it "if (input == 0)".
*/
auto reset_function = [accumulator](int input) {
if (input == 1) {
accumulator->reset(); // Resets the output to 0.0
}
};

/**
* Create the LambdaConsumer that calls reset_function, Because DigitalInputChange
* outputs an int, the version of LambdaConsumer we need is LambdaConsumer<int>.
*
* While this approach - defining the lambda function (above) separate from the
* LambdaConsumer (below) - is simpler to understand, there is a more concise approach:
*
auto* button_consumer = new LambdaConsumer<int>([accumulator](int input) {
->connect_to(new SKOutputFloat(sk_path, sk_path_config_path, metadata));

/**
* DigitalInputChange monitors a physical button connected to BUTTON_PIN.
* Because its interrupt type is CHANGE, it will emit a value when the button
* is pressed, and again when it's released, but that's OK - our
* LambdaConsumer function will act only on the press, and ignore the release.
* DigitalInputChange looks for a change every read_delay ms, which can be
* configured at read_delay_config_path in the Config UI.
*/
int read_delay = 10;
String read_delay_config_path = "/button_watcher/read_delay";
auto* button_watcher = new DigitalInputChange(
BUTTON_PIN, INPUT, read_delay, read_delay_config_path);

/**
* Create a DebounceInt to make sure we get a nice, clean signal from the
* button. Set the debounce delay period to 15 ms, which can be configured at
* debounce_config_path in the Config UI.
*/
int debounce_delay = 15;
String debounce_config_path = "/debounce/delay";
auto* debounce = new DebounceInt(debounce_delay, debounce_config_path);

/**
* When the button is pressed (or released), it will call the lambda
* expression (or "function") that's called by the LambdaConsumer. This is the
* function - notice that it calls reset() only when the input is 1, which
* indicates a button press. It ignores the button release. If your button
* goes to GND when pressed, make it "if (input == 0)".
*/
auto reset_function = [accumulator](int input) {
if (input == 1) {
accumulator->reset();
accumulator->reset(); // Resets the output to 0.0
}
});

*
*/
auto* button_consumer = new LambdaConsumer<int>(reset_function);


/* Connect the button_watcher to the debounce to the button_consumer. */
button_watcher->connect_to(debounce)
->connect_to(button_consumer);


/* Finally, start the SensESPApp */
sensesp_app->start();

});

};

/**
* Create the LambdaConsumer that calls reset_function, Because
DigitalInputChange
* outputs an int, the version of LambdaConsumer we need is
LambdaConsumer<int>.
*
* While this approach - defining the lambda function (above) separate from
the
* LambdaConsumer (below) - is simpler to understand, there is a more concise
approach:
*
auto* button_consumer = new LambdaConsumer<int>([accumulator](int input) {
if (input == 1) {
accumulator->reset();
}
});

*
*/
auto* button_consumer = new LambdaConsumer<int>(reset_function);

/* Connect the button_watcher to the debounce to the button_consumer. */
button_watcher->connect_to(debounce)->connect_to(button_consumer);

/* Finally, start the SensESPApp */
sensesp_app->start();
}

// The loop function is called in an endless loop during program execution.
// It simply calls `app.tick()` which will then execute all reactions as needed.
void loop() { app.tick(); }
12 changes: 10 additions & 2 deletions examples/fuel_level_sensor/fuel_level_sensor_example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@

using namespace sensesp;

ReactESP app([]() {
ReactESP app;

void setup() {
#ifndef SERIAL_DEBUG_DISABLED
SetupSerialDebug(115200);
#endif
Expand Down Expand Up @@ -39,4 +41,10 @@ ReactESP app([]() {
new SKOutputFloat("tanks.fuel.0.currentLevel"));

sensesp_app->start();
});
}

// The loop function is called in an endless loop during program execution.
// It simply calls `app.tick()` which will then execute all reactions as needed.
void loop() {
app.tick();
}
13 changes: 11 additions & 2 deletions examples/hysteresis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@

using namespace sensesp;

ReactESP app([]() {
ReactESP app;

void setup() {
SetupSerialDebug(115200);

SensESPAppBuilder builder;
Expand Down Expand Up @@ -49,4 +51,11 @@ ReactESP app([]() {
->connect_to(new SKOutputBool(sk_path));

sensesp_app->start();
});
}

// The loop function is called in an endless loop during program execution.
// It simply calls `app.tick()` which will then execute all reactions as needed.
void loop() {
app.tick();
}

12 changes: 10 additions & 2 deletions examples/lambda_transform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@

using namespace sensesp;

ReactESP app([]() {
ReactESP app;

void setup() {
SetupSerialDebug(115200);

// Create a new SensESPApp object. This is the direct constructor call, and
Expand Down Expand Up @@ -85,4 +87,10 @@ ReactESP app([]() {
->connect_to(new SKOutputFloat(sk_path));

sensesp_app->start();
});
}

// The loop function is called in an endless loop during program execution.
// It simply calls `app.tick()` which will then execute all reactions as needed.
void loop() {
app.tick();
}
14 changes: 11 additions & 3 deletions examples/milone_level_sensor/milone_level_sensor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,10 @@ class ETapeInterpreter : public CurveInterpolator
};

// SensESP builds upon the ReactESP framework. Every ReactESP application
// defines an "app" object vs defining a "main()" method.
ReactESP app([]() {
// defines an "app" object.
ReactESP app;

void setup() {

// Some initialization boilerplate when in debug mode...
#ifndef SERIAL_DEBUG_DISABLED
Expand Down Expand Up @@ -129,4 +131,10 @@ ReactESP app([]() {

// Start the SensESP application running
sensesp_app->start();
});
}

// The loop function is called in an endless loop during program execution.
// It simply calls `app.tick()` which will then execute all reactions as needed.
void loop() {
app.tick();
}
Loading