Domotiocz + Rain gauge


  • Hardware Contributor

    Hi!

    Has anyone a sketch with a tipping bucket posting to domoticz?
    I have tried MySensors tippingbucket and also Water pulse meter sketch but cant figure it out...

    Thanx
    Andreas


  • Hardware Contributor

    This is my rainsensor/tipping bucket for MySensors that works with Domoticz.

    It uses 2xAA as power source, a Pro Mini 3.3v with a 0.9 to 3.3 booster.
    The bucket has a magnet which triggeras a reed switch which triggers an interrupt pin.
    I also use battery sensing with voltage divider.

    // Enable debug prints to serial monitor
    #define MY_DEBUG 
    #define MY_RADIO_NRF24
    #define MY_NODE_ID 7
    
    #include <SPI.h>
    #include <MySensor.h>  
    
    // Running this in Domoticz stable version 2.5 will not work - upgrade to beta.
    
    #define DIGITAL_INPUT_SENSOR 3                  // The reed switch you attached.  (Only 2 and 3 generates interrupt!)
    #define INTERRUPT DIGITAL_INPUT_SENSOR-2        // Usually the interrupt = pin -2 (on uno/nano anyway)
    
    #define CHILD_ID 1                              // Id of the sensor child
    #define SKETCH_NAME "Rain Gauge"                // Change to a fancy name you like
    #define SKETCH_VERSION "1.1"                    // Your version
    
    unsigned long SLEEP_TIME = 18*60000;            // Sleep time (in milliseconds).
    //unsigned long SLEEP_TIME = 20000;             // use this instead for debug
    
    float hwRainVolume = 0;                         // Current rainvolume calculated in hardware.
    int hwPulseCounter = 0;                         // Pulsecount recieved from GW
    float fullCounter = 0;                           // Counts when to send counter
    float bucketSize = 0.5;                           // Bucketsize mm, needs to be 1, 0.5, 0.25, 0.2 or 0.1
    boolean pcReceived = false;                     // If we have recieved the pulscount from GW or not 
    boolean reedState;                              // Current state the reedswitch is in
    boolean oldReedState;                           // Old state (last state) of the reedswitch
    unsigned long lastSend =0;                      // Time we last tried to fetch counter.
    
    MyMessage volumeMsg(CHILD_ID,V_RAIN);
    MyMessage lastCounterMsg(CHILD_ID,V_VAR1);
    
    //=========================
    // BATTERY 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 1.9                                  //  Vmin (radio Min Volt)=1.9V (564v)
    #define VMAX 3.0                                  //  Vmax = (2xAA bat)=3.0V (892v)
    int batteryPcnt = 0;                              // Calc value for battery %
    int batLoop = 0;                                  // Loop to help calc average
    int batArray[3];                                  // Array to store value for average calc.
    int BATTERY_SENSE_PIN = A0;                       // select the input pin for the battery sense point
    //=========================
    
    void presentation() {
    
      // Send the Sketch Version Information to the Gateway
      sendSketchInfo(SKETCH_NAME, SKETCH_VERSION);
    
      // Register this device as Rain sensor (will not show in Domoticz until first value arrives)
      present(CHILD_ID, S_RAIN);       
    }
    
    
    void setup()  
    {  
      // use the 1.1 V internal reference
      analogReference(INTERNAL);             // For battery sensing
      
      pinMode(DIGITAL_INPUT_SENSOR, INPUT_PULLUP);  // sets the reed sensor digital pin as input
    
      reedState = digitalRead(DIGITAL_INPUT_SENSOR); // Read what state the reedswitch is in
      oldReedState = reedState; // Set startup position for reedswitch 
      
      Serial.println("Startup completed");
    }
    
    void loop()     
    { 
    unsigned long currentTime = millis();
    
        //See if we have the counter/pulse from Domoticz - and ask for it if we dont.
        if (!pcReceived && (currentTime - lastSend > 5000)) {      
          request(CHILD_ID, V_VAR1);
          lastSend=currentTime;
          return;
        }
        if (!pcReceived) {
          return;
        }
        
    //Read if the bucket tipped over
    reedState = digitalRead(DIGITAL_INPUT_SENSOR);
    boolean tipped = oldReedState != reedState; 
    
        //BUCKET TIPS!
        if (tipped==true) {
        Serial.println("The bucket has tipped over...");
        oldReedState = reedState;
        hwRainVolume = hwRainVolume + bucketSize;
        send(volumeMsg.set((float)hwRainVolume,1));
        wait(1000);
        fullCounter = fullCounter + bucketSize;
    
          //Count so we send the counter for every 1mm
          if(fullCounter >= 1){
          hwPulseCounter++;
          send(lastCounterMsg.set(hwPulseCounter));
          wait(1000);
          fullCounter = 0;
          }
          
        }
        
        if (tipped==false) {
    
         //No bucket tipped over last sleep-period, check battery then...
         batM(); 
        }
    
    lastSend=currentTime;
    sleep(INTERRUPT, CHANGE, SLEEP_TIME); 
    //The interupt can be CHANGE or FALLING depending on how you wired the hardware.
    }
    
    //Read if we have a incoming message.
    void receive(const MyMessage &msg) {
        if (msg.type==V_VAR1) {
        hwPulseCounter = msg.getULong();
        hwRainVolume = hwPulseCounter;
        pcReceived = true;
        Serial.print("Received last pulse count from gw: ");
        Serial.println(hwPulseCounter);   
        }
    }
    
    void batM(){  //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.println(" %");  
       
       // Add it to array so we get an average of 3 (3x20min)
       batArray[batLoop] = batteryPcnt;
      
       if (batLoop > 1) {  
         batteryPcnt = (batArray[0] + batArray[1] + batArray[2]);
         batteryPcnt = batteryPcnt / 3;
     
       if (batteryPcnt > 100) {
         batteryPcnt=100;
     }
     
         Serial.print("Battery Average (Send): "); Serial.print(batteryPcnt); Serial.println(" %");
           sendBatteryLevel(batteryPcnt);
           batLoop = 0;
           
         //Sends 1 per hour as a heartbeat.
         send(volumeMsg.set((float)hwRainVolume,1));   
         send(lastCounterMsg.set(hwPulseCounter));
         }
         else 
         {
         batLoop++;
         }
    }
    

  • Hardware Contributor

    This is great!
    1 year - times fly by, but my rainsensor is going strong!

    I just wanted to celebrate 1 year for my Rainsensor on batteries, reporting every hour (or less when it rains). Still going strong and 81% battery left! Except for some range issues in the beginning you can see its working as it should:

    Also It will be my (almost) 1000th post so thank you all for making MySensors such a great community. I just love every minute here!

    0_1474871808445_1.jpg



  • @sundberg84 Wow, that is impressive! What type of batteries are you using?

    I'm waiting for parts to come in to start building some battery powered and external sensors.


  • Hardware Contributor

    @mrwomble - 2xAA



  • Thats impressive, out of interest are you doing anything with this data in domotiocz?


  • Hardware Contributor

    @Qu3Uk nope, just monitoring. I could probably use it for watering if I made some actuators... but not that garden interested.


  • MySensors Evangelist

    @sundberg84 , very nice. I would say.. I want that as well ๐Ÿ˜‰
    any suggestions for a shopping and modification list?
    As I don't have a 3D printer to print the thing myself.


  • Hardware Contributor


  • Contest Winner

    @sundberg84 Just playing with your sketch, because it's easier for my to understand than the one one the build page. I'm curious about how domoticz handles these values. I don't see you reset the hwRainVolume variable. So does this mean that this is an ever increasing value that must be send to Domoticz?


  • Hardware Contributor

    @TheoL - Correct.
    There is a countervalue and Domoticz calculates the value from midnight each night.


  • Contest Winner

    @sundberg84 Thanx for your fast reply. So what happens when the float resets to 0?


  • Contest Winner

    @sincze Hello my friend, just curious how many sensors you've got hooked up at the moment?


  • Hardware Contributor

    @TheoL - Just to add what we discussed in chat for future questions - If float would hit the maximum value (which is hugh so lets hope its not a problem) im not sure what will happen...


  • Contest Winner

    @sundberg84 It's also not a concern of the MySensors node. This should be handled by Domoticz. I really like your sketch, it works like a charm. I modified it to my needs so that I can run the node without the sleep. Still need to think of an hourly heart beat. But almost there.


  • Hardware Contributor

    @TheoL - If you modify the sketch with a heartbeat() please post it ๐Ÿ™‚ Im interested as well!


  • Contest Winner

    @AWI do you happen to know if the pulse counter in Domoticz is a 1mm pulse counter? Or is it a real tip pulse counter? Right know where checking whenever the rain fall exceeds 1mm and send a pulse ++ in that case. Meaning we miss some pulse counts when we reset the node.


  • Hero Member

    @TheoL My rain meter counts in 1 mm resolution but I am sending actual total (in mm) from the start of sensor and keep totals in EEPROM.


  • Contest Winner

    @AWI (Glad that your back, hope you're doing allright) So, if I understand your setup correctly you don't send the pulse count to Domoticz? I kind of like it, because that way I can reset the rain sensor many times and still keep the rain fall log in sync, without using the EPROM.

    And my rain sensor did reset a couple of times. I had to put a diode (Dutch name is blus diode) between the two wires coming out from the rain gauge to prevent this.


  • Hero Member

    @TheoL (i'm fine, thank you) That is what i'm doing. The only thing what I need to do after a reset is delete the miscalculation in Domoticz (easy). My sensor (oregon) uses a 'reed' switch (no induction). I MySensoriz'ed it without losing the original circuitry and function. (so in parallel).

    0_1475422212074_upload-82d166bf-a999-4d76-b3e3-8c010fa5f427


  • Contest Winner

    @AWI A lesson learned a couple of month ago. When using an induction reed switch (some of them have a coil around the glass) always add a reversed diode. Otherwise the polarity of the reed switch is being turned for just a millisecond which is enough to cause the arduino to reset ;-). I'm still learning a lot about electronics.

    At the moment the diode seems to work. No Arduino resetting for the last couple of hours.

    Regarding to the pulse counter is seems to work perfectly. That way I don't need to store any values on the EPROM, which is something I prefer not to do. I just query the current pulse count from Domoticz when the sensors boots. Sending the total amount of rain is as easy as pulse count * bucket size. Not real rocket science.


  • Contest Winner

    @sundberg84 Here's the first version of the sketch. Note that I don't use the sleep. My main goal for creating my own outside weather station is to get rid of the batteries. Because they always same to stop working whenever I'm not at home.

    /*
     Arduino Tipping Bucket Rain Gauge, SI7021 Temperature + Humidity sensor
    
     Created October 2nd 2016
     Author by Theo
    
     This node uses a tipping bucket rain gauge for measuring rain fall. And a si7021 Temperature and Humidity sensor. The logic in
     this sketch might be specific for Domoticz, because of the Pulse counter.
    
     Based upon sketches created by @BulldogLowell / @PeteWill, @sundber84
     for free public use
    
     Hardware used:
     Arduino Pro Mini 3.3V
     buck converter
     nrf24L01+ radio
     100 uf capacitor
     2 10K resistors (for i2c)
     1N007 diode
     MI-SOL Rain Guage 
     SI7021 sensor
    
     Version history:
     02-10-2016 Initial version
    */
    
    /**
       Configure MySensors
    */
    // Enable debug prints
    // #define MY_DEBUG
    
    // Enable and select radio type attached
    #define MY_RADIO_NRF24
    
    /*
      Include libraries used by the sketch
    */
    #include "ThresholdUtil.h"
    #include <math.h>
    #include <Time.h>
    #include <SI7021.h>
    #include <MySensors.h>
    
    /**
       Define constants used by sketch
    */
    #define BUCKET_PIN 3                  // The Arduino pin to which the bucket is attached. We need an interrupt pin (2 or 3 on the Uno and the Pro Mini) 
    #define SKETCH_INFO "Outside weather" // The name of the sketch as presented to the gateway
    #define SKETCH_VERSION "1.0"          // The version of the sketch as presented to the gateway
    #define CHILD_ID_HUM  2               // The child id of the humidity sensor
    #define CHILD_ID_TEMP 1               // The child id of the temperature sensor
    #define CHILD_ID_RAIN_LOG 4           // The child id of the rain gauge
    #define MS_WAIT 100                   // short delay used to give the NRF24L01+ antenna some time to recover from the last data sending
    #define bucketSize 0.3                // I've used a MI-SOL Rain Guage which has a bucket size of 0.3 mm
    
    /**
       Declare MySensors messages used by the node
    */
    MyMessage msgHum( CHILD_ID_HUM, V_HUM );
    MyMessage msgTemp( CHILD_ID_TEMP, V_TEMP );
    MyMessage msgRain( CHILD_ID_RAIN_LOG, V_RAIN );
    MyMessage lastCounterMsg( CHILD_ID_RAIN_LOG, V_VAR1 );
    
    /**
       Declare variables used by the Sketch
    */
    SI7021 humiditySensor; // Declare a SI7021 Temp humidity sensor object
    float hwRainVolume = 0;           // Current rainvolume calculated in hardware.
    unsigned long hwPulseCounter = 0; // Pulsecount recieved from GW
    boolean pcReceived = false;       // If we have recieved the pulscount from GW or not
    unsigned long lastTipTime = millis(); // TS of when the bucket tip has been detected for the last time
    volatile unsigned long wasTippedCounter; // Queue for storing the tipped counter as been set by the interrupt handler.
    byte lastHour;                    // Stores the hour used for checking if time needs to be synchronized
    
    /**
      Present all child's to the gateway and query for the pulse count known by the HA controller.
    */
    void presentation() {
      // Send the sketch version information to the gateway
      sendSketchInfo( SKETCH_INFO, SKETCH_VERSION );
    
      wait( MS_WAIT );
      // Register all sensors to gw (they will be created as child devices)
      present( CHILD_ID_HUM, S_HUM, "Outside temperature" );
      wait( MS_WAIT );
      present( CHILD_ID_TEMP, S_TEMP, "Outside humidity" );
      wait( MS_WAIT );
      present( CHILD_ID_RAIN_LOG, S_RAIN, "Rain fall" );
      wait( MS_WAIT );
    
      unsigned long functionTimeout = millis();
      while ( pcReceived == false && millis() - functionTimeout < 30000UL ) {
        request( CHILD_ID_RAIN_LOG, V_VAR1);
        Serial.println(F("Getting pulse count"));
        Serial.println(F("."));
        wait( 1000 );
      }
      attachInterrupt( digitalPinToInterrupt( BUCKET_PIN ), sensorTipped, LOW ); //FALLING );  // depending on location of the hall effect sensor may need CHANGE
    }
    
    /**
       Setup of the sketch. It initializes all sensors and queries the gateway for the current time.
    */
    void setup() {
      Serial.begin( 115200 );
      pinMode( BUCKET_PIN, INPUT_PULLUP );
    
      humiditySensor.begin();
    
      registerThresholdedSensor( CHILD_ID_TEMP, 1, TEMPERATURE_SENSOR, 0.5, 30, 20 );
      registerThresholdedSensor( CHILD_ID_HUM, 2, HUMIDTY_SENSOR, 2.0, 30, 20 );
    
      unsigned long functionTimeout = millis();
      while ( timeStatus() == timeNotSet && millis() - functionTimeout < 30000UL ) {
        requestTime();
        Serial.println(F("Getting Time"));
        Serial.println(F("."));
        wait( 1000 );
      }
    
      lastHour = hour();
    }
    
    /**
      Sends the value of the rain gauge to the Gateway.
    */
    void sendRainVolumeData() {
      float hwRainVolume = hwPulseCounter * bucketSize;
      Serial.print( "Tipped " );
      Serial.print( hwPulseCounter );
      Serial.println( " times." );
      Serial.print( "Rain fall is " );
      Serial.print( hwRainVolume, 1 );
      Serial.println( " mm." );
      send( msgRain.set( (float)hwRainVolume, 1 ) );
      wait( MS_WAIT );
      send( lastCounterMsg.set( hwPulseCounter ) );
      wait( MS_WAIT );
    }
    
    /**
      Main loop of the node. It checks:
      - whether the rain gauge bucket has been tipped.
      - whether the hourly heartbeat needs to be send.
      - checks all thresholded sensors
    */
    void loop() {
      if ( wasTippedCounter != hwPulseCounter ) {
        hwPulseCounter = wasTippedCounter;
        sendRainVolumeData();
      }
    
      byte currentHour = hour();
      if (currentHour != lastHour) {
        Serial.println( "Resyncing hour" );
        requestTime(); // sync the time every hour
        wait( MS_WAIT );
        lastHour = currentHour;
        sendRainVolumeData(); // Send heart beat
      }
    
      checkThresholdedSensors( readTHSensor, updatedTHSensorValue );
    }
    
    /**
      Interrupt handler for handling bucket tips.
    */
    void sensorTipped() {
      unsigned long thisTipTime = millis();
      if (thisTipTime - lastTipTime > 100UL) {
        wasTippedCounter++;
      }
      lastTipTime = thisTipTime;
    }
    
    /**
      Threshold util wants to know the current value of a specific sensor.
    */
    void readTHSensor( uint8_t aSensorId, ThreshHoldedSensorType aType, float *value ) {
      si7021_env data = humiditySensor.getHumidityAndTemperature();
      switch ( aSensorId ) {
        case CHILD_ID_TEMP:
          *value = data.celsiusHundredths / 100.0;
          break;
        case CHILD_ID_HUM:
          *value = data.humidityPercent;
          break;
      }
    }
    
    /**
      Threshhold util detects that the value of a specific sensor needs to be send to the gateway.
    */
    void updatedTHSensorValue( uint8_t child_id, uint8_t sensor_id, ThreshHoldedSensorType sensor_type, float value ) {
      switch ( child_id ) {
        case CHILD_ID_TEMP:
          Serial.print( "Sending temp " );
          Serial.println( value, 1 );
          send( msgTemp.set( value, 1 ) );
          wait( MS_WAIT );
          break;
        case CHILD_ID_HUM:
          Serial.print( "Sending Humidity " );
          Serial.println( value, 1 );
          send( msgHum.set( value, 1 ) );
          wait( MS_WAIT );
          break;
      }
    }
    
    /**
      Call back handler for handling time send by the gateway.
    */
    void receiveTime(unsigned long time) {
      Serial.println( F("Time received..."));
      setTime(time);
      char theTime[6];
      sprintf(theTime, "%d:%2d", hour(), minute());
      Serial.println(theTime);
    }
    
    /**
      Callback handler for handling incomming MySensors message.
    */
    void receive(const MyMessage &message) {
      if ( message.sensor == CHILD_ID_RAIN_LOG && message.type == V_VAR1) { // We only expect pulse count values from the gateway
        hwPulseCounter = message.getULong();
        wasTippedCounter = hwPulseCounter;
        pcReceived = true;
    
        Serial.print("Received last pulse count from gw: ");
        Serial.println(hwPulseCounter);
      }
    }
    

    ps. Because the old MySensors API's where removed from the main page, I had to move over to MySensors 2.0. I just uploaded the MySensors 2.0 to my serial gateway and everything seems to work fine. With this I mean all MySensors 1.5 node's are still doing their work. Love it!

    EDITED: Added rain rate. But still testing.


  • Contest Winner

    @AWI last question for today. Do you send the rain rate to domoticz as well? Still figuring out how to do this.


  • Hardware Contributor

    @TheoL - No I dont, and if i remember right its because i sleep the node I cant do the calculations.


  • Contest Winner

    @sundberg84 I've added it. But so far Domoticz doesn't return a value whenever I query a JSON for the sensor. Maybe it does when the clock switches to the next hour.



  • @TheoL said:

    @AWI last question for today. Do you send the rain rate to domoticz as well? Still figuring out how to do this.

    Domoticz have some sort of rain rate, not like mm/12h, mm/6h but it will give mm/h depending how you send data to Domoticz it will be more or less correct.
    0_1475427368240_IMG_2992.PNG


  • Contest Winner

    @flopp Thank you. What do you mean by sending data correctly? Do you have an example sketch?



  • @TheoL said:

    @flopp Thank you. What do you mean by sending data correctly? Do you have an example sketch?

    Not correctly, I wrote depending.

    If you send data every 2 hours and ot every time the buck has tiped the rate will not be correct. Lets say you send/report every 2 hour, you report 10 mm, that means you have "collect" 10 mm for 2 hours. Maybe the hour was not raining, then the rate will show you 10mm/h, sorry if I confusing you.

    What I mean is that you should send/report directly when the buck has tiped then the rate in DZ will be correct rate/h.

    my sketch

    #include <SPI.h>
    #include <MySensor.h> 
    
    // Running this in Domoticz stable version 2.5 will not work - upgrade to beta.
    
    #define DIGITAL_INPUT_SENSOR 3 // The reed switch you attached. (Only 2 and 3 generates interrupt!)
    #define INTERRUPT DIGITAL_INPUT_SENSOR-2 // Usually the interrupt = pin -2 (on uno/nano anyway)
    
    #define CHILD_ID 1 // Id of the sensor child
    #define BATT_CHILD 2
    #define NODE_ID AUTO // or AUTO to let controller assign
    #define SKETCH_NAME "Rain Gauge" // Change to a fancy name you like
    #define SKETCH_VERSION "1.8" // Your version
    
    unsigned long SLEEP_TIME = 180*60000; // Sleep time (in milliseconds).
    //unsigned long SLEEP_TIME = 20000; // use this instead for debug
    
    float hwRainVolume = 0; // Current rainvolume calculated in hardware.
    int hwPulseCounter = 0; // Pulsecount recieved from GW
    float fullCounter = 0; // Counts when to send counter
    float bucketSize = 0.5; // Bucketsize mm, needs to be 1, 0.5, 0.25, 0.2 or 0.1
    boolean pcReceived = false; // If we have recieved the pulscount from GW or not 
    boolean reedState; // Current state the reedswitch is in
    boolean oldReedState; // Old state (last state) of the reedswitch
    unsigned long lastSend =0; // Time we last tried to fetch counter.
    
    MySensor gw;
    MyMessage volumeMsg(CHILD_ID,V_RAIN);
    MyMessage lastCounterMsg(CHILD_ID,V_VAR1);
    MyMessage battMsg(BATT_CHILD, V_VOLTAGE);
    
    //=========================
    // BATTERY 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 1.9 // Vmin (radio Min Volt)=1.9V (564v)
    #define VMAX 3.0 // Vmax = (2xAA bat)=3.0V (892v)
    int batteryPcnt = 0; // Calc value for battery %
    int batLoop = 0; // Loop to help calc average
    int batArray[3]; // Array to store value for average calc.
    int BATTERY_SENSE_PIN = A0; // select the input pin for the battery sense point
    //=========================
    */
    
    long result;
    float batteryPcnt;
    float batteryVolt;
    
    void setup() 
    { 
    pinMode(6,OUTPUT);
    digitalWrite(6,HIGH);
    // use the 1.1 V internal reference
    //analogReference(INTERNAL); // For battery sensing
    
    pinMode(DIGITAL_INPUT_SENSOR, INPUT_PULLUP); // sets the reed sensor digital pin as input
    
    reedState = digitalRead(DIGITAL_INPUT_SENSOR); // Read what state the reedswitch is in
    oldReedState = reedState; // Set startup position for reedswitch
    
    delay(500); // Allow time for radio if power used as reset
    
    //Begin (Change if you dont want static node_id! (NODE_ID to AUTO)
    gw.begin(incomingMessage, NODE_ID, false);
    
    // Send the Sketch Version Information to the Gateway
    gw.sendSketchInfo(SKETCH_NAME, SKETCH_VERSION);
    
    // Register this device as Rain sensor (will not show in Domoticz until first value arrives)
    gw.present(CHILD_ID, S_RAIN); 
    gw.present(BATT_CHILD, S_MULTIMETER);
    
    Serial.println("Startup completed");
    }
    
    void loop() 
    { 
    
    digitalWrite(6,HIGH);
    delay(100);
    
    gw.process();
    //gw.begin(incomingMessage, NODE_ID, false);
    unsigned long currentTime = millis();
    
    //See if we have the counter/pulse from Domoticz - and ask for it if we dont.
    if (!pcReceived && (currentTime - lastSend > 5000)) { 
    gw.begin(incomingMessage, NODE_ID, false);
    gw.request(CHILD_ID, V_VAR1);
    Serial.println("Request pulsecount");
    lastSend=currentTime;
    gw.process();
    return;
    }
    if (!pcReceived) {
    return;
    }
    
    //Read if the bucket tipped over
    reedState = digitalRead(DIGITAL_INPUT_SENSOR);
    boolean tipped = oldReedState != reedState; 
    
    //BUCKET TIPS!
    if (tipped==true) {
    gw.begin(incomingMessage, NODE_ID, false);
    Serial.println("The bucket has tipped over...");
    oldReedState = reedState;
    hwRainVolume = hwRainVolume + bucketSize;
    gw.send(volumeMsg.set((float)hwRainVolume,1));
    gw.wait(1000);
    fullCounter = fullCounter + bucketSize;
    
    //Count so we send the counter for every 1mm
    if(fullCounter >= 1){
    hwPulseCounter++;
    gw.send(lastCounterMsg.set(hwPulseCounter));
    gw.wait(1000);
    fullCounter = 0;
    }
    readVcc(); 
    }
    
    if (tipped==false) {
    
    //No bucket tipped over last sleep-period, check battery then...
    readVcc(); 
    }
    
    lastSend=currentTime;
    Serial.println("sleep");
    digitalWrite(6,LOW);
    delay(1000);
    gw.sleep(INTERRUPT, CHANGE, SLEEP_TIME); 
    //The interupt can be CHANGE or FALLING depending on how you wired the hardware.
    }
    
    //Read if we have a incoming message.
    void incomingMessage(const MyMessage &message) {
    if (message.type==V_VAR1) {
    hwPulseCounter = message.getULong();
    hwRainVolume = hwPulseCounter;
    pcReceived = true;
    Serial.print("Received last pulse count from gw: ");
    Serial.println(hwPulseCounter); 
    }
    }
    /*
    void batM() //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.println(" %"); 
    
    // Add it to array so we get an average of 3 (3x20min)
    batArray[batLoop] = batteryPcnt;
    
    if (batLoop > 1) { 
    batteryPcnt = (batArray[0] + batArray[1] + batArray[2]);
    batteryPcnt = batteryPcnt / 3;
    
    if (batteryPcnt > 100) {
    batteryPcnt=100;
    }
    
    Serial.print("Battery Average (Send): "); Serial.print(batteryPcnt); Serial.println(" %");
    gw.sendBatteryLevel(batteryPcnt);
    batLoop = 0;
    
    //Sends 1 per hour as a heartbeat.
    gw.send(volumeMsg.set((float)hwRainVolume,1));
    gw.send(lastCounterMsg.set(hwPulseCounter));
    }
    else 
    {
    batLoop++;
    }
    }
    */
    long readVcc() {
    Serial.println("readVcc");
    // Read 1.1V reference against AVcc
    ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
    delay(2); // Wait for Vref to settle
    ADCSRA |= _BV(ADSC); // Convert
    while (bit_is_set(ADCSRA,ADSC));
    result = ADCL;
    result |= ADCH<<8;
    result = 1126400L / result; // Back-calculate AVcc in mV
    //return result;
    gw.begin(incomingMessage, NODE_ID, false);
    batteryPcnt = (result - 3300) * 0.111111;
    batteryVolt = result/1000.000;
    gw.sendBatteryLevel(batteryPcnt);
    gw.send(battMsg.set(batteryVolt, 3));
    /*Serial.print("battery volt:");
    Serial.println(batteryVolt, 3);
    Serial.print("battery percent:");
    Serial.println(batteryPcnt);
    */
    }
    

  • Contest Winner

    @flopp Thank you for the explanation. I think I've got it.

    I've added a RAINRATE msg like this
    MyMessage rainRateMsg( CHILD_ID_RAIN_LOG, V_RAINRATE );

    But I don't think domoticz uses it.


  • Contest Winner

    @sundberg84 Using a real pulse counter instead of a 1mm pulse counter seems to work perfectly. Luckily it makes the sketch a bunch easier to implement and read. And there will also be no loss of 0.2 or 0.5 mm rain fall whenever you reset the node while it didn't have a .0 value.



  • @TheoL RAINRATE is implemented according to this page https://github.com/domoticz/domoticz/blob/master/hardware/MySensorsBase.cpp but I don't know how to use it. I know that DZ doesn't work with this example https://www.mysensors.org/build/rain



  • I have adjust my bucked to tip every ~0.25mm and calibrated it ofcourse


  • Hero Member

    Domoticz just recently changed the method of rain rate calculation. It does not interpret rainrate values sent by sensors but calculates this by the total value coming in.


  • Contest Winner

    @AWI Thank you again. I already had a gut feeling this would be the case. I'll strip out the rain rate code from the sketch.


  • Contest Winner

    @TheoL

    Great to see this project continuing to grow legs!



  • This post is deleted!


  • @sundberg84 said:

    I just wanted to celebrate 1 year for my Rainsensor on batteries, reporting every hour (or less when it rains). Still going strong and 81% battery left! Except for some range issues in the beginning you can see its working as it should:

    WOW, nice. Would it be possible to see your Battery graph, if you have one?
    I am send data every 2h or often when it rains but my battery is draining much quicker than yours. Maybe I will get 1 year out of it, so I am happy anyway.
    But I am interested in your graph if the voltage is going down quicker in the beginning.



  • Maybe a stupid question, but it is possible to replace the SI7021 sensor with a DHT-22 sensor (the code has to be changed offsourse)? And get everything to work with ThresholdUtil? I have all parts, but not the SI7021 sensor to build the rain gauge.


  • Contest Winner

    @Hilltan That should really be easy. I've created the threshold util especially for this. You only have to replace the si7021 init part with the DHT22 init part and replace the reading part of the si7021 in the threshold util callback with reading the DHT22 part. Then you're done.

    Just give it a try yourself. It's really not that hard.

    There's however a reason why I use the si7021 instead of the DHT's. I've had serious troubles with the DHT sensors. Some of them wouldn't report the values to the gateway for a week. After the that the node spontaneously started reporting again. I have a sense bender running for more than a half year flawlessly. So in my opinion the si7021 is superior to the DHT.


  • Hero Member

    @Hilltan Like @TheoL mentioned, try to avoid the DHT22, especially for battery powered operation. The DHT-22 is (apart from other disadvantages) specified for a working voltage from 3.3-6V. And tend to get unstable at low voltages.


  • Admin

    Hmm.. @AWI, @TheoL maybe we should replace DHT example on the main site for something more modern?


  • Contest Winner

    @hek That sounds like a good idea. Should we also indicate that the SI7021 is a sensor for more experienced users? Because you need to solder wires or headers to it.


  • Admin

    Yes, But they exist in breakout board variants. So it shouldn't be much more effort than connecting a DHT module.


  • Hero Member

    @hek @TheoL let's join forces. Dht21 or si7021 share the same code and both available on a board with level converter. And a sketch wit Bme280 (with pressure)
    Making a drawing (kicad) is not my thing. The rest ok


  • Admin

    Yep, note that the BMP180/BMP085 is described in the https://www.mysensors.org/build/pressure example. BME280 might be a better choice nowadays perhaps.


  • Contest Winner

    @AWI Would love to join forces with you my friend. I can make a Fritzing ๐Ÿ˜‰


  • Hero Member

    @TheoL deal๐Ÿ‘


  • Contest Winner

    @hek The BME280 is very interesting. But for most of my temp sensors I'm only interested in Temp and Humidity. At the moment I have only one Pressure sensor.



  • @TheoL

    How will the numbers affect the Thresholds reading and reporting of the sensor?

    registerThresholdedSensor( CHILD_ID_TEMP, 1, TEMPERATURE_SENSOR, 0.5, 30, 20 );

    0.5 //What will this do?
    30 //What will this do?
    20 //That one I assume is how often the value will be sent to the gateway?

    void updatedTHSensorValue( uint8_t child_id, uint8_t sensor_id, ThreshHoldedSensorType sensor_type, float value ) {
    switch ( child_id ) {
    case CHILD_ID_TEMP:
    Serial.print( "Sending temp " );
    Serial.println( value, 1 ); //What will this do?
    send( msgTemp.set( value, 1 ) ); //What will this do?
    break;

    I donโ€™t have the SI7021 sensor yet so therefore my questions

    And a problem with the DHT sensor is correct me if I am wrong, is that the DHT sensor does not like to be โ€œreadโ€ to often. How will I do this? Or maybe the answer to my question is in the registerThresholdedSensor code ;).


  • Contest Winner

    @Hilltan I assume that you've downloaded my ThresholdUtil library from my github.

    The three values are:

    • theshHold: The value of threshold is indicates how much the new value needs to differ from the last send value before it triggers a resend.
    • readingInterval: The amount of seconds the library waits before it request a new value for this sensor
    • forcedTransmissionInterval: The amount of measurements without retransmissions, before a retransmission is triggered. In other words if the values of a sensor don't extend the threshold, a retransmissionis triggered of this given amount of readings.

    I just checked my github and there's a none MySensors example handling a DHT22 and a Lux sensors. You can find it here

    I initialize the threshold util as follows

    #include "ThresholdUtil.h"
    
    #include "DHT.h"
    
    DHT dht;
    
    
    #define DHT 0
    
    #define CHILD_ID_TEMP 0
    #define CHILD_ID_HUMIDITY 1
    #define CHILD_ID_LIGHT_SENSOR 2
    #define DHT22_PIN 14
    
    void setup() {
      Serial.begin( 115200 );
    
      registerThresholdedSensor( CHILD_ID_TEMP, DHT, TEMPERATURE_SENSOR, 0.5, 30, 20 ); // every 30 seconds report at least every 10 minutes
      registerThresholdedSensor( CHILD_ID_HUMIDITY, DHT, HUMIDTY_SENSOR, 1.0, 60, 10 ); // every 60 seconds
    
      dht.setup( DHT22_PIN ); // data pin 2
    
      delay( dht.getMinimumSamplingPeriod() );
    
      checkThresholdedSensors( checkThrsedSensor, reportSensorValue ); // Necessary call for intializing ThresholdUtil
    }
    

    This means that I read the temp value every 30 seconds and report the temperature at least every 10 minutes or if the temperature lowers a half degree. But it would be better to change the half degree into 1 degree.
    The humidity gets read every minute and will report at least every 10 minutes as well. Or when the humidity drops or raises 1 %. But I think I would use 2 percent in production.

    To make sure the DHT is not being read to often. I remember the humidity when I read the temperature from the DHT. So when the ThresholdUtil requests the humidity state I return the humidity we last read.

    float dhtHumidity; 
    
    void checkThrsedSensor( uint8_t aSensorId, ThreshHoldedSensorType aType, float *value ) {
      if ( aSensorId == DHT  ) {
        if ( aType == TEMPERATURE_SENSOR ) {
          dhtHumidity = dht.getHumidity();
          *value = dht.getTemperature();
        }
        else {
          *value = dhtHumidity;
        }
      }
      if ( aSensorId == LUX_SENSOR && aType == LIGHTLEVEL_SENSOR ) {
        *value = random( 30, 40 ); // not sure why but I apparently just fake the light level sensor
      }
    }
    

    The remainder of the sketch contains a callback handler for reporting the sensor values e.g. to MySensors. But I've noticed that I need to update that example on github

    void reportSensorValue( uint8_t child_id, uint8_t sensor_id, ThreshHoldedSensorType sensor_type, float value ) {
      Serial.print( millis() ); Serial.print( ": new sensor value " );
     Serial.print( value ); 
    Serial.print( child_id == CHILD_ID_TEMP ? " C" : " %" );
     Serial.print( " for child " );
     Serial.println( child_id == CHILD_ID_TEMP ? "temp" : ( child_id == CHILD_ID_HUMIDITY ? "hum" : "light" ) );
    }
    

    And in the loop we continuously call the checkThresholdedSensors method, that well handle all the timing part for you. So that the check only gets called when needed and the report only when a sensor value needs to be reported.

    void loop() {
      checkThresholdedSensors( checkThrsedSensor, reportSensorValue );
    }
    

    Hope this helps you a bit. I'm currently to occupied to update the sketch for you.



  • Thanks @TheoL, I will give it a try.



  • Finally I get it to run with a light sensor (BH1750), temp/hum sensor (DHT22), and the rain tipping sensor. But there are some problems:

    Domoticz seems not to want to divide the DHT sensor in to two, one humidity and one temperature. What I get in Domoticz is one WTGR800 (temp/hum) and one LaCrosse TX3 (temp). Have played around with the code a little bit, just ending up with one WTGT800 (temp/hum) and one LaCrosse TX3 (temp or humidity).

    The rain sensor gets fault impulse from time to time, the sensor got trigged without that the sensor have been set off?
    Overall your @TheoL Threshhold util is a very nice tool to work with, but the DHT sensor is not that easy to deal with I thinkโ€ฆ

    // Enable and select radio type attached
    #define MY_RADIO_NRF24
    
    /*
      Include libraries used by the sketch
    */
    #include "ThresholdUtil.h"
    #include <math.h>
    #include <Time.h>
    #include <MySensors.h>
    #include <BH1750.h>
    #include "DHT.h"
    #include <Wire.h>
    
    DHT dht;
    #define DHT 0
    
    #define BUCKET_PIN 3                  // The Arduino pin to which the bucket is attached. We need an interrupt pin (2 or 3 on the Uno and the Pro Mini) 
    #define SKETCH_INFO "Outside weather" // The name of the sketch as presented to the gateway
    #define SKETCH_VERSION "1.0"          // The version of the sketch as presented to the gateway
    #define CHILD_ID_RAIN_LOG 4           // The child id of the rain gauge
    #define MS_WAIT 100                   // short delay used to give the NRF24L01+ antenna some time to recover from the last data sending
    #define bucketSize 0.3                // I've used a MI-SOL Rain Guage which has a bucket size of 0.3 mm
    #define LIGHTLEVEL_SENSOR_CHILD_ID 0
    #define LIGHTLEVEL_SENSOR_ID 3
    
    #define CHILD_ID_TEMP 5
    #define DHT_TEMP 6
    #define CHILD_ID_HUMIDITY 7
    #define DHT_HUM 9
    #define DHT_DATA_PIN 8
    
    MyMessage lightLevelMsg(LIGHTLEVEL_SENSOR_CHILD_ID, V_LIGHT_LEVEL);
    MyMessage msgHum( CHILD_ID_HUMIDITY, V_HUM );
    MyMessage msgTemp( CHILD_ID_TEMP, V_TEMP );
    MyMessage msgRain( CHILD_ID_RAIN_LOG, V_RAIN );
    MyMessage lastCounterMsg( CHILD_ID_RAIN_LOG, V_VAR1 );
    
    BH1750 lightSensor;
    float hwRainVolume = 0;           // Current rainvolume calculated in hardware.
    unsigned long hwPulseCounter = 0; // Pulsecount recieved from GW
    boolean pcReceived = false;       // If we have recieved the pulscount from GW or not
    unsigned long lastTipTime = millis(); // TS of when the bucket tip has been detected for the last time
    volatile unsigned long wasTippedCounter; // Queue for storing the tipped counter as been set by the interrupt handler.
    byte lastHour;                    // Stores the hour used for checking if time needs to be synchronized
    
    void presentation() {
      // Send the sketch version information to the gateway
      
      sendSketchInfo( SKETCH_INFO, SKETCH_VERSION );
      wait( MS_WAIT );
      
      present(LIGHTLEVEL_SENSOR_CHILD_ID, S_LIGHT_LEVEL, "Light level" );
      wait( MS_WAIT );  
      present( CHILD_ID_HUMIDITY, S_HUM, "Outside Humidity" );
      wait( MS_WAIT );
      present( CHILD_ID_TEMP, S_TEMP, "Outside Temperature" );
      wait( MS_WAIT );  
      present( CHILD_ID_RAIN_LOG, S_RAIN, "Rain fall" );
      wait( MS_WAIT );
    
      unsigned long functionTimeout = millis();
      while ( pcReceived == false && millis() - functionTimeout < 30000UL ) {
        request( CHILD_ID_RAIN_LOG, V_VAR1);
        Serial.println(F("Getting pulse count"));
        Serial.println(F("."));
        wait( 1000 );
      }
      attachInterrupt( digitalPinToInterrupt( BUCKET_PIN ), sensorTipped, LOW ); //FALLING );  // depending on location of the hall effect sensor may need CHANGE
    }
    
    void setup() {
      Serial.begin( 115200 );
      pinMode( BUCKET_PIN, INPUT_PULLUP );
    
      lightSensor.begin();
      
      registerThresholdedSensor( LIGHTLEVEL_SENSOR_CHILD_ID,  LIGHTLEVEL_SENSOR_ID,  LIGHTLEVEL_SENSOR,  20,  30, 20 ); // read every 5 sec and report at least every 5 minute รคndrat 300 till 20
      registerThresholdedSensor( CHILD_ID_TEMP, DHT_TEMP, TEMPERATURE_SENSOR, 0.5, 30, 20 ); // every 30 seconds report at least every 10 minutes 
      registerThresholdedSensor( CHILD_ID_HUMIDITY, DHT_HUM, HUMIDTY_SENSOR, 1.0, 60, 10 ); // every 60 seconds 
    
      dht.setup( DHT_DATA_PIN ); // data pin 8
      delay( dht.getMinimumSamplingPeriod() );
    
      unsigned long functionTimeout = millis();
      while ( timeStatus() == timeNotSet && millis() - functionTimeout < 30000UL ) {
        requestTime();
        Serial.println(F("Getting Time"));
        Serial.println(F("."));
        wait( 1000 );
      }
    
      lastHour = hour();
    }
    
    /**
      Sends the value of the rain gauge to the Gateway.
    */
    void sendRainVolumeData() {
      float hwRainVolume = hwPulseCounter * bucketSize;
      Serial.print( "Tipped " );
      Serial.print( hwPulseCounter );
      Serial.println( " times." );
      Serial.print( "Rain fall is " );
      Serial.print( hwRainVolume, 1 );
      Serial.println( " mm." );
      send( msgRain.set( (float)hwRainVolume, 1 ) );
      wait( MS_WAIT );
      send( lastCounterMsg.set( hwPulseCounter ) );
      wait( MS_WAIT );
    }
    
    void loop() {
      if ( wasTippedCounter != hwPulseCounter ) {
        hwPulseCounter = wasTippedCounter;
        sendRainVolumeData();
      }
    
      byte currentHour = hour();
      if (currentHour != lastHour) {
        Serial.println( "Resyncing hour" );
        requestTime(); // sync the time every hour
        wait( MS_WAIT );
        lastHour = currentHour;
        sendRainVolumeData(); // Send heart beat
      }
    
    checkThresholdedSensors( readSensorValue, updatedSensorValue );
    
    
    }
    
    void sensorTipped() {
      unsigned long thisTipTime = millis();
      if (thisTipTime - lastTipTime > 100UL) {
        wasTippedCounter++;
      }
      lastTipTime = thisTipTime;
    }
    
    float dhtHumidity; 
    
    void readSensorValue( uint8_t aSensorId, ThreshHoldedSensorType aType, float *value ) {
      switch ( aSensorId ) {    
        case LIGHTLEVEL_SENSOR_ID:
          if ( aType == LIGHTLEVEL_SENSOR ) {
            *value = lightSensor.readLightLevel(); 
          }
          break;      
          case DHT_TEMP:
          if ( aType == TEMPERATURE_SENSOR ) {
            *value = dht.getTemperature();
          }
          break;
          case DHT_HUM:
          if ( aType == HUMIDTY_SENSOR ) {
            *value = dht.getHumidity();
          }
          break;
      }
    }
    
    void updatedSensorValue( uint8_t child_id, uint8_t sensor_id, ThreshHoldedSensorType sensor_type, float value ) {
      switch ( child_id ) {
        case LIGHTLEVEL_SENSOR_CHILD_ID:
          Serial.print( "Light level " ); 
          Serial.print( value, 0 ); 
          Serial.println( "%" );
          send( lightLevelMsg.set( value, 5 ) );
          wait( MS_WAIT );
          break;
        case CHILD_ID_TEMP: 
          Serial.print( "Temperatur " ); 
          Serial.print( value, 0 ); 
          Serial.print( "C" ); 
          send( msgTemp.set( value, 1 ) );
          wait( MS_WAIT );
          break;
        case CHILD_ID_HUMIDITY: 
          Serial.print( "HUMIDITY " ); 
          Serial.print( value, 0 ); 
          Serial.print( "%" ); 
          send( msgHum.set( value, 1 ) );
          wait( MS_WAIT );
          break;  
       
      }
    }
    
    void receiveTime(unsigned long time) {
      Serial.println( F("Time received..."));
      setTime(time);
      char theTime[6];
      sprintf(theTime, "%d:%2d", hour(), minute());
      Serial.println(theTime);
    }
    
    void receive(const MyMessage &message) {
      if ( message.sensor == CHILD_ID_RAIN_LOG && message.type == V_VAR1) { // We only expect pulse count values from the gateway
        hwPulseCounter = message.getULong();
        wasTippedCounter = hwPulseCounter;
        pcReceived = true;
    
        Serial.print("Received last pulse count from gw: ");
        Serial.println(hwPulseCounter);
      }
    }
    

    There are probably strange things in the sketch, I am new to this ๐Ÿ˜‰


  • Hero Member

    @Hilltan it is a Domoticz 'feature' to combine temperature, humidity and barometric sensors. There is a method to separate them if you have (or pretend to have) multiple sensors of the same type. This is done by presenting the one you want to combine right after each other.

    In your case I would just keep it...



  • @sundberg84 sorry I know this is an old thread but hoping you can remember how you wrote this code.I have changed it to suit MYS 2.1 as below. I have also added battery level as a separate child ID so I can watch performance over time. Aside from these simple changes the code is all yours from the start of this post. It is built on v8 of your board, controller/GW is latest domoticz beta running on a PI2 using NRFs.
    I have a couple of questions though. I am curious as to why bucketSize needs to be 1, 0.5, 0.25, 0.2 or 0.1 as per your comments and I suspect that when I calibrate my gauge it wont be any of these.
    I am testing at the moment without the gauge. When I earth D3 it actually reports as TWO bucket tips and the volume goes up by 0.5 twice. I dont think this is a bounce issue due to the many wait(1000) functions in your code. Would you know why this is? I have tried changing CHANGE to FALLING in the sleep function. I have a simple reed switch gague.
    Which leads to my third question. Are all the wait times necessary? Could they be much less? I wonder if I will miss bucket tips because of these during heavy rain...
    Many many thanks,
    Matt

    // Enable debug prints to serial monitor
    #define MY_DEBUG 
    #define MY_RADIO_NRF24
    #define MY_RF24_PA_LEVEL RF24_PA_LOW
    #define MY_RF24_DATARATE RF24_250KBPS
    
    
    #include <MySensors.h>  
    
    // Running this in Domoticz stable version 2.5 will not work - upgrade to beta.
    
    #define DIGITAL_INPUT_SENSOR 3                  // The reed switch you attached.  (Only 2 and 3 generates interrupt!)
    #define INTERRUPT DIGITAL_INPUT_SENSOR-2        // Usually the interrupt = pin -2 (on uno/nano anyway)
    
    #define CHILD_ID 1                              // Id of the sensor child
    #define CHILD_ID_BAT 2                          // Id of BAT
    #define SKETCH_NAME "Rain Gauge"                // Change to a fancy name you like
    #define SKETCH_VERSION "1.1"                    // Your version
    
    unsigned long SLEEP_TIME = 18*60000;            // Sleep time (in milliseconds).
    //unsigned long SLEEP_TIME = 20000;             // use this instead for debug
    
    float hwRainVolume = 0;                         // Current rainvolume calculated in hardware.
    int hwPulseCounter = 0;                         // Pulsecount recieved from GW
    float fullCounter = 0;                           // Counts when to send counter
    float bucketSize = 0.5;                           // Bucketsize mm, needs to be 1, 0.5, 0.25, 0.2 or 0.1
    boolean pcReceived = false;                     // If we have recieved the pulscount from GW or not 
    boolean reedState;                              // Current state the reedswitch is in
    boolean oldReedState;                           // Old state (last state) of the reedswitch
    unsigned long lastSend =0;                      // Time we last tried to fetch counter.
    
    MyMessage volumeMsg(CHILD_ID,V_RAIN);
    MyMessage lastCounterMsg(CHILD_ID,V_VAR1);
    MyMessage msgBat(CHILD_ID_BAT, V_VOLTAGE);
    
    //=========================
    // BATTERY 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 1.9                                  //  Vmin (radio Min Volt)=1.9V (564v)
    #define VMAX 3.0                                  //  Vmax = (2xAA bat)=3.0V (892v)
    int batteryPcnt = 0;                              // Calc value for battery %
    int batLoop = 0;                                  // Loop to help calc average
    int batArray[3];                                  // Array to store value for average calc.
    int BATTERY_SENSE_PIN = A0;                       // select the input pin for the battery sense point
    //=========================
    
    void presentation() {
    
      // Send the Sketch Version Information to the Gateway
      sendSketchInfo(SKETCH_NAME, SKETCH_VERSION);
    
      // Register this device as Rain sensor (will not show in Domoticz until first value arrives)
      present(CHILD_ID, S_RAIN); 
      present(CHILD_ID_BAT, S_MULTIMETER);      
    }
    
    
    void setup()  
    {  
                                                     // use the 1.1 V internal reference
      analogReference(INTERNAL);                     // For battery sensing
      
      pinMode(DIGITAL_INPUT_SENSOR, INPUT_PULLUP);   // sets the reed sensor digital pin as input
    
      reedState = digitalRead(DIGITAL_INPUT_SENSOR); // Read what state the reedswitch is in
      oldReedState = reedState;                      // Set startup position for reedswitch 
      
      Serial.println("Startup completed");
      delay(500);                                    // Allow time for radio if power used as reset
    }
    
    void loop()     
    { 
    unsigned long currentTime = millis();
    
        //See if we have the counter/pulse from Domoticz - and ask for it if we dont.
        if (!pcReceived && (currentTime - lastSend > 5000)) {      
          request(CHILD_ID, V_VAR1);
          lastSend=currentTime;
          return;
        }
        if (!pcReceived) {
          return;
        }
        
    //Read if the bucket tipped over
    reedState = digitalRead(DIGITAL_INPUT_SENSOR);
    boolean tipped = oldReedState != reedState; 
    
        //BUCKET TIPS!
        if (tipped==true) {
        Serial.println("The bucket has tipped over...");
        oldReedState = reedState;
        hwRainVolume = hwRainVolume + bucketSize;
        send(volumeMsg.set((float)hwRainVolume,1));
        wait(1000);
        fullCounter = fullCounter + bucketSize;
    
          //Count so we send the counter for every 1mm
          if(fullCounter >= 1){
          hwPulseCounter++;
          send(lastCounterMsg.set(hwPulseCounter));
          wait(1000);
          fullCounter = 0;
          }
          
        }
        
        if (tipped==false) {
    
         //No bucket tipped over last sleep-period, check battery then...
         batM(); 
        }
    
    lastSend=currentTime;
    sleep(INTERRUPT, FALLING, SLEEP_TIME); 
    //The interupt can be CHANGE or FALLING depending on how you wired the hardware.
    }
    
    //Read if we have a incoming message.
    void receive(const MyMessage &msg) {
        if (msg.type==V_VAR1) {
        hwPulseCounter = msg.getULong();
        hwRainVolume = hwPulseCounter;
        pcReceived = true;
        Serial.print("Received last pulse count from gw: ");
        Serial.println(hwPulseCounter);   
        }
    }
    
    void batM(){  //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.println(" %");  
       
       // Add it to array so we get an average of 3 (3x20min)
       batArray[batLoop] = batteryPcnt;
      
       if (batLoop > 1) {  
         batteryPcnt = (batArray[0] + batArray[1] + batArray[2]);
         batteryPcnt = batteryPcnt / 3;
     
       if (batteryPcnt > 100) {
         batteryPcnt=100;
     }
     
         Serial.print("Battery Average (Send): "); Serial.print(batteryPcnt); Serial.println(" %");
           sendBatteryLevel(batteryPcnt);
           send(msgBat.set(Vbat, 4));
           batLoop = 0;
           
         //Sends 1 per hour as a heartbeat.
         send(volumeMsg.set((float)hwRainVolume,1));   
         send(lastCounterMsg.set(hwPulseCounter));
         }
         else 
         {
         batLoop++;
         }
    }```

  • Hardware Contributor

    @Matt said in Domotiocz + Rain gauge:

    OK ๐Ÿ™‚ Lets see what I can do...

    I am curious as to why bucketSize needs to be 1, 0.5, 0.25, 0.2 or 0.1 as per your comments and I suspect that when I calibrate my gauge it wont be any of these.

    Its because of this calculaction and that Domoticz uses 1mm counter:

        fullCounter = fullCounter + bucketSize;
    
          //Count so we send the counter for every 1mm
          if(fullCounter >= 1){
          hwPulseCounter++;
          send(lastCounterMsg.set(hwPulseCounter));
          wait(1000);
          fullCounter = 0;
          }
    

    If the bucketsize is set to say 0,3mm it will not add up to a full 1 and the code is lost. (0,3+0,3+0,3+0,3 = 1.2) and 0,2 is lost. Im sure you can code this better (code is not my strong side!!!)

    I am testing at the moment without the gauge. When I earth D3 it actually reports as TWO bucket tips and the volume goes up by 0.5 twice. I dont think this is a bounce issue due to the many wait(1000) functions in your code. Would you know why this is? I have tried changing CHANGE to FALLING in the sleep function. I have a simple reed switch gague.

    Do you have a pulldown/up resistor to avoid the pin floats?

    Are all the wait times necessary? Could they be much less?

    Its a matter of code and what bucket you have. Some wait() are for debounce and stabilising power for radio and readings. I would not change those but I always aim for the high numbers to be sure(wait(1000); = really high!!). Try!
    Other wait() could depend on what kind of bucket you use - im sorry to say, but all you can do is try!



  • @sundberg84
    Thankyou very much for your reply.
    It seems strange that domoticz would only accept 1mm pulses I wonder if this has changed... In any case it should be easy to save the 'lost' volume and add it to the next bucket in code...
    The internal pullup is switched on in code so reed switch pin won't be floating. Will have a fiddle round with your code today.
    Will also try to calibrate by gauge today will be easy to see max tipping speed and can adjust wait times accordingly...
    Thanks again,
    Matt


  • Hardware Contributor

    @Matt - Let me know if I can help you anything-



  • I need could need some help/advice to get my rain gauge to show correct values, as per today my rain gauge shows to low values. The rain gauge that I use is this one: Rain gauge
    I use Domoticz V 3.8153 with Mysensors V2.1.1 and have bucket size 0,3. Anyone that have experience with this rain gauge and what bucket size to use for correct values or is there something with my code that creates problems?

    This it my sketch that I am usning:

    // Enable and select radio type attached
    #define MY_RADIO_NRF24
    #define MY_NODE_ID 5
    
    #include "ThresholdUtil.h"
    #include <math.h>
    #include <Time.h>
    #include <MySensors.h>
    #include "DHT.h"
    #include <Wire.h>
    
    DHT dht;
    #define DHT 0
    
    #define BUCKET_PIN 3                  // The Arduino pin to which the bucket is attached. We need an interrupt pin (2 or 3 on the Uno and the Pro Mini) 
    #define SKETCH_INFO "Rain,Temp&Hum" // The name of the sketch as presented to the gateway
    #define SKETCH_VERSION "1.0"          // The version of the sketch as presented to the gateway
    #define CHILD_ID_RAIN_LOG 4           // The child id of the rain gauge
    #define MS_WAIT 100                   // short delay used to give the NRF24L01+ antenna some time to recover from the last data sending
    #define bucketSize 0.3                // I've used a MI-SOL Rain Guage which has a bucket size of 0.3 mm
    
    
    #define CHILD_ID_TEMP 5
    #define DHT_TEMP 6
    #define CHILD_ID_HUMIDITY 7
    #define DHT_HUM 9
    #define DHT_DATA_PIN 5
    
    MyMessage msgHum( CHILD_ID_HUMIDITY, V_HUM );
    MyMessage msgTemp( CHILD_ID_TEMP, V_TEMP );
    MyMessage msgRain( CHILD_ID_RAIN_LOG, V_RAIN );
    MyMessage lastCounterMsg( CHILD_ID_RAIN_LOG, V_VAR1 );
    
    
    float hwRainVolume = 0;           // Current rainvolume calculated in hardware.
    unsigned long hwPulseCounter = 0; // Pulsecount recieved from GW
    boolean pcReceived = false;       // If we have recieved the pulscount from GW or not
    unsigned long lastTipTime = millis(); // TS of when the bucket tip has been detected for the last time
    volatile unsigned long wasTippedCounter; // Queue for storing the tipped counter as been set by the interrupt handler.
    byte lastHour;                    // Stores the hour used for checking if time needs to be synchronized
    
    void presentation() {
      // Send the sketch version information to the gateway
      
      sendSketchInfo( SKETCH_INFO, SKETCH_VERSION );
      wait( MS_WAIT );  
      present( CHILD_ID_HUMIDITY, S_HUM, "Outside Humidity" );
      wait( MS_WAIT );
      present( CHILD_ID_TEMP, S_TEMP, "Outside Temperature" );
      wait( MS_WAIT );  
      present( CHILD_ID_RAIN_LOG, S_RAIN, "Rain fall" );
      wait( MS_WAIT );
    
      unsigned long functionTimeout = millis();
      while ( pcReceived == false && millis() - functionTimeout < 30000UL ) {
        request( CHILD_ID_RAIN_LOG, V_VAR1);
        Serial.println(F("Getting pulse count"));
        Serial.println(F("."));
        wait( 1000 );
      }
      attachInterrupt( digitalPinToInterrupt( BUCKET_PIN ), sensorTipped, LOW ); //FALLING );  // depending on location of the hall effect sensor may need CHANGE, LOW or HIGE
    }
    
    void setup() {
      Serial.begin( 115200 );
      pinMode( BUCKET_PIN, INPUT_PULLUP ); 
    
      registerThresholdedSensor( CHILD_ID_TEMP, DHT_TEMP, TEMPERATURE_SENSOR, 0.5, 60, 8 ); // Change of value +/-0,5 , every 60 seconds report, and force report every 8 minutes 
      registerThresholdedSensor( CHILD_ID_HUMIDITY, DHT_HUM, HUMIDTY_SENSOR, 1.0, 60, 8 ); // Change of value +/- 1, every 60 seconds report, and force report every 8 minutes  
    
      dht.setup( DHT_DATA_PIN ); // data pin 8
      delay( dht.getMinimumSamplingPeriod() );
    
      unsigned long functionTimeout = millis();
      while ( timeStatus() == timeNotSet && millis() - functionTimeout < 30000UL ) {
        requestTime();
        Serial.println(F("Getting Time"));
        Serial.println(F("."));
        wait( 1000 );
      }
    
      lastHour = hour();
    }
    
    /**
      Sends the value of the rain gauge to the Gateway.
    */
    void sendRainVolumeData() {
      float hwRainVolume = hwPulseCounter * bucketSize;
      Serial.print( "Tipped " );
      Serial.print( hwPulseCounter );
      Serial.println( " times." );
      Serial.print( "Rain fall is " );
      Serial.print( hwRainVolume, 1 );
      Serial.println( " mm." );
      send( msgRain.set( (float)hwRainVolume, 1 ) );
      wait( MS_WAIT );
      send( lastCounterMsg.set( hwPulseCounter ) );
      wait( MS_WAIT );
    }
    
    void loop() {
      if ( wasTippedCounter != hwPulseCounter ) {
        hwPulseCounter = wasTippedCounter;
        sendRainVolumeData();
      }
    
      byte currentHour = hour();
      if (currentHour != lastHour) {
        Serial.println( "Resyncing hour" );
        requestTime(); // sync the time every hour
        wait( MS_WAIT );
        lastHour = currentHour;
        sendRainVolumeData(); // Send heart beat
      }
    
    checkThresholdedSensors( readSensorValue, updatedSensorValue );
    
    
    }
    
    void sensorTipped() {
      unsigned long thisTipTime = millis();
      if (thisTipTime - lastTipTime > 100UL) {
        wasTippedCounter++;
      }
      lastTipTime = thisTipTime;
    }
    
    float dhtHumidity; 
    
    void readSensorValue( uint8_t aSensorId, ThreshHoldedSensorType aType, float *value ) {
      switch ( aSensorId ) {    
          case DHT_TEMP:
          if ( aType == TEMPERATURE_SENSOR ) {
            *value = dht.getTemperature();
          }
          break;
          case DHT_HUM:
          if ( aType == HUMIDTY_SENSOR ) {
            *value = dht.getHumidity();
          }
          break;
      }
    }
    
    void updatedSensorValue( uint8_t child_id, uint8_t sensor_id, ThreshHoldedSensorType sensor_type, float value ) {
      switch ( child_id ) {
          case CHILD_ID_TEMP: 
          Serial.print( "Temperatur " ); 
          Serial.print( value, 0 ); 
          Serial.print( "C" ); 
          send( msgTemp.set( value, 1 ) );
          wait( MS_WAIT );
          break;
        case CHILD_ID_HUMIDITY: 
          Serial.print( "HUMIDITY " ); 
          Serial.print( value, 0 ); 
          Serial.print( "%" ); 
          send( msgHum.set( value, 1 ) );
          wait( MS_WAIT );
          break;  
       
      }
    }
    
    void receiveTime(unsigned long time) {
      Serial.println( F("Time received..."));
      setTime(time);
      char theTime[6];
      sprintf(theTime, "%d:%2d", hour(), minute());
      Serial.println(theTime);
    }
    
    void receive(const MyMessage &message) {
      if ( message.sensor == CHILD_ID_RAIN_LOG && message.type == V_VAR1) { // We only expect pulse count values from the gateway
        hwPulseCounter = message.getULong();
        wasTippedCounter = hwPulseCounter;
        pcReceived = true;
    
        Serial.print("Received last pulse count from gw: ");
        Serial.println(hwPulseCounter);
      }
    } 
    


  • Hi
    I am using this sketch on my battery powered rain gauge but have noticed the gauge never resets, how are you managing this? i am using Vera as a controller


  • Hardware Contributor

    @jch I made this just because the standard sketch didn't work with domoticz. The example sketch should work with Vera. It's been a long time now since I made this so thing might changed.



  • Ok thanks for the reply.... I was only wanting to use your sketch as my node is battery powered and the mysensors example uses a lot of power as it doesn't sleep.
    I will try and modify it.


 

368
Online

7.9k
Users

8.7k
Topics

93.7k
Posts