diff --git a/NodeManager.cpp b/NodeManager.cpp index 0e0eca1631262c4562027bb2a85e0f67e0c6b18e..bcee7dba9955c185105416e4434117ff70972403 100755 --- a/NodeManager.cpp +++ b/NodeManager.cpp @@ -2542,6 +2542,10 @@ void SensorMHZ19::onProcess(Request & request) { _send(_msg_service.set(function)); } +// what to do when receiving an interrupt +void SensorMHZ19::onInterrupt() { +} + #endif /* @@ -2620,6 +2624,10 @@ void SensorAM2320::onReceive(const MyMessage & message) { // what to do when receiving a remote message void SensorAM2320::onProcess(Request & request) { } + +// what to do when receiving an interrupt +void SensorAM2320::onInterrupt() { +} #endif /* @@ -2750,6 +2758,10 @@ void SensorTSL2561::onProcess(Request & request) { } _send(_msg_service.set(function)); } + +// what to do when receiving an interrupt +void SensorTSL2561::onInterrupt() { +} #endif /* @@ -2764,7 +2776,7 @@ SensorPT100::SensorPT100(NodeManager* node_manager, int child_id, int pin): Sens setValueType(TYPE_FLOAT); } -//// setter/getter +// setter/getter void SensorPT100::setVoltageRef(float value) { _voltageRef = value; } @@ -2784,7 +2796,6 @@ void SensorPT100::onSetup() { void SensorPT100::onLoop() { // read the PT100 sensor int temperature = _PT100->readTemperature(_pin); - #if DEBUG == 1 Serial.print(F("PT100 I=")); Serial.print(_child_id); @@ -2809,6 +2820,112 @@ void SensorPT100::onProcess(Request & request) { } _send(_msg_service.set(function)); } + +// what to do when receiving an interrupt +void SensorPT100::onInterrupt() { +} +#endif + +/* + SensorDimmer +*/ + +#if MODULE_DIMMER == 1 +// contructor +SensorDimmer::SensorDimmer(NodeManager* node_manager, int child_id, int pin): Sensor(node_manager, child_id, pin) { + // set presentation, type and value type + setPresentation(S_DIMMER); + setType(V_PERCENTAGE); +} + +// setter/getter +void SensorDimmer::setEasing(int value) { + _easing = value; +} +void SensorDimmer::setDuration(int value) { + _duration = value*1000; +} +void SensorDimmer::setStepDuration(int value) { + _duration = value; +} + +// what to do during before +void SensorDimmer::onBefore() { + pinMode(_pin, OUTPUT); +} + +// what to do during setup +void SensorDimmer::onSetup() { +} + +// what to do during loop +void SensorDimmer::onLoop() { +} + +// what to do as the main task when receiving a message +void SensorDimmer::onReceive(const MyMessage & message) { + if (message.getCommand() == C_SET) { + int percentage = message.getInt(); + // normalize the provided percentage + if (percentage < 0) percentage = 0; + if (percentage > 100) percentage = 100; + fadeTo(percentage); + _value_int = percentage; + } + if (message.getCommand() == C_REQ) { + // return the current status + _value_int = _percentage; + } +} + +// what to do when receiving a remote message +void SensorDimmer::onProcess(Request & request) { + int function = request.getFunction(); + switch(function) { + case 101: setEasing(request.getValueInt()); break; + case 102: setDuration(request.getValueInt()); break; + case 103: setStepDuration(request.getValueInt()); break; + default: return; + } + _send(_msg_service.set(function)); +} + +// what to do when receiving an interrupt +void SensorDimmer::onInterrupt() { +} + +// fade to the provided value +void SensorDimmer::fadeTo(int target_percentage) { + #if DEBUG == 1 + Serial.print(F("DIM I=")); + Serial.print(_child_id); + Serial.print(F(" V=")); + Serial.println(target_percentage); + #endif + // count how many steps we need to do + int steps = _duration / _step_duration; + // for each step + for (int current_step = 1; current_step <= steps; current_step++) { + // calculate the delta between the target value and the current + int delta = target_percentage - _percentage; + // calculate the smooth transition and adjust it in the 0-255 range + int value_to_write = (int)(_getEasing(current_step,_percentage,delta,steps) / 100. * 255); + // write to the PWM output + analogWrite(_pin,value_to_write); + // wait at the end of this step + wait(_step_duration); + } + _percentage = target_percentage; +} + +// for smooth transitions. t: current time, b: beginning value, c: change in value, d: duration +float SensorDimmer::_getEasing(float t, float b, float c, float d) { + if (_easing == EASE_INSINE) return -c * cos(t/d * (M_PI/2)) + c + b; + else if (_easing == EASE_OUTSINE) return c * sin(t/d * (M_PI/2)) + b; + else if (_easing == EASE_INOUTSINE) return -c/2 * (cos(M_PI*t/d) - 1) + b; + else return c*t/d + b; +} + #endif /******************************************* @@ -3149,6 +3266,12 @@ int NodeManager::registerSensor(int sensor_type, int pin, int child_id) { // register temperature sensor return registerSensor(new SensorPT100(this,child_id,pin)); } + #endif + #if MODULE_DIMMER == 1 + else if (sensor_type == SENSOR_DIMMER) { + // register the dimmer sensor + return registerSensor(new SensorDimmer(this,child_id,pin)); + } #endif else { #if DEBUG == 1 diff --git a/NodeManager.h b/NodeManager.h index 883b32095deef30606e20d33d5f12d5fc7fe8a63..a0f94b8282fb4904dc013b972f99cf9bc84bf45e 100755 --- a/NodeManager.h +++ b/NodeManager.h @@ -190,6 +190,10 @@ #ifndef MODULE_BMP280 #define MODULE_BMP280 0 #endif +// Enable this module to use one of the following sensors: SENSOR_DIMMER +#ifndef MODULE_DIMMER + #define MODULE_DIMMER 0 +#endif /*********************************** Supported Sensors @@ -299,6 +303,10 @@ enum supported_sensors { // BMP280 sensor, return temperature and pressure SENSOR_BMP280, #endif + #if MODULE_DIMMER == 1 + // Generic dimmer sensor used to drive a pwm output + SENSOR_DIMMER, + #endif }; /*********************************** @@ -376,6 +384,9 @@ enum supported_sensors { #include <Adafruit_Sensor.h> #include <Adafruit_BMP280.h> #endif +#if MODULE_DIMMER == 1 + #include <math.h> +#endif /******************************************************************* Classes @@ -1222,13 +1233,14 @@ class SensorMHZ19: public Sensor { SensorMHZ19(NodeManager* node_manager, int child_id, int pin); // set the pins for RX and TX of the SoftwareSerial (default: Rx=6, Tx=7) void setRxTx(int rxpin, int txpin); + int readCO2(); // define what to do at each stage of the sketch void onBefore(); void onSetup(); void onLoop(); void onReceive(const MyMessage & message); void onProcess(Request & request); - int readCO2(); + void onInterrupt(); protected: SoftwareSerial* _ser; int _tx_pin = 6; @@ -1249,6 +1261,7 @@ class SensorAM2320: public Sensor { void onLoop(); void onReceive(const MyMessage & message); void onProcess(Request & request); + void onInterrupt(); // constants const static int TEMPERATURE = 0; const static int HUMIDITY = 1; @@ -1279,6 +1292,7 @@ class SensorTSL2561: public Sensor { void onLoop(); void onReceive(const MyMessage & message); void onProcess(Request & request); + void onInterrupt(); // constants const static int ADDR_FLOAT = 0; const static int ADDR_LOW = 1; @@ -1316,12 +1330,50 @@ class SensorPT100: public Sensor { void onLoop(); void onReceive(const MyMessage & message); void onProcess(Request & request); + void onInterrupt(); protected: DFRobotHighTemperature* _PT100; float _voltageRef = 3.3; }; #endif +/* + SensorPT100 +*/ +#if MODULE_DIMMER == 1 +class SensorDimmer: public Sensor { + public: + SensorDimmer(NodeManager* node_manager, int child_id, int pin); + // [101] set the effect to use for a smooth transition, can be one of SensorDimmer::EASE_LINEAR, SensorDimmer::EASE_INSINE, SensorDimmer::EASE_OUTSINE, SensorDimmer::EASE_INOUTSINE (default: EASE_LINEAR) + void setEasing(int value); + // [102] the duration of entire the transition in seconds (default: 1) + void setDuration(int value); + // [103] the duration of a single step of the transition in milliseconds (default: 100) + void setStepDuration(int value); + // fade the output from the current value to the target provided in the range 0-100 + void fadeTo(int value); + enum easing { + EASE_LINEAR, + EASE_INSINE, + EASE_OUTSINE, + EASE_INOUTSINE, + }; + // define what to do at each stage of the sketch + void onBefore(); + void onSetup(); + void onLoop(); + void onReceive(const MyMessage & message); + void onProcess(Request & request); + void onInterrupt(); + protected: + int _percentage = 0; + int _easing = EASE_LINEAR; + int _duration = 1000; + int _step_duration = 100; + float _getEasing(float t, float b, float c, float d); +}; +#endif + /*************************************** NodeManager: manages all the aspects of the node */ diff --git a/NodeManager.ino b/NodeManager.ino index 3df7d4749d1c34e584a3d9ea91d0d291d4504046..e42bf43569716623021feac9af3f81754a5cce06 100755 --- a/NodeManager.ino +++ b/NodeManager.ino @@ -1,3 +1,4 @@ + /* NodeManager is intended to take care on your behalf of all those common tasks a MySensors node has to accomplish, speeding up the development cycle of your projects. NodeManager includes the following main components: diff --git a/README.md b/README.md index 122990f4da49d48b098060466e294ade1276c8f8..e5cb7f1695ea070b45b0219010c1a71026fe993f 100755 --- a/README.md +++ b/README.md @@ -209,7 +209,8 @@ The next step is to enable NodeManager's additional functionalities and the modu #define MODULE_PT100 0 // Enable this module to use one of the following sensors: SENSOR_BMP280 #define MODULE_BMP280 0 - +// Enable this module to use one of the following sensors: SENSOR_DIMMER +#define MODULE_DIMMER 0 ~~~ ### Installing the dependencies @@ -412,6 +413,7 @@ SENSOR_TSL2561 | TSL2561 sensor, return light in lux SENSOR_AM2320 | AM2320 sensors, return temperature/humidity based on the attached AM2320 sensor SENSOR_PT100 | High temperature sensor associated with DFRobot Driver, return the temperature in C° from the attached PT100 sensor SENSOR_BMP280 | BMP280 sensor, return temperature/pressure based on the attached BMP280 sensor +SENSOR_DIMMER | Generic dimmer sensor used to drive a pwm output To register a sensor simply call the NodeManager instance with the sensory type and the pin the sensor is conncted to and optionally a child id. For example: ~~~c @@ -688,6 +690,18 @@ Each sensor class can expose additional methods. void setAddress(int value); ~~~ +* SensorDimmer +~~~c + // [101] set the effect to use for a smooth transition, can be one of SensorDimmer::EASE_LINEAR, SensorDimmer::EASE_INSINE, SensorDimmer::EASE_OUTSINE, SensorDimmer::EASE_INOUTSINE (default: EASE_LINEAR) + void setEasing(int value); + // [102] the duration of entire the transition in seconds (default: 1) + void setDuration(int value); + // [103] the duration of a single step of the transition in milliseconds (default: 100) + void setStepDuration(int value); + // fade the output from the current value to the target provided in the range 0-100 + void fadeTo(int value); +~~~ + ### Upload your sketch Upload your sketch to your arduino board as you are used to. @@ -1350,6 +1364,7 @@ v1.6: * Added support for PT100 high temperature sensor * Added support for MH-Z19 CO2 sensor * Added buil-in rain and soil moisture analog sensors +* Added support for generic dimmer sensor (PWM output) * SensorRainGauge now supports sleep mode * SensorSwitch now supports awake mode * SensorLatchingRealy now handles automatically both on and off commands diff --git a/config.h b/config.h index 0259c24df78b96b7b837544422a15027410d8794..c367a80a6cee31989108e5aa9ae9d187f0a6597f 100755 --- a/config.h +++ b/config.h @@ -163,6 +163,8 @@ #define MODULE_PT100 0 // Enable this module to use one of the following sensors: SENSOR_BMP280 #define MODULE_BMP280 0 +// Enable this module to use one of the following sensors: SENSOR_DIMMER +#define MODULE_DIMMER 0 #endif