ISR Pulse Meter Question



  • In the example code, I am trying to understand the sleep behaviour. In testing, if I set sleep time to 10 mins it works fine and counts pulses. Then every 10 minutes it sends the data to Domoticz.

    My question is that I understood an ISR would return to the main loop when done, in this case counting one pulse. If this is the case however, it would then send the data to gateway since the pulse count is different.

    Instead it seems to be just counting the pulses and returning back to sleep until the sleep timer runs out. Then if the pulse counts are different, sends the count to gw and repeats. Hence the 10 minute updates.

    I clearly don't understand sometging here, can anyone please explain? Many thanks.

    /*
     * The MySensors Arduino library handles the wireless radio link and protocol
     * between your home built sensors/actuators and HA controller of choice.
     * The sensors forms a self healing radio network with optional repeaters. Each
     * repeater and gateway builds a routing tables in EEPROM which keeps track of the
     * network topology allowing messages to be routed to nodes.
     *
     * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
     * Copyright (C) 2013-2018 Sensnology AB
     * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors
     *
     * Documentation: http://www.mysensors.org
     * Support Forum: http://forum.mysensors.org
     *
     * This program is free software; you can redistribute it and/or
     * modify it under the terms of the GNU General Public License
     * version 2 as published by the Free Software Foundation.
     *
     *******************************
     *
     * REVISION HISTORY
     * Version 1.0 - Henrik Ekblad
     * Version 1.1 - GizMoCuz
     *
     * DESCRIPTION
     * Use this sensor to measure volume and flow of your house water meter.
     * You need to set the correct pulsefactor of your meter (pulses per m3).
     * The sensor starts by fetching current volume reading from gateway (VAR 1).
     * Reports both volume and flow back to gateway.
     *
     * Unfortunately millis() won't increment when the Arduino is in
     * sleepmode. So we cannot make this sensor sleep if we also want
     * to calculate/report flow.
     * http://www.mysensors.org/build/pulse_water
     */
    
    // Enable debug prints to serial monitor
    #define MY_DEBUG
    
    // Enable and select radio type attached
    #define MY_RADIO_RF24
    //#define MY_RADIO_NRF5_ESB
    //#define MY_RADIO_RFM69
    //#define MY_RADIO_RFM95
    
    #include <MySensors.h>
    
    #define DIGITAL_INPUT_SENSOR 3                  // The digital input you attached your sensor.  (Only 2 and 3 generates interrupt!)
    
    #define PULSE_FACTOR 1000                       // Number of blinks per m3 of your meter (One rotation/liter)
    
    #define SLEEP_MODE false                        // flowvalue can only be reported when sleep mode is false.
    
    #define MAX_FLOW 40                             // Max flow (l/min) value to report. This filters outliers.
    
    #define CHILD_ID 1                              // Id of the sensor child
    
    uint32_t SEND_FREQUENCY =
        30000;           // Minimum time between send (in milliseconds). We don't want to spam the gateway.
    
    MyMessage flowMsg(CHILD_ID,V_FLOW);
    MyMessage volumeMsg(CHILD_ID,V_VOLUME);
    MyMessage lastCounterMsg(CHILD_ID,V_VAR1);
    
    double ppl = ((double)PULSE_FACTOR)/1000;        // Pulses per liter
    
    volatile uint32_t pulseCount = 0;
    volatile uint32_t lastBlink = 0;
    volatile double flow = 0;
    bool pcReceived = false;
    uint32_t oldPulseCount = 0;
    uint32_t newBlink = 0;
    double oldflow = 0;
    double volume =0;
    double oldvolume =0;
    uint32_t lastSend =0;
    uint32_t lastPulse =0;
    
    void setup()
    {
    	// initialize our digital pins internal pullup resistor so one pulse switches from high to low (less distortion)
    	pinMode(DIGITAL_INPUT_SENSOR, INPUT_PULLUP);
    
    	pulseCount = oldPulseCount = 0;
    
    	// Fetch last known pulse count value from gw
    	request(CHILD_ID, V_VAR1);
    
    	lastSend = lastPulse = millis();
    
    	attachInterrupt(digitalPinToInterrupt(DIGITAL_INPUT_SENSOR), onPulse, FALLING);
    }
    
    void presentation()
    {
    	// Send the sketch version information to the gateway and Controller
    	sendSketchInfo("Water Meter", "1.1");
    
    	// Register this device as Water flow sensor
    	present(CHILD_ID, S_WATER);
    }
    
    void loop()
    {
    	uint32_t currentTime = millis();
    
    	// Only send values at a maximum frequency or woken up from sleep
    	if (SLEEP_MODE || (currentTime - lastSend > SEND_FREQUENCY)) {
    		lastSend=currentTime;
    
    		if (!pcReceived) {
    			//Last Pulsecount not yet received from controller, request it again
    			request(CHILD_ID, V_VAR1);
    			return;
    		}
    
    		if (!SLEEP_MODE && flow != oldflow) {
    			oldflow = flow;
    
    			Serial.print("l/min:");
    			Serial.println(flow);
    
    			// Check that we don't get unreasonable large flow value.
    			// could happen when long wraps or false interrupt triggered
    			if (flow<((uint32_t)MAX_FLOW)) {
    				send(flowMsg.set(flow, 2));                   // Send flow value to gw
    			}
    		}
    
    		// No Pulse count received in 2min
    		if(currentTime - lastPulse > 120000) {
    			flow = 0;
    		}
    
    		// Pulse count has changed
    		if ((pulseCount != oldPulseCount)||(!SLEEP_MODE)) {
    			oldPulseCount = pulseCount;
    
    			Serial.print("pulsecount:");
    			Serial.println(pulseCount);
    
    			send(lastCounterMsg.set(pulseCount));                  // Send  pulsecount value to gw in VAR1
    
    			double volume = ((double)pulseCount/((double)PULSE_FACTOR));
    			if ((volume != oldvolume)||(!SLEEP_MODE)) {
    				oldvolume = volume;
    
    				Serial.print("volume:");
    				Serial.println(volume, 3);
    
    				send(volumeMsg.set(volume, 3));               // Send volume value to gw
    			}
    		}
    	}
    	if (SLEEP_MODE) {
    		sleep(SEND_FREQUENCY);
    	}
    }
    
    void receive(const MyMessage &message)
    {
    	if (message.type==V_VAR1) {
    		uint32_t gwPulseCount=message.getULong();
    		pulseCount += gwPulseCount;
    		flow=oldflow=0;
    		Serial.print("Received last pulse count from gw:");
    		Serial.println(pulseCount);
    		pcReceived = true;
    	}
    }
    
    void onPulse()
    {
    	if (!SLEEP_MODE) {
    		uint32_t newBlink = micros();
    		uint32_t interval = newBlink-lastBlink;
    
    		if (interval!=0) {
    			lastPulse = millis();
    			if (interval<500000L) {
    				// Sometimes we get interrupt on RISING,  500000 = 0.5 second debounce ( max 120 l/min)
    				return;
    			}
    			flow = (60000000.0 /interval) / ppl;
    		}
    		lastBlink = newBlink;
    	}
    	pulseCount++;
    }
    ``

  • Mod

    @killerfreek welcome to the forum 🙂
    attachinterrupt connects the ISR with the interrupt. Sleep is called without interrupt, so sleep will not return until the set amount of time.

    It is possible to call sleep so it wakes up for every pulse. See https://www.mysensors.org/download/sensor_api_20#sleeping for documentation.



  • @mfalkvidd Many thanks!



  • Hello

    I'm asking exactly the same question.
    I mixed this sketch with another one for battery measurement (and added fonction to resend last volume for updating domoticz, software debounce, but that's not the main point).

    Each time I have a pulse, the loop start again, even if it was sleeping.

    I have also tried this simple code

    
    // Enable debug prints to serial monitor
    #define MY_DEBUG
    
    // Enable and select radio type attached
    #define MY_RADIO_RF24
    
    #include <MySensors.h>
    
    #define DIGITAL_INPUT_SENSOR 3                  // The digital input you attached your sensor.  (Only 2 and 3 generates interrupt!)
    
    #define CHILD_ID 1                              // Id of the sensor child
    
    unsigned long SEND_FREQUENCY =  60000;           // Minimum time between send (in milliseconds). We don't want to spam the gateway.
    
    volatile uint32_t pulseCount = 0;
    uint32_t oldPulseCount = 0;
    
    
    
    void setup()
    {
      // initialize our digital pins internal pullup resistor so one pulse switches from high to low (less distortion)
      pinMode(DIGITAL_INPUT_SENSOR, INPUT_PULLUP);
      pulseCount = oldPulseCount = 0;
      attachInterrupt(digitalPinToInterrupt(DIGITAL_INPUT_SENSOR), onPulse, FALLING);
    }
    
    void presentation()
    {
      // Send the sketch version information to the gateway and Controller
      sendSketchInfo("TEST", "1.1");
      // Register this device as Water flow sensor
      present(CHILD_ID, S_GAS);
    }
    
    void loop()
    {
    
      // Pulse count has changed
      if ((pulseCount != oldPulseCount)) {
        oldPulseCount = pulseCount;
    
        Serial.print("pulsecount:");
        Serial.println(pulseCount);
      } else {
        Serial.println("pulsecount not changed");
    
      }
    
      sleep(SEND_FREQUENCY);
    
    }
    
    void onPulse()
    {
      pulseCount++;
    }
    
    

    And here is the log

    18:33:44.593 -> 3229 MCO:BGN:INIT OK,TSP=1
    18:33:44.593 -> pulsecount not changed
    18:33:44.593 -> 3233 MCO:SLP:MS=60000,SMS=0,I1=255,M1=255,I2=255,M2=255
    18:33:44.593 -> 3239 TSF:TDI:TSL
    18:34:48.589 -> 3241 MCO:SLP:WUP=-1
    18:34:48.589 -> 3244 TSF:TRI:TSB
    18:34:48.635 -> pulsecount not changed
    18:34:48.635 -> 3250 MCO:SLP:MS=60000,SMS=0,I1=255,M1=255,I2=255,M2=255
    18:34:48.635 -> 3258 TSF:TDI:TSL
    18:34:57.719 -> 3260 MCO:SLP:WUP=-1
    18:34:57.719 -> 3262 TSF:TRI:TSB
    18:34:57.763 -> pulsecount:159
    18:34:57.763 -> 3270 MCO:SLP:MS=60000,SMS=0,I1=255,M1=255,I2=255,M2=255
    18:34:57.763 -> 3276 TSF:TDI:TSL
    18:34:58.212 -> 3280 MCO:SLP:WUP=-1
    18:34:58.212 -> 3282 TSF:TRI:TSB
    18:34:58.212 -> pulsecount:364
    18:34:58.212 -> 3289 MCO:SLP:MS=60000,SMS=0,I1=255,M1=255,I2=255,M2=255
    18:34:58.212 -> 3295 TSF:TDI:TSL
    18:35:04.813 -> 3299 MCO:SLP:WUP=-1
    18:35:04.813 -> 3301 TSF:TRI:TSB
    18:35:04.813 -> pulsecount:380
    18:35:04.813 -> 3307 MCO:SLP:MS=60000,SMS=0,I1=255,M1=255,I2=255,M2=255
    18:35:04.861 -> 3313 TSF:TDI:TSL
    18:35:05.211 -> 3315 MCO:SLP:WUP=-1
    18:35:05.211 -> 3319 TSF:TRI:TSB
    18:35:05.211 -> pulsecount:394
    18:35:05.211 -> 3325 MCO:SLP:MS=60000,SMS=0,I1=255,M1=255,I2=255,M2=255
    18:35:05.211 -> 3332 TSF:TDI:TSL
    18:35:10.827 -> 3334 MCO:SLP:WUP=-1
    18:35:10.827 -> 3336 TSF:TRI:TSB
    18:35:10.827 -> pulsecount:402
    18:35:10.827 -> 3344 MCO:SLP:MS=60000,SMS=0,I1=255,M1=255,I2=255,M2=255
    18:35:10.827 -> 3350 TSF:TDI:TSL
    18:36:14.864 -> 3352 MCO:SLP:WUP=-1
    18:36:14.864 -> 3354 TSF:TRI:TSB
    18:36:14.864 -> pulsecount not changed
    18:36:14.864 -> 3360 MCO:SLP:MS=60000,SMS=0,I1=255,M1=255,I2=255,M2=255
    18:36:14.864 -> 3368 TSF:TDI:TSL
    

    As you can see with timestamp, you don't get value every minute, but every minute AND each time ISR is run. The main loop continue don't wait the end of the time to continue. What do I miss ?

    Thank you for your help


  • Mod

    @barrydou my guess is that the interrupt causes the sleep function to believe that 8 seconds has passed (which is the maximum time for the watchdog), so it deducts 8 seconds for each pulse.



  • Hi

    Thank you for your response.

    Does it means that if I sleep longer, 300 sec for example, and I debounce the switch on interrupt not get a huge increase on a single event, It will sleep 300sec with no pulse, 292 sec with one pule, 284 sec for two pulse (and so on 🙂 )?

    Thank you again for your help and explanation


  • Mod

    @barrydou almost. The sleep function will set the watchdog to 8 seconds and power down the node. When the node is woken up, sleep will assume that 8 seconds has passed.

    If the interrupt happens 7.999 seconds after the node powered down, assuming 8 seconds will yield an error of 0.001 seconds.

    If the interrupt happens 0.2 seconds after the node powered down, assuming 8 seconds will yield an error of 7.8 seconds.

    So it depends on how quickly the interrupts come. In your log you had about 16 pulses per second. That should yield an error of 8-1/16 seconds which is 7.9375 per pulse.



  • Ok thank you very much for all the informations.

    The high rate of interrupts is due to the way I generate the interrupt for the test : with a breadboard jumper manually connected on the pin, so it generates a lot of bounces.

    In a normal behaviour, I will have a reed switch for my gas counter. So it should not occur so much.

    I have not realised that the sleep function "hide" WDT for sleeping (but it's quite logic).
    In fact, in my example, my high rate of interrupts causes the loop to start again. With one event and 6 bounces (so 7 interrupts), the wait period is considered elapsed, even if it was sleeping only from a few seconds.

    I never realised that before 🙂



  • @barrydou I admit confusion, it sounds as if your objective is to derive a flow rate at the gas meter, which you will then pass to Domoticz, but puzzled why? Process monitoring rather than domestic consumption?
    An RTC is the only sure way to get time accuracy, but a standard domestic gas meter reed pulses every 10 litres.
    I just checked Domoticz log on a heating cycle, fastest single pulse would be somewhere around 21 secs, but this Node only sends in every 5 pulses to extend battery life.
    The sketch used here sleeps the loop indefinitely (sleep=0) until triggered by the Reed.
    One caution - I got crazy readings initially despite a debounce circuit, and eventually found the reed closes ca 5 seconds on a typical run, solved by a subroutine check for reed reset before going to sleep.
    The physical and Domoticz meters are still in perfect sync, and the Node on the same 2AA after well over a year. I might go back to single pulses later for greater accuracy, but only out of curiosity.
    The standard Domoticz Gas Meter groups readings into hourly and daily totals. For your own puzzle, the readings come in on timestamps, so perhaps NodeRed might be an alternative way to go to derive a flow rate...



  • No no, my intention is just to send the pulse count, every 10 or 15 minutes, with battery powered sensor (and resend the last value even if it not change, due to domoticz not reporting heartbeat, but that is another story 🙂 )

    Hourly and daily value are ok for me.

    I was using this sketch as an example just to see how it work and if it could directly do the job.
    I enabled sleep_mode.
    I was doing that with a testing arduino, directly connected to radio with jumper, and using jumper to simulate reed.
    Each time I was doing a pulse that way, the node send the information directly. I was not understanding why. So I run a minimal sketch to try to understand, and I found this thread ...

    Finally with all those informations, i think i'll do something like that:

    • The loop sleeps for 1 minute, or for the reed interrupt.
    • When the loop restart, it checked if the reed interrupt occured with the return value of sleep
      -- if yes, it increments pulse count, waits a few ms for debounce, and continues
      -- if no it continues
    • every 10 loops, a msg is send with the pulse count
    • every 60 loops, the battery level is checked
    • and then it sleeps again for 1 minute or if the reed interrupt occurs

    Thank you again for this great help



  • @barrydou Ok, went through much the same head-scratching, even if I still didn't fully understand the detail then, it pretty much worked.
    There really is no need to insert a time element, Domoticz makes 5 minute accumulations then hourly then daily.
    If you leave the loop to ONLY activate on a reed pulse, send in after X pulses (if you wish), and send in battery after YxX pulses, you should be good to go with long battery life.
    Only issue I fell over was holding the reading originally as an INT caused chaos in Domoticz when it rolled over to a minus.
    From memory changing it to a LONG worked but left trailing digits on the live meter update in Domoticz, but I ignored them anyway. One day I might look at it again, but it accurately records otherwise.

    Looked back for the sketch, it is so early in the learning curve the sketch name doesn't bear the Node Number like the rest.

    #include <T2WhisperNode.h>
    
    /**
     * The MySensors Arduino library handles the wireless radio link and protocol
     * between your home built sensors/actuators and HA controller of choice.
     * The sensors forms a self healing radio network with optional repeaters. Each
     * repeater and gateway builds a routing tables in EEPROM which keeps track of the
     * network topology allowing messages to be routed to nodes.
     *
     * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
     * Copyright (C) 2013-2015 Sensnology AB
     * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
     *
     * Documentation: http://www.mysensors.org
     * Support Forum: http://forum.mysensors.org
     *
     * This program is free software; you can redistribute it and/or
     * modify it under the terms of the GNU General Public License
     * version 2 as published by the Free Software Foundation.
     *
     *******************************
     *
     * DESCRIPTION
     *
     * Interrupt driven binary switch example with dual interrupts
     * Author: Patrick 'Anticimex' Fallberg
     * Connect one button or door/window reed switch between
     * digitial I/O pin 3 (BUTTON_PIN below) and GND and the other
     * one in similar fashion on digital I/O pin 2.
     * This example is designed to fit Arduino Nano/Pro Mini
     *
     */
    
    #include <MyConfig.h>
    // Enable debug prints to serial monitor
    //#define MY_DEBUG //Comment out once all working saving memory
    
    // Enable and select radio type attached
    ////#define MY_RADIO_NRF24
    #define MY_RADIO_RFM69
    #define MY_RFM69_FREQUENCY RF69_433MHZ  // Define for frequency setting. Needed if you're radio module isn't 868Mhz (868Mhz is default in lib)
    
    #define MY_RFM69_NETWORKID 101  // Default is 100 in lib. Uncomment it and set your preferred network id if needed
    #define MY_NODE_ID 4  //Manually set the node ID here. Comment out to auto assign
    //A define should be added to provide minimum power output to provide decent RSSI to the Gateway if ATC not available
    #include <SPI.h>
    #include <MySensors.h>
    #define SN "Gas"
    #define SV "1"
    #define FIRST_CHILD_ID 1
    //#define SECOND_CHILD_ID 2
    #define THIRD_CHILD_ID 3
    #define REED_PIN 3   // Arduino Digital I/O pin for button/reed switch
    #define BatteryOn 14
    #define BatteryIn A6
    
    
    // Change to V_LIGHT if you use S_LIGHT in presentation below
    MyMessage msg(FIRST_CHILD_ID, V_VOLUME);
    //MyMessage msg2(SECOND_CHILD_ID, V_VOLUME);
    MyMessage msg3(THIRD_CHILD_ID, V_VOLTAGE);
    
    int GasCycle=0;
    int batteryread=0;
    long gasunit=906867L;
    
    unsigned long SLEEP_TIME = 0; // Sleep time between reports (in milliseconds)
    
    void setup(){
      // Setup the buttons
     pinMode(REED_PIN, INPUT);
     pinMode(BatteryOn, OUTPUT);
     pinMode(BatteryIn, INPUT);
     analogReference(INTERNAL);
    }
    
    void presentation(){
      // Send the sketch version information to the gateway and Controller
      sendSketchInfo(SN, SV);
    
      // Register binary input sensor to sensor_node (they will be created as child devices)
      // You can use S_DOOR, S_MOTION or S_LIGHT here depending on your usage.
      // If S_LIGHT is used, remember to update variable type you send in. See "msg" above.
      present(FIRST_CHILD_ID, S_GAS);
    //  present(SECOND_CHILD_ID, S_GAS);
      present(THIRD_CHILD_ID, S_MULTIMETER);
    }
    
    // Loop will respond then wait for interrupt to reloop
    void loop(){ //Wait for Reed to release from closed
      while(digitalRead(REED_PIN)==LOW){
        sleep(1000);
      }
      
      //Battery Read
     if(batteryread==0){
      digitalWrite(BatteryOn, HIGH);
      int voltread = analogRead(BatteryIn);
      float voltage = (7.272 * voltread) / 1024;
      sleep(5);
      digitalWrite(BatteryOn, LOW);
      send(msg3.set(voltage,2));
      batteryread=-100; 
      sleep(50);
    }
    
     //Increment variables
      batteryread++;
    //  gastotal++;
      gasunit++;
      GasCycle++;
     
    
      if(GasCycle>=5){
        // Short delay to allow setup to properly settle
      sleep(5);
        send(msg.set(gasunit));
    //    send(msg2.set(gastotal));
     sleep(100);
     GasCycle=0;
     }
     sleep(100);// Time to settle down
      // Sleep until something happens with the sensor
      sleep(digitalPinToInterrupt(REED_PIN),LOW, SLEEP_TIME);
    
    }
    

    It still needs tidied, but butcher away with it if it helps. Good luck 😉



  • Hello

    Here is my last code for my gas meter. If it could help somebody

    /*
     * The MySensors Arduino library handles the wireless radio link and protocol
     * between your home built sensors/actuators and HA controller of choice.
     * The sensors forms a self healing radio network with optional repeaters. Each
     * repeater and gateway builds a routing tables in EEPROM which keeps track of the
     * network topology allowing messages to be routed to nodes.
     *
     * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
     * Copyright (C) 2013-2018 Sensnology AB
     * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors
     *
     * Documentation: http://www.mysensors.org
     * Support Forum: http://forum.mysensors.org
     *
     * This program is free software; you can redistribute it and/or
     * modify it under the terms of the GNU General Public License
     * version 2 as published by the Free Software Foundation.
     *
     *******************************
     *
     * REVISION HISTORY
     * Version 1.0 - Henrik Ekblad
     * Version 1.1 - GizMoCuz
     *
     * DESCRIPTION
     * Use this sensor to measure volume and flow of your house water meter.
     * You need to set the correct pulsefactor of your meter (pulses per m3).
     * The sensor starts by fetching current volume reading from gateway (VAR 1).
     * Reports both volume and flow back to gateway.
     *
     * Unfortunately millis() won't increment when the Arduino is in
     * sleepmode. So we cannot make this sensor sleep if we also want
     * to calculate/report flow.
     * http://www.mysensors.org/build/pulse_water
     */
    
    // Enable debug prints to serial monitor
    #define MY_DEBUG
    
    // Enable and select radio type attached
    #define MY_RADIO_RF24
    
    #include <MySensors.h>
    
    #define DIGITAL_INPUT_SENSOR 3                  // The digital input you attached your sensor.  (Only 2 and 3 generates interrupt!)
    #define CHILD_ID 1                              // Id of the sensor child
    
    unsigned long loopNumber = 0;
    unsigned long lastLoopSend = 0;
    
    MyMessage volumeMsg(CHILD_ID, V_VOLUME);
    MyMessage lastCounterMsg(CHILD_ID, V_VAR1);
    
    volatile uint32_t pulseCount = 0;
    bool pcReceived = false;
    double volume = 0;
    
    //=========================
    // BATTERY MEASURER
    // VOLTAGE DIVIDER SETUP
    // 1M, 470K divider across battery and using internal ADC ref of 1.1V
    // Sense point is bypassed with 0.1 uF cap to reduce noise at that point
    // ((1e6+470e3)/470e3)*1.1 = Vmax = 3.44 Volts
    // 3.44/1023 = Volts per bit = 0.003363075
    #define VBAT_PER_BITS 0.003363075
    #define VMIN 2.2                                  //  Vmin (radio Min Volt)=1.9V (564v)
    #define VMAX 3.2                                  //  Vmax = (2xAA bat)=3.0V (892v)
    int batteryPcnt = 0;                              // Calc value for battery %
    int batLoop = 0;                                  // Loop to help calc average
    int batArray[4];                                  // Array to store value for average calc.
    int BATTERY_SENSE_PIN = A0;                       // select the input pin for the battery sense point
    //=========================
    
    
    void setup() {
      // initialize our digital pins internal pullup resistor so one pulse switches from high to low (less distortion)
      pinMode(DIGITAL_INPUT_SENSOR, INPUT_PULLUP);
    
      pulseCount = 0;
    
      // Fetch last known pulse count value from gw
      request(CHILD_ID, V_VAR1);
    
      //Battery
      analogReference(INTERNAL);
      Serial.print("With Battery VMax (100%) = "); Serial.print(VMAX); Serial.print("volts and Vmin (0%) = "); Serial.print(VMIN); Serial.println(" volts");
      Serial.print("Battery Percent 25%/50%/75% calculates to: "); Serial.print(((VMAX - VMIN) / 4) + VMIN); Serial.print("/"); Serial.print(((VMAX - VMIN) / 2) + VMIN); Serial.print("/"); Serial.println(VMAX - ((VMAX - VMIN) / 4));
      delay(1000);
      int sensorValue = analogRead(BATTERY_SENSE_PIN);
      delay(50);
      float Vbat  = sensorValue * VBAT_PER_BITS;
      int batteryPcnt = static_cast<int>(((Vbat - VMIN) / (VMAX - VMIN)) * 100.);
      Serial.print("Current battery are measured to (please confirm!): "); Serial.print(batteryPcnt); Serial.print(" % - Or "); Serial.print(Vbat); Serial.println(" Volts");
    
    
    }
    
    void presentation()
    {
      // Send the sketch version information to the gateway and Controller
      sendSketchInfo("Gas Meter", "2.0");
    
      // Register this device as Water flow sensor
      present(CHILD_ID, S_GAS);
    }
    
    //=========================
    // BATTERY MEASURER
    void MeasureBattery() //The battery calculations
    {
      delay(500);
      // Battery monitoring reading
      int sensorValue = analogRead(BATTERY_SENSE_PIN);
      delay(500);
    
      // Calculate the battery in %
      float Vbat  = sensorValue * VBAT_PER_BITS;
      int batteryPcnt = static_cast<int>(((Vbat - VMIN) / (VMAX - VMIN)) * 100.);
      Serial.print("Battery percent: "); Serial.print(batteryPcnt); Serial.print(" %"); Serial.print("Battery Voltage: "); Serial.print(Vbat); Serial.println(" Volts");
    
      // Add it to array so we get an average of 3 (3x20min)
      batArray[batLoop] = batteryPcnt;
    
      if (batLoop > 2) {
        batteryPcnt = (batArray[0] + batArray[1] + batArray[2] + batArray[3]);
        batteryPcnt = batteryPcnt / 4;
    
        if (batteryPcnt > 100) {
          batteryPcnt = 100;
        }
        Serial.print("Battery Average (Send): "); Serial.print(batteryPcnt); Serial.println(" %");
        sendBatteryLevel(batteryPcnt);
        batLoop = 0;
      }
      else
      {
        batLoop++;
      }
    }
    
    void loop() {
      if (!pcReceived) {
        //Last Pulsecount not yet received from controller, request it again
        request(CHILD_ID, V_VAR1);
        wait(1000);
        return;
      }
      Serial.print("loopNumer=");
      Serial.println(loopNumber);
    
      if (loopNumber % 60 == 0) {
        Serial.println("Measuring Battery");
        //=========================
        // BATTERY MEASURER
        MeasureBattery();
        //=========================
      }
      if (loopNumber % 10 == 0) {
        Serial.println("Sending pulse Count");
        volume = ((double)pulseCount / ((double)1000));
        send(volumeMsg.set(volume,4));
        send(lastCounterMsg.set(pulseCount));
      }
      Serial.println("I'm sleeping");
      int8_t cause = sleep(digitalPinToInterrupt(DIGITAL_INPUT_SENSOR), FALLING, 60000);
      Serial.print("WakeUp , cause:");
      Serial.print(cause);
      Serial.print("(pin interrupt :");
      Serial.print(digitalPinToInterrupt(DIGITAL_INPUT_SENSOR));
      Serial.println(";-1=timer)");
    
      if (cause == digitalPinToInterrupt(DIGITAL_INPUT_SENSOR)) {
        pulseCount++;
        wait(100);
      }
      Serial.print("Pulsecount=");
      Serial.println(pulseCount);
    
      loopNumber++;
    
    }
    
    void receive(const MyMessage &message)
    {
        if (message.type==V_VAR1) {
            uint32_t gwPulseCount=message.getULong();
            pulseCount += gwPulseCount;
            Serial.print("Received last pulse count from gw:");
            Serial.println(pulseCount);
            pcReceived = true;
        }
    }```

 

279
Online

8.7k
Users

9.5k
Topics

99.5k
Posts