Commit 83814b81 authored by user2684's avatar user2684 Committed by GitHub
Browse files

Added support for Power/Water pulse sensors (#96)

parent 303806a2
......@@ -276,6 +276,9 @@ int Sensor::getValueType() {
void Sensor::setFloatPrecision(int value) {
_float_precision = value;
}
void Sensor::setDoublePrecision(int value) {
_double_precision = value;
}
#if POWER_MANAGER == 1
void Sensor::setPowerPins(int ground_pin, int vcc_pin, int wait_time) {
_powerManager.setPowerPins(ground_pin, vcc_pin, wait_time);
......@@ -378,7 +381,7 @@ void Sensor::loop(const MyMessage & message) {
if (_auto_power_pins) powerOn();
#endif
// for numeric sensor requiring multiple samples, keep track of the total
float total = 0;
double total = 0;
// collect multiple samples if needed
for (int i = 0; i < _samples; i++) {
// call the sensor-specific implementation of the main task which will store the result in the _value variable
......@@ -390,9 +393,10 @@ void Sensor::loop(const MyMessage & message) {
// we'be been called from loop()
onLoop();
}
// for integers and floats, keep track of the total
// for integers, floats and doubles, keep track of the total
if (_value_type == TYPE_INTEGER) total += (float)_value_int;
else if (_value_type == TYPE_FLOAT) total += _value_float;
else if (_value_type == TYPE_DOUBLE) total += _value_double;
// wait between samples
if (_samples_interval > 0) _node_manager->sleepOrWait(_samples_interval);
}
......@@ -418,6 +422,17 @@ void Sensor::loop(const MyMessage & message) {
_value_float = -1;
}
}
// process a double value
else if (_value_type == TYPE_DOUBLE && total > -1) {
// calculate the average value of the samples
double avg = total / _samples;
// report the value back
if (_isReceive(message) || _isWorthSending(avg != _last_value_double)) {
_last_value_double = avg;
_send(_msg.set(avg, _double_precision));
_value_double = -1;
}
}
// process a string value
else if (_value_type == TYPE_STRING) {
// if track last value is disabled or if enabled and the current value is different then the old value, send it back
......@@ -485,6 +500,7 @@ void Sensor::process(Request & request) {
case 19: setReportIntervalHours(request.getValueInt()); break;
case 20: setReportIntervalDays(request.getValueInt()); break;
case 18: setForceUpdateHours(request.getValueInt()); break;
case 21: setDoublePrecision(request.getValueInt()); break;
default: return;
}
_send(_msg_service.set(function));
......@@ -870,79 +886,6 @@ void SensorACS712::onProcess(Request & request) {
void SensorACS712::onInterrupt() {
}
/*
SensorRainGauge
*/
// contructor
SensorRainGauge::SensorRainGauge(NodeManager* node_manager, int child_id, int pin): Sensor(node_manager,child_id, pin) {
// set presentation, type and value type
setPresentation(S_RAIN);
setType(V_RAIN);
setValueType(TYPE_FLOAT);
}
// setter/getter
void SensorRainGauge::setSingleTip(float value) {
_single_tip = value;
}
void SensorRainGauge::setInitialValue(int value) {
_initial_value = value;
}
// what to do during before
void SensorRainGauge::onBefore() {
// configure the interrupt pin so onInterrupt() will be called on tip
setInterrupt(_pin,FALLING,_initial_value);
}
// what to do during setup
void SensorRainGauge::onSetup() {
}
// what to do during loop
void SensorRainGauge::onLoop() {
// do not execute loop if called by an interrupt
if (_node_manager->getLastInterruptPin() == _interrupt_pin) return;
// time to report the rain so far
_value_float = _count * _single_tip;
#if DEBUG == 1
Serial.print(F("RAIN I="));
Serial.print(_child_id);
Serial.print(F(" T="));
Serial.println(_value_float);
#endif
// reset the counter
_count = 0;
}
// what to do as the main task when receiving a message
void SensorRainGauge::onReceive(const MyMessage & message) {
if (message.getCommand() == C_REQ) {
// report the total amount of rain for the last period
_value_float = _count * _single_tip;
}
}
// what to do when receiving a remote message
void SensorRainGauge::onProcess(Request & request) {
int function = request.getFunction();
switch(function) {
case 102: setSingleTip(request.getValueFloat()); break;
default: return;
}
_send(_msg_service.set(function));
}
// what to do when receiving an interrupt
void SensorRainGauge::onInterrupt() {
// increase the counter
_count++;
#if DEBUG == 1
Serial.println(F("RAIN+"));
#endif
}
/*
SensorRain
*/
......@@ -2938,7 +2881,119 @@ float SensorDimmer::_getEasing(float t, float b, float c, float d) {
else if (_easing == EASE_INOUTSINE) return -c/2 * (cos(M_PI*t/d) - 1) + b;
else return c*t/d + b;
}
#endif
/*
SensorPulseMeter
*/
#if MODULE_PULSE_METER == 1
// contructor
SensorPulseMeter::SensorPulseMeter(NodeManager* node_manager, int child_id, int pin): Sensor(node_manager,child_id, pin) {
// set presentation, type and value type
setValueType(TYPE_FLOAT);
}
// setter/getter
void SensorPulseMeter::setPulseFactor(float value) {
_pulse_factor = value;
}
void SensorPulseMeter::setInitialValue(int value) {
_initial_value = value;
}
void SensorPulseMeter::setInterruptMode(int value) {
_interrupt_mode = value;
}
// what to do during before
void SensorPulseMeter::onBefore() {
// configure the interrupt pin so onInterrupt() will be called on tip
setInterrupt(_pin,_interrupt_mode,_initial_value);
}
// what to do during setup
void SensorPulseMeter::onSetup() {
}
// what to do during loop
void SensorPulseMeter::onLoop() {
// do not report anything if called by an interrupt
if (_node_manager->getLastInterruptPin() == _interrupt_pin) return;
// time to report the rain so far
_reportTotal();
#if DEBUG == 1
Serial.print(F("PLS I="));
Serial.print(_child_id);
Serial.print(F(" T="));
Serial.println(_value_float);
#endif
// reset the counter
_count = 0;
}
// what to do as the main task when receiving a message
void SensorPulseMeter::onReceive(const MyMessage & message) {
if (message.getCommand() == C_REQ) {
// report the total the last period
_reportTotal();
}
}
// what to do when receiving a remote message
void SensorPulseMeter::onProcess(Request & request) {
int function = request.getFunction();
switch(function) {
case 102: setPulseFactor(request.getValueFloat()); break;
default: return;
}
_send(_msg_service.set(function));
}
// what to do when receiving an interrupt
void SensorPulseMeter::onInterrupt() {
// increase the counter
_count++;
#if DEBUG == 1
Serial.println(F("PLS+"));
#endif
}
// return the total based on the pulses counted
void SensorPulseMeter::_reportTotal() {
if (_value_type == TYPE_DOUBLE) _value_double = _count / _pulse_factor;
else _value_float = _count / _pulse_factor;
}
/*
SensorRainGauge
*/
// contructor
SensorRainGauge::SensorRainGauge(NodeManager* node_manager, int child_id, int pin): SensorPulseMeter(node_manager,child_id, pin) {
setPresentation(S_RAIN);
setType(V_RAIN);
setPulseFactor(9.09);
}
/*
SensorPowerMeter
*/
// contructor
SensorPowerMeter::SensorPowerMeter(NodeManager* node_manager, int child_id, int pin): SensorPulseMeter(node_manager,child_id, pin) {
setPresentation(S_POWER);
setType(V_KWH);
setValueType(TYPE_DOUBLE);
setPulseFactor(1000);
}
/*
SensorWaterMeter
*/
// contructor
SensorWaterMeter::SensorWaterMeter(NodeManager* node_manager, int child_id, int pin): SensorPulseMeter(node_manager,child_id, pin) {
setPresentation(S_WATER);
setType(V_VOLUME);
setValueType(TYPE_DOUBLE);
setPulseFactor(1000);
}
#endif
/*******************************************
......@@ -3092,7 +3147,6 @@ int NodeManager::registerSensor(int sensor_type, int pin, int child_id) {
else if (sensor_type == SENSOR_THERMISTOR) return registerSensor(new SensorThermistor(this,child_id, pin));
else if (sensor_type == SENSOR_ML8511) return registerSensor(new SensorML8511(this,child_id, pin));
else if (sensor_type == SENSOR_ACS712) return registerSensor(new SensorACS712(this,child_id, pin));
else if (sensor_type == SENSOR_RAIN_GAUGE) return registerSensor(new SensorRainGauge(this,child_id, pin));
else if (sensor_type == SENSOR_RAIN) return registerSensor(new SensorRain(this,child_id, pin));
else if (sensor_type == SENSOR_SOIL_MOISTURE) return registerSensor(new SensorSoilMoisture(this,child_id, pin));
#endif
......@@ -3160,9 +3214,7 @@ int NodeManager::registerSensor(int sensor_type, int pin, int child_id) {
}
#endif
#if MODULE_BH1750 == 1
else if (sensor_type == SENSOR_BH1750) {
return registerSensor(new SensorBH1750(this,child_id));
}
else if (sensor_type == SENSOR_BH1750) return registerSensor(new SensorBH1750(this,child_id));
#endif
#if MODULE_MLX90614 == 1
else if (sensor_type == SENSOR_MLX90614) {
......@@ -3217,9 +3269,7 @@ int NodeManager::registerSensor(int sensor_type, int pin, int child_id) {
}
#endif
#if MODULE_SONOFF == 1
else if (sensor_type == SENSOR_SONOFF) {
return registerSensor(new SensorSonoff(this,child_id));
}
else if (sensor_type == SENSOR_SONOFF) return registerSensor(new SensorSonoff(this,child_id));
#endif
#if MODULE_BMP085 == 1
else if (sensor_type == SENSOR_BMP085) {
......@@ -3241,9 +3291,7 @@ int NodeManager::registerSensor(int sensor_type, int pin, int child_id) {
}
#endif
#if MODULE_HCSR04 == 1
else if (sensor_type == SENSOR_HCSR04) {
return registerSensor(new SensorHCSR04(this,child_id, pin));
}
else if (sensor_type == SENSOR_HCSR04) return registerSensor(new SensorHCSR04(this,child_id, pin));
#endif
#if MODULE_MCP9808 == 1
else if (sensor_type == SENSOR_MCP9808) {
......@@ -3259,14 +3307,10 @@ int NodeManager::registerSensor(int sensor_type, int pin, int child_id) {
}
#endif
#if MODULE_MQ == 1
else if (sensor_type == SENSOR_MQ) {
return registerSensor(new SensorMQ(this,child_id, pin));
}
else if (sensor_type == SENSOR_MQ) return registerSensor(new SensorMQ(this,child_id, pin));
#endif
#if MODULE_MHZ19 == 1
else if (sensor_type == SENSOR_MHZ19) {
return registerSensor(new SensorMHZ19(this, child_id, pin));
}
else if (sensor_type == SENSOR_MHZ19) return registerSensor(new SensorMHZ19(this, child_id, pin));
#endif
#if MODULE_AM2320 == 1
else if (sensor_type == SENSOR_AM2320) {
......@@ -3279,22 +3323,18 @@ int NodeManager::registerSensor(int sensor_type, int pin, int child_id) {
}
#endif
#if MODULE_TSL2561 == 1
else if (sensor_type == SENSOR_TSL2561) {
// register light sensor
return registerSensor(new SensorTSL2561(this,child_id));
}
else if (sensor_type == SENSOR_TSL2561) return registerSensor(new SensorTSL2561(this,child_id));
#endif
#if MODULE_PT100 == 1
else if (sensor_type == SENSOR_PT100) {
// register temperature sensor
return registerSensor(new SensorPT100(this,child_id,pin));
}
#if MODULE_PT100 == 1
else if (sensor_type == SENSOR_PT100) 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));
}
#if MODULE_DIMMER == 1
else if (sensor_type == SENSOR_DIMMER) return registerSensor(new SensorDimmer(this,child_id,pin));
#endif
#if MODULE_PULSE_METER == 1
else if (sensor_type == SENSOR_RAIN_GAUGE) return registerSensor(new SensorRainGauge(this,child_id,pin));
else if (sensor_type == SENSOR_POWER_METER) return registerSensor(new SensorPowerMeter(this,child_id,pin));
else if (sensor_type == SENSOR_WATER_METER) return registerSensor(new SensorWaterMeter(this,child_id,pin));
#endif
else {
#if DEBUG == 1
......
......@@ -31,6 +31,7 @@
#define TYPE_INTEGER 0
#define TYPE_FLOAT 1
#define TYPE_STRING 2
#define TYPE_DOUBLE 2
// define interrupt pins
#define INTERRUPT_PIN_1 3
......@@ -118,7 +119,7 @@
Default module settings
*/
// Enable this module to use one of the following sensors: SENSOR_ANALOG_INPUT, SENSOR_LDR, SENSOR_THERMISTOR, SENSOR_ML8511, SENSOR_ACS712, SENSOR_RAIN_GAUGE, SENSOR_RAIN, SENSOR_SOIL_MOISTURE
// Enable this module to use one of the following sensors: SENSOR_ANALOG_INPUT, SENSOR_LDR, SENSOR_THERMISTOR, SENSOR_ML8511, SENSOR_ACS712, SENSOR_RAIN, SENSOR_SOIL_MOISTURE
#ifndef MODULE_ANALOG_INPUT
#define MODULE_ANALOG_INPUT 0
#endif
......@@ -202,6 +203,10 @@
#ifndef MODULE_DIMMER
#define MODULE_DIMMER 0
#endif
// Enable this module to use one of the following sensors: SENSOR_RAIN_GAUGE, SENSOR_POWER_METER, SENSOR_WATER_METER
#ifndef MODULE_PULSE_METER
#define MODULE_PULSE_METER 0
#endif
/***********************************
Supported Sensors
......@@ -218,8 +223,6 @@ enum supported_sensors {
SENSOR_ML8511,
// Current sensor
SENSOR_ACS712,
// rain gauge sensor
SENSOR_RAIN_GAUGE,
// Rain sensor, return the percentage of rain from an attached analog sensor
SENSOR_RAIN,
// Soil moisture sensor, return the percentage of moisture from an attached analog sensor
......@@ -315,6 +318,14 @@ enum supported_sensors {
// Generic dimmer sensor used to drive a pwm output
SENSOR_DIMMER,
#endif
#if MODULE_PULSE_METER == 1
// rain gauge sensor
SENSOR_RAIN_GAUGE,
// power meter pulse sensor
SENSOR_POWER_METER,
// water meter pulse sensor
SENSOR_WATER_METER,
#endif
};
/***********************************
......@@ -519,6 +530,8 @@ class Sensor {
int getValueType();
// [11] for float values, set the float precision (default: 2)
void setFloatPrecision(int value);
// [21] for double values, set the double precision (default: 4)
void setDoublePrecision(int value);
#if POWER_MANAGER == 1
// to save battery the sensor can be optionally connected to two pins which will act as vcc and ground and activated on demand
void setPowerPins(int ground_pin, int vcc_pin, int wait_time = 50);
......@@ -577,8 +590,11 @@ class Sensor {
bool _track_last_value = false;
int _value_type = TYPE_INTEGER;
int _float_precision = 2;
int _double_precision = 4;
int _value_int = -1;
float _value_float = -1;
double _value_double = -1;
double _last_value_double = -1;
char * _value_string = "";
int _last_value_int = -1;
float _last_value_float = -1;
......@@ -709,30 +725,6 @@ class SensorACS712: public Sensor {
int _mv_per_amp = 185;
};
/*
SensorRainGauge
*/
class SensorRainGauge: public Sensor {
public:
SensorRainGauge(NodeManager* node_manager, int child_id, int pin);
// [102] set how many mm of rain to count for each tip (default: 0.11)
void setSingleTip(float value);
// set initial value - internal pull up (default: HIGH)
void setInitialValue(int value);
// 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:
long _count = 0;
float _single_tip = 0.11;
int _initial_value = HIGH;
};
/*
SensorRain
*/
......@@ -1388,6 +1380,59 @@ class SensorDimmer: public Sensor {
};
#endif
/*
SensorPulseMeter
*/
#if MODULE_PULSE_METER == 1
class SensorPulseMeter: public Sensor {
public:
SensorPulseMeter(NodeManager* node_manager, int child_id, int pin);
// [102] set how many pulses for each unit (e.g. 1000 pulses for 1 kwh of power, 9 pulses for 1 mm of rain, etc.)
void setPulseFactor(float value);
// set initial value - internal pull up (default: HIGH)
void setInitialValue(int value);
// set the interrupt mode to attach to (default: FALLING)
void setInterruptMode(int value);
// 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:
long _count = 20;
float _pulse_factor;
int _initial_value = HIGH;
int _interrupt_mode = FALLING;
void _reportTotal();
};
/*
SensorRainGauge
*/
class SensorRainGauge: public SensorPulseMeter {
public:
SensorRainGauge(NodeManager* node_manager, int child_id, int pin);
};
/*
SensorPowerMeter
*/
class SensorPowerMeter: public SensorPulseMeter {
public:
SensorPowerMeter(NodeManager* node_manager, int child_id, int pin);
};
/*
SensorWaterMeter
*/
class SensorWaterMeter: public SensorPulseMeter {
public:
SensorWaterMeter(NodeManager* node_manager, int child_id, int pin);
};
#endif
/***************************************
NodeManager: manages all the aspects of the node
*/
......
......@@ -172,7 +172,7 @@ The next step is to enable NodeManager's additional functionalities and the modu
// if enabled, send a SLEEPING and AWAKE service messages just before entering and just after leaving a sleep cycle and STARTED when starting/rebooting
#define SERVICE_MESSAGES 0
// Enable this module to use one of the following sensors: SENSOR_ANALOG_INPUT, SENSOR_LDR, SENSOR_THERMISTOR, SENSOR_ML8511, SENSOR_ACS712, SENSOR_RAIN_GAUGE, SENSOR_RAIN, SENSOR_SOIL_MOISTURE
// Enable this module to use one of the following sensors: SENSOR_ANALOG_INPUT, SENSOR_LDR, SENSOR_THERMISTOR, SENSOR_ML8511, SENSOR_ACS712, SENSOR_RAIN, SENSOR_SOIL_MOISTURE
#define MODULE_ANALOG_INPUT 1
// Enable this module to use one of the following sensors: SENSOR_DIGITAL_INPUT
#define MODULE_DIGITAL_INPUT 1
......@@ -214,6 +214,8 @@ The next step is to enable NodeManager's additional functionalities and the modu
#define MODULE_BMP280 0
// Enable this module to use one of the following sensors: SENSOR_DIMMER
#define MODULE_DIMMER 0
// Enable this module to use one of the following sensors: SENSOR_RAIN_GAUGE, SENSOR_POWER_METER, SENSOR_WATER_METER
#define MODULE_PULSE_METER 0
~~~
### Installing the dependencies
......@@ -441,6 +443,8 @@ SENSOR_AM2320 | AM2320 sensors, return temperature/humidity based on the attache
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
SENSOR_POWER_METER | Power meter pulse sensor
SENSOR_WATER_METER | Water meter pulse sensor
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
......@@ -519,6 +523,8 @@ The following methods are available for all the sensors and can be called on the
int getValueType();
// [11] for float values, set the float precision (default: 2)
void setFloatPrecision(int value);
// [21] for double values, set the double precision (default: 4)
void setDoublePrecision(int value);
#if POWER_MANAGER == 1
// to save battery the sensor can be optionally connected to two pins which will act as vcc and ground and activated on demand
void setPowerPins(int ground_pin, int vcc_pin, int wait_time = 50);
......@@ -617,12 +623,14 @@ Each sensor class can expose additional methods.
void setOffset(int value);
~~~
* SensorRainGauge
* SensorRainGauge / SensorPowerMeter / SensorWaterMeter
~~~c
// [102] set how many mm of rain to count for each tip (default: 0.11)
void setSingleTip(float value);
// [102] set how many pulses for each unit (e.g. 1000 pulses for 1 kwh of power, 9 pulses for 1 mm of rain, etc.)
void setPulseFactor(float value);
// set initial value - internal pull up (default: HIGH)
void setInitialValue(int value);
// set the interrupt mode to attach to (default: FALLING)
void setInterruptMode(int value);
~~~
* SensorDigitalOutput / SensorRelay
......@@ -1396,6 +1404,7 @@ v1.6:
* Added support for MH-Z19 CO2 sensor
* Added buil-in rain and soil moisture analog sensors
* Added support for generic dimmer sensor (PWM output)
* Added support for power and water meter pulse sensors
* Radio signal level is reported automatically and on demand through child 202
* SensorRainGauge now supports sleep mode
* SensorSwitch now supports awake mode
......
......@@ -125,7 +125,7 @@
// if enabled, send a SLEEPING and AWAKE service messages just before entering and just after leaving a sleep cycle and STARTED when starting/rebooting
#define SERVICE_MESSAGES 0
// Enable this module to use one of the following sensors: SENSOR_ANALOG_INPUT, SENSOR_LDR, SENSOR_THERMISTOR, SENSOR_ML8511, SENSOR_ACS712, SENSOR_RAIN_GAUGE, SENSOR_RAIN, SENSOR_SOIL_MOISTURE
// Enable this module to use one of the following sensors: SENSOR_ANALOG_INPUT, SENSOR_LDR, SENSOR_THERMISTOR, SENSOR_ML8511, SENSOR_ACS712, SENSOR_RAIN, SENSOR_SOIL_MOISTURE
#define MODULE_ANALOG_INPUT 1
// Enable this module to use one of the following sensors: SENSOR_DIGITAL_INPUT
#define MODULE_DIGITAL_INPUT 1
......@@ -167,6 +167,8 @@
#define MODULE_BMP280 0
// Enable this module to use one of the following sensors: SENSOR_DIMMER
#define MODULE_DIMMER 0
// Enable this module to use one of the following sensors: SENSOR_RAIN_GAUGE, SENSOR_POWER_METER, SENSOR_WATER_METER
#define MODULE_PULSE_METER 0
#endif
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment