diff --git a/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino b/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino index 2c755b3d..e06b7819 100644 --- a/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino +++ b/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino @@ -21,6 +21,15 @@ * REVISION HISTORY * Version 1.0 - Henrik Ekblad * Version 1.1 - GizMoCuz + * Version 1.2 - Paolo Rendano + * * factory reset + * * automatic home assistant entities creation + * * counter correction from home assistant using + * service notify.mysensors + * * fixed counter automatically incremented by 1 + * at each device restart (due to arduino library + * interrupt bug) + * * other tiny improvements * * DESCRIPTION * Use this sensor to measure volume and flow of your house water meter. @@ -36,6 +45,13 @@ // Enable debug prints to serial monitor #define MY_DEBUG +#define APP_DEBUG + +// Enable factory reset to REINIT the board with a different ID +//#define FORCE_FACTORY_RESET + +// uncomment to rejoin to a previous assigned node id +//#define MY_NODE_ID 58 // Enable and select radio type attached #define MY_RADIO_RF24 @@ -43,27 +59,54 @@ //#define MY_RADIO_RFM69 //#define MY_RADIO_RFM95 //#define MY_PJON +#define MY_SPLASH_SCREEN_DISABLED #include -#define DIGITAL_INPUT_SENSOR 3 // The digital input you attached your sensor. (Only 2 and 3 generates interrupt!) +// The digital input you attached your sensor. (Only 2 and 3 generates interrupt!) +#define DIGITAL_INPUT_SENSOR 3 -#define PULSE_FACTOR 1000 // Number of blinks per m3 of your meter (One rotation/liter) +// Arduino Uno/Nano: INTF0 for DIGITAL_INPUT_SENSOR = 2; INTF1 for DIGITAL_INPUT_SENSOR = 3 +// Arduino AtMega2560: INTF0->INTF7 see datasheet based on the input you want to attach +#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +#define DIGITAL_INPUT_SENSOR_INTF INTF1 +#endif -#define SLEEP_MODE false // flowvalue can only be reported when sleep mode is false. +// Number of blinks per m3 of your meter (One rotation/liter) +#define PULSE_FACTOR 1000.0d -#define MAX_FLOW 40 // Max flow (l/min) value to report. This filters outliers. +// flowvalue can only be reported when sleep mode is false. +#define SLEEP_MODE false -#define CHILD_ID 1 // Id of the sensor child +// Max flow (l/min) value to report. This filters outliers. +#define MAX_FLOW 40 -uint32_t SEND_FREQUENCY = - 30000; // Minimum time between send (in milliseconds). We don't want to spam the gateway. +// Timeout (in milliseconds) to reset to 0 the flow +// information (assuming no pulses if no flow) +#define FLOW_RESET_TO_ZERO_TIMEOUT 120000 + +// Id of the sensor child +#define CHILD_ID 1 + +// Id of the sensor child for counter pulse addition +#define CHILD_ID_VAR1 2 + +// Minimum time between send (in milliseconds). We don't want to spam the gateway. +#define SEND_FREQUENCY 30000 + +// Save on board if the home assistant counters have been initialized +// (sufficient condition to see the entity in hass) +#define FIRST_VALUE_SENT_FLAG_POSITION 0 +#define FIRST_VALUE_SENT_FLAG_YES 1 +#define FIRST_VALUE_SENT_FLAG_NO 255 MyMessage flowMsg(CHILD_ID,V_FLOW); MyMessage volumeMsg(CHILD_ID,V_VOLUME); MyMessage lastCounterMsg(CHILD_ID,V_VAR1); +MyMessage volumeAdd(CHILD_ID_VAR1,V_TEXT); -double ppl = ((double)PULSE_FACTOR)/1000; // Pulses per liter +// Pulses per liter +double ppl = ((double)PULSE_FACTOR)/1000; volatile uint32_t pulseCount = 0; volatile uint32_t lastBlink = 0; @@ -74,6 +117,7 @@ double oldflow = 0; double oldvolume =0; uint32_t lastSend =0; uint32_t lastPulse =0; +bool firstValuesMessageSent = false; void IRQ_HANDLER_ATTR onPulse() { @@ -84,7 +128,8 @@ void IRQ_HANDLER_ATTR onPulse() if (interval!=0) { lastPulse = millis(); if (interval<500000L) { - // Sometimes we get interrupt on RISING, 500000 = 0.5 second debounce ( max 120 l/min) + // Sometimes we get interrupt on RISING, + // 500000 = 0.5 second debounce ( max 120 l/min) return; } flow = (60000000.0 /interval) / ppl; @@ -96,26 +141,51 @@ void IRQ_HANDLER_ATTR onPulse() void setup() { - // initialize our digital pins internal pullup resistor so one pulse switches from high to low (less distortion) + #ifdef FORCE_FACTORY_RESET + // got from mysensors clear e2p sketch + for (uint16_t i=0; i 120000) { + // No Pulse count received for a defined time + if(currentTime - lastPulse > FLOW_RESET_TO_ZERO_TIMEOUT) { flow = 0; } // Pulse count has changed if ((pulseCount != oldPulseCount)||(!SLEEP_MODE)) { oldPulseCount = pulseCount; - +#ifdef APP_DEBUG Serial.print("pulsecount:"); Serial.println(pulseCount); +#endif + // Send pulsecount value to gw in VAR1 + send(lastCounterMsg.set(pulseCount)); - send(lastCounterMsg.set(pulseCount)); // Send pulsecount value to gw in VAR1 - - double volume = ((double)pulseCount/((double)PULSE_FACTOR)); + double volume = pulseCount / PULSE_FACTOR; if ((volume != oldvolume)||(!SLEEP_MODE)) { oldvolume = volume; +#ifdef APP_DEBUG Serial.print("volume:"); Serial.println(volume, 3); - - send(volumeMsg.set(volume, 3)); // Send volume value to gw +#endif + // Send volume value to gw + send(volumeMsg.set(volume, 3)); } } } @@ -175,15 +250,74 @@ void loop() } } +// clearing eeprom with mysensors sketch is not enough since this +// doesn't cover the saved state values. Call this function once +// to force factory reset +void forceFactoryReset() { + saveState(FIRST_VALUE_SENT_FLAG_POSITION, FIRST_VALUE_SENT_FLAG_NO); +} + +void checkAndFirstTimeInitValuesOnHomeAssistant() { + // check local e2p if this sensor has already sent + // initial value (0). If not will send the init value + uint8_t state = loadState(FIRST_VALUE_SENT_FLAG_POSITION); + if (state==FIRST_VALUE_SENT_FLAG_NO) { + // never sent anything. No value in HASS is assumed +#ifdef APP_DEBUG + Serial.println("First time init"); +#endif + firstValuesMessageSent = true; + // Send flow value to gw + send(flowMsg.set(0.0d, 2)); + // Send volume value to gw + send(volumeMsg.set(0.0d, 3)); + // Send pulsecount value to gw in VAR1 + send(lastCounterMsg.set((uint32_t)0)); + // Send volumeAdd value to gw in V_TEXT + send(volumeAdd.set("")); + } +} + void receive(const MyMessage &message) { if (message.getType()==V_VAR1) { + if (firstValuesMessageSent) { + // ack saving value on board that HomeAssistant + // got first init values. Will never be sent again + saveState(FIRST_VALUE_SENT_FLAG_POSITION, + FIRST_VALUE_SENT_FLAG_YES); + } + uint32_t gwPulseCount=message.getULong(); pulseCount += gwPulseCount; - flow=oldflow=0; + flow=oldflow=0.0d; + +#ifdef APP_DEBUG Serial.print("Received last pulse count from gw:"); Serial.println(pulseCount); +#endif + pcReceived = true; } -} + // incoming message to correct pulsecount + // used to add or remove pulses to the current reading + if (message.getType()==V_TEXT) { + long val = atol(message.getString()); + if ((val+(int32_t)pulseCount)<0) { + // TODO: this is not covering all the ranges problems +#ifdef APP_DEBUG + Serial.println("out of range. Won't add"); +#endif + } + else { + pulseCount+=val; + // reset only if ok + send(volumeAdd.set("")); +#ifdef APP_DEBUG + Serial.print("New pulseCount: "); + Serial.println(pulseCount); +#endif + } + } +} \ No newline at end of file