💬 Rain Gauge


  • Admin

    According to @Ivan-Z, the MI-SOL Rain Guage has CALIBRATE_FACTOR = 36

    https://forum.mysensors.org/topic/156/rain-guage/112


  • Contest Winner

    @hek Thank you very much. This saves me a lot of time 😉



  • When I try to compile the code above I get the error "'timeStatus' was not declared in this scope" in the line

    while (timeStatus() == timeNotSet && millis() - functionTimeout < 30000UL)
    

    I use Arduino IDE 1.6.10 and inserted the library "Time" from the MySensorsArduinoExamples in the Arduino libraries folder.

    Has anyone a hint for me? Thank you in advance!

    By the way: Thanks a lot to @hek and the forum for the project! 🙂


  • Admin

    Might be best to check with @petewill and @BulldogLowell.

    A quick googling revealed this:
    https://github.com/PaulStoffregen/Time/issues/32

    So if you rename the Time library to Time2 or something and change the include it might work.


  • Contest Winner

    @hek @hoefoigel ,

    I coded the basic sensor and @petewill added the rest and updated... Sorry I cannot be helpful!


  • Admin

    I am currently upgrading my devices to 2.0 using the 1.6.12 IDE. I'll try to work on this one in the next few days and post an update.


  • Admin

    I finally finished with the update and it has been merged to the MySensors github. Here is the link: https://github.com/mysensors/MySensorsArduinoExamples/tree/master/examples/RainGauge
    You will also need to download the updated Time library here: https://github.com/mysensors/MySensorsArduinoExamples/tree/master/libraries/Time

    Let me know if you run into any issues.



  • 123456789



  • which sensor do you use for the rain gauge content sensor


  • Mod

    @李旻峰 the tipping bucket rain sensor is linked on the build page. See the link in the first post on this thread.


  • Contest Winner

    Hi! I bought the rain gauge recommended in the page, put together a simplified version of the sketch which just reports the mm every hour and everything works just fine. However I did notice that during a sunny day almost every hour I have the equivalent of something between 0 and 3 interrupts happening which are clearly false positives. Do you guys suggest anything to mitigate this behavior? I don't think there is anything that can be done in software (an interrupt is an interrupt) so I was wondering if there is anything else which can do the magic 🙂
    Thanks



  • I have been using my tipping bucket for at least 6 month now and I also noticed that the last week I got some fake interrupt. We have had a very nice week in south Sweden so it must be something with the weather that makes the interrupt


  • Contest Winner

    @flopp I may have noticed something similar, while testing it, indoor, I had no fake interrupts at all (even if I did test it for a short time). When outside though, under the sunshine, I had frequent fake interrupts, like there is a voltage drop in that scenario causing it to trigger. I can of course survive with it but I was wondering if there may be a way to mitigate it somehow. I may try to "debounce" it by checking the input after the interrupt but not sure would be effective since I do expect the input to be HIGH again after the interrupt. Thanks



  • My node is batteri powered, can it have something with the battery why this happens?
    I have a second rain gauge powered by USB and that one doesn't give fake interrupt


  • Contest Winner

    Mine is powered by USB but still I have fake interrupts. Agree with you, I guess powering it with batteries could be worse since it is more likely that the voltage would fluctuate so causing fake interrupts. Btw, I assumed the board cannot sleep for this sketch to work, am I wrong? Or are you keeping it awake but still powering it with batteries? Thanks



  • @user2684
    My board is sleep and wake up every 2 hours to send battery voltage or it wake up by interrupt


  • Admin

    @flopp & @user2684 Hmm. Strange. Mine has been running for around 2 years and I have never noticed this behavior. I live in an area where we get lots of nice weather so I'm sure I would have noticed it if it were happening to me. I know that's not helpful for you but hopefully we can get this fixed...
    I don't have any great ideas on how to fix this but you may want to try updating to the latest MySensors bata library. There were some updates recently that fixed some interrupt issues.
    Also, since this was not happening indoors is it possible that there is something else causing this issue like wind or heat?
    Lastly, did you make any changes to the code or wiring for your sensors?



  • I am using version 1.5.?
    I have not opened the rain-box for at least 4 month and not changed the code.
    Maybe this error have been there since day one but I have not checked so often.
    But now I am checking daily because of other nodes that I added recently and then I noticed this


  • Admin

    @flopp What other types of nodes is this happening on? I'd definitely suggest updating to the latest version of the Beta code if you're having interrupt issues.



  • @petewill
    I have never seen it on other nodes and I don't think I had this error when it was cold


  • Contest Winner

    As for myself, I'm using an over-simplified version of your code (https://github.com/mysensors/NodeManager/blob/v1.5-dev/NodeManager.cpp#L585) but the principle should be the same I hope (btw I didn't have the chance to tell you what a great project you put together!). I'm with the latest beta release but since using the arduino's attachInterrupt() in a non-sleeping board, the mysensors' library should not have an impact in my scenario I guess.

    Something I want to check that may cause my issue I think is the power supply. I have a (chinese) USB wall plug connected to a (chinese) USB TTL connected to my arduino board. I wonder if a fluctuating power would generate this behavior (while indoor, it was connected to a different power supply). I'll try this way and report back.

    Out of curiosity those are the logs from my controller (0.11 is 1 interrupt). So this is happening at every hour, up to 9 times per hour so the heat cannot be the issue I might say:

    [2017-05-19 16:22:18] [plugin_mysensors.py:250 - process_inbound()] INFO: [serial_1][5][1] presented as S_RAIN
    [2017-05-19 17:22:07] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.88
    [2017-05-19 19:21:45] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.11
    [2017-05-19 20:21:35] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.66
    [2017-05-19 21:21:25] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.33
    [2017-05-19 22:21:16] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.11
    [2017-05-19 23:21:07] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.66
    [2017-05-20 00:21:00] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.33
    [2017-05-20 01:20:53] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.11
    [2017-05-20 02:20:47] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.00
    [2017-05-20 03:20:41] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.00
    [2017-05-20 04:20:33] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.00
    [2017-05-20 05:20:28] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.00
    [2017-05-20 06:20:24] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.11
    [2017-05-20 07:20:18] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.11
    [2017-05-20 08:20:12] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.00
    [2017-05-20 09:20:04] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.11
    [2017-05-20 10:19:56] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.77
    [2017-05-20 11:19:48] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.22
    [2017-05-20 12:19:37] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.44
    [2017-05-20 13:19:23] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.22
    [2017-05-20 14:19:09] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.22
    [2017-05-20 15:18:55] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.99
    [2017-05-20 16:18:43] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.11
    [2017-05-20 17:18:31] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.00
    [2017-05-20 18:18:21] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.11
    [2017-05-20 19:18:12] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.11
    [2017-05-20 20:18:03] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.11
    [2017-05-20 21:17:55] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.11
    [2017-05-20 22:17:50] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.00
    [2017-05-20 23:17:44] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.00
    [2017-05-21 00:17:39] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.11
    [2017-05-21 01:17:32] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.00
    [2017-05-21 02:17:24] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.11
    [2017-05-21 03:17:16] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.00
    [2017-05-21 04:17:10] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.00
    [2017-05-21 05:17:05] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.11
    [2017-05-21 06:16:58] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.00
    [2017-05-21 07:16:52] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.11
    [2017-05-21 08:16:45] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.11
    [2017-05-21 09:16:38] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.11
    [2017-05-21 10:16:32] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.00
    [2017-05-21 11:16:25] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.11
    [2017-05-21 12:16:16] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.00
    [2017-05-21 13:15:53] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.11
    [2017-05-21 14:15:30] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.00
    [2017-05-21 15:15:15] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.00
    [2017-05-21 16:15:02] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.11
    [2017-05-21 17:14:47] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.11
    [2017-05-21 18:14:35] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.11
    [2017-05-21 19:14:23] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.00
    [2017-05-21 19:14:23] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.00
    [2017-05-21 20:14:11] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.11
    [2017-05-21 20:14:12] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.11
    [2017-05-21 20:14:12] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.11
    [2017-05-21 20:14:12] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.11
    [2017-05-21 20:14:12] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.11
    [2017-05-21 21:14:01] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.44
    [2017-05-21 22:13:49] [plugin_mysensors.py:253 - process_inbound()] INFO: [serial_1][5][1][SET][V_RAIN]: 0.44
    


  • I had fake interupts on my device - would work great on test bench then with a 5v dc converter that was noisey plus a longer cable to the bucket I was getting a lot of trips. My fix which solved all the issues was a 0.1uF ceramic cap from ground to the signal pin of the bucket (right at the adruino) coupled with an inline resistor 330ohm to the bucket and a 1Kohm resistor from +5v to the signal pin. This is a basic pull up and debounce system and it manages to hold the 5V via the cap with 100% reliability thus far for 3 weeks including a lot of rain over the last few days. I would draw a circuit diagram if someone could tell me the best program to use?


  • Contest Winner

    @itbeyond cool thanks! I'll try to put together something similar and report back the results. I guess in this way you don't need INPUT_PULLUP when setting up the pin since already there right? Thanks



  • Last 5 days all of them are fake, always during noon(12:00) isn't that strange?
    0_1495472098137_IMG_4118.PNG



  • @user2684 Yes make the line:
    pinMode(TIP_SENSOR_PIN, INPUT);

    I did make one other modification of installing an RF Choke and cap circuit on the input power supply but I am sure the cap & resistor mods made all the difference. Good luck and let me know how it goes!


  • Admin

    @itbeyond I don't know if it's the best but I use Fritzing to do my diagrams. It is very easy to learn and easy for new people to understand.

    @user2684 I am powering my with a good power supply and I believe it's on the vcc pin (not using the ftdi adapter). Maybe you want to try that?

    @flopp based on what others are saying here I suggest you try changing the power supply as well. Also, are you powering the radio from the arduino or from the power source? If you don't have one already I would add a 100uF capacitor on the radio.


  • Contest Winner

    @itbeyond I've put together today the changes you recommended to my project and see what will happen overnight and tomorrow before moving on and considering replacing the power supply. So far so good since during the last 4 hours I had 0.00 which never happened 4 times in a row so far before applying the resistors and the cap. Btw, my project is 3.3v powered and not 5v like yours, should I use different resistors/capacitors. I'm asking because I'm not 100% sure how you got there 😉 Thanks!



  • @user2684 Those values should be ok - maybe the 330 inline with the switch could be a little smaller but it should be fine with all those values. See how you go.

    I kept my noisy power supply after making these and an RF Choke mod. The RF Choke if you are interested is a 330uH choke inline with the power supply and a cap at 22uF (I used electro) on the inbound power supply just as it hits the board.

    Good luck and do let me know how it is going. I am sure it will sort it.


  • Contest Winner

    @itbeyond I can say it is working perfectly now, thanks! Always 0.00 during the night, I force two triggers this morning and I had the correct equivalent of rain.

    @petewill I'd add this as a note on https://www.mysensors.org/build/rain, even if it is not a common issue, at least for those who will experience it can have a solution ready to use.

    So if I understand correctly (which rarely happens), in a no rain situation it is like the bucket is unplugged and the pin is connected to Vcc through the 1k resistor (to limit the current right?) and also charging the capacitor. When it rains, it is like the bucket would connect the input pin to ground and I guess the capacitor and 330R resistor would smooth this so to actually debounce the signal. Is it the case? Thanks



  • @user2684 That is great news - your understanding is basically correct. When no rain the 1K is providing the pull up to 3.3/5v and charging the cap at the same time (current limit is really for when you go to ground not to hold the pin up). When the bucket tips the cap is discharged via the resistor to ground (bucket switch) and thus the pin goes low. Yes - simple and effective pull up and debounce system which works every time - in fact I use this on all interrupt triggered pins for all my projects.

    @petewill it would be good to include something like this on most of the projects, would have saved me a lot of early angst in having faulty triggered interrupts. I suspect different cloned Arduino boards have different to zero internal pull ups (3 different ones I have tried seem to have none) and to be 100% sure it is much better to document an external arrangement. It will really help the beginners to get it right first time and keep some hair regardless of the quality of the board they are using. I needed this on my irrigation controller also - same problem with a 10cm cable to a push button.


  • Contest Winner

    @itbeyond thanks for the explanation! Last question even if not necessarily mysensors related: how did you size the cap the resistors? Thanks!


  • Admin

    @itbeyond said in 💬 Rain Gauge:

    I needed this on my irrigation controller also - same problem with a 10cm cable to a push button.

    Interesting. I haven't experienced this behavior with any of my devices yet. I do power most of my sensors with my whole house power supply though so I guess that would explain it.

    I will update the rain gauge page and also add this info to the troubleshooting section. Thanks for your help with this!

    If anyone needs a visual of what @itbeyond described above here is the wiring diagram.

    0_1495740779599_Hardware-Debounce-False-Interrupt-Fix.jpg



  • Hi friends,

    here is my replica of Rain Guage MySensors project
    photos:
    https://goo.gl/photos/4kA7T4d8SsDBRrrS7

    The sketch is adopted for 'Adafruit Unified Sensor by Adafruit' + 'DHT sensor library' just uncomment both DHT_ON and DHT_ADAFRUIT
    and last version of Arduino IDE 1.8.3

    ...and Yes, I'm using rfm69hw radio with encryption enabled 😉

    #define MY_RFM69_ENABLE_ENCRYPTION
    
    /*
     Arduino Tipping Bucket Rain Gauge
    
     April 26, 2015
    
     Version 2.0
    
     Arduino Tipping Bucket Rain Gauge
    
     Utilizing a tipping bucket sensor, your Vera home automation controller and the MySensors.org
     gateway you can measure and sense local rain.  This sketch will create two devices on your
     Vera controller.  One will display your total precipitation for the last 5 days.  The other, 
     a sensor that changes state if there is recent rain (up to last 120 hours)  above a threshold.  
     Both these settings are user definable.
    
     There is a build overview video here: https://youtu.be/1eMfKQaLROo
    
     This sketch features the following:
    
     * Allows you to set the rain threshold in mm
     * Allows you to determine the tripped indicator window up to 120 hours.
     * Displays the last 5 days of rain in Variable1 through Variable5
       of the Rain Sensor device
     * Configuration changes to Sensor device updated every hour
     * Should run on any Arduino
     * Will retain Tripped/Not Tripped status and data in a power interruption, saving small amount
       of data to EEPROM (Circular Buffer to maximize life of EEPROM)
     * LED status indicator
     * Optional Temp/Humidity (DHT-22 or DHT-11) and Light LUX (BH1750) sensors. To use, uncomment
       #define DHT_ON  and/or #define LUX_ON
     * Optionally send total accumulation of each day's rainfall or send only individual days rainfall totals.
       Uncomment #define USE_DAILY to display individual daily rainfall.  If it is commented out it will display
       a cumulative total rainfall (day4 = day1+day2+day3+day4 etc)
    
     by @BulldogLowell and @PeteWill for free public use
    
     */
    
    // Enable debug prints to serial monitor
    //#define MY_DEBUG
    //#define MY_DEBUG_VERBOSE
    #define MY_NODE_ID AUTO
    // Enable and select radio type attached
    //#define MY_RADIO_NRF24
    #define MY_RADIO_RFM69
    #define MY_IS_RFM69HW
    #define MY_RFM69_FREQUENCY RF69_433MHZ
    #define MY_RFM69_NETWORKID 100
    #define MY_RFM69_TX_POWER 31
    
    #include <math.h>
    #include <TimeLib.h>
    #include <MySensors.h>
    
    #define SKETCH_NAME "Rain Gauge"
    #define SKETCH_VERSION "2.0"
    
    #define DWELL_TIME 40  // this allows for radio to come back to power after a transmission, ideally 0 
    
    //#define DEBUG_ON  // Rain gauge specific debug messages. 
    #define DHT_ON // uncomment out this line to enable DHT sensor
    
    // 20170621 by Enfeet
    #define DHT_ADAFRUIT // uncomment out this line to enable DHT with 'Adafruit Unified Sensor by Adafruit' + 'DHT sensor library'
    //#define DHTTYPE           DHT11     // DHT 11 
    #define DHTTYPE           DHT22     // DHT 22 (AM2302)
    //#define DHTTYPE           DHT21     // DHT 21 (AM2301)
    // /20170621 by Enfeet
    
    //#define LUX_ON // uncomment out this line to enable BH1750 sensor
    //#define USE_DAILY // Uncomment to display individual daily rainfall totals in the variables sent to your controller. If it's commented it will add each day to the next for a cumulative total.
    
    #define TIP_SENSOR_PIN 3
    //d=112 mm
    //11689.863832 mm2 =  116,89863832 cm2
    //42,77209787776081 mm
    //88 89 91 91 90 = 89,8
    //0,4763039852757329
    #define CALIBRATE_FACTOR 48 // amount of rain per rain bucket tip e.g. 5 is .05mm
    #define DHT_LUX_DELAY 300000  //Delay in milliseconds that the DHT and LUX sensors will wait before sending data
    
    #define CHILD_ID_RAIN_LOG 3  // Keeps track of accumulated rainfall
    #define CHILD_ID_TRIPPED_INDICATOR 4  // Indicates Tripped when rain detected
    #define EEPROM_BUFFER_LOCATION 0  // location of the EEPROM circular buffer
    #define E_BUFFER_LENGTH 240
    #define RAIN_BUCKET_SIZE 120
    
      #ifdef  DEBUG_ON
        #define M_DEBUG_PRINT(x)   Serial.print(x)
        #define M_DEBUG_PRINTLN(x) Serial.println(x)  
        #define SERIAL_START(x)  Serial.begin(x)
        #else
        #define M_DEBUG_PRINT(x)
        #define M_DEBUG_PRINTLN(x)
        #define SERIAL_START(x)
      #endif
    //
    MyMessage msgRainRate(CHILD_ID_RAIN_LOG, V_RAINRATE);
    MyMessage msgRain(CHILD_ID_RAIN_LOG, V_RAIN);
    //
    MyMessage msgRainVAR1(CHILD_ID_RAIN_LOG, V_VAR1);
    MyMessage msgRainVAR2(CHILD_ID_RAIN_LOG, V_VAR2);
    MyMessage msgRainVAR3(CHILD_ID_RAIN_LOG, V_VAR3);
    MyMessage msgRainVAR4(CHILD_ID_RAIN_LOG, V_VAR4);
    MyMessage msgRainVAR5(CHILD_ID_RAIN_LOG, V_VAR5);
    //
    MyMessage msgTripped(CHILD_ID_TRIPPED_INDICATOR, V_TRIPPED);
    MyMessage msgTrippedVar1(CHILD_ID_TRIPPED_INDICATOR, V_VAR1);
    MyMessage msgTrippedVar2(CHILD_ID_TRIPPED_INDICATOR, V_VAR2);
    //
    #ifdef DHT_ON
    // 20170621 by Enfeet
      #ifdef DHT_ADAFRUIT
      #include <Adafruit_Sensor.h>
      #include <DHT_U.h>
      #endif
    // /20170621 by Enfeet
      #include <DHT.h>
      #define CHILD_ID_HUM 0
      #define CHILD_ID_TEMP 1
      #define HUMIDITY_SENSOR_DIGITAL_PIN 8
      #ifndef DHT_ADAFRUIT // 20170621 by Enfeet
        DHT dht;
      #else 
        DHT_Unified dht(HUMIDITY_SENSOR_DIGITAL_PIN, DHTTYPE);
        sensors_event_t event;
      #endif // /20170621 by Enfeet  
      float lastTemp;
      float lastHum;
      bool metric = true;
      MyMessage msgHum(CHILD_ID_HUM, V_HUM);
      MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
    #endif
    //
    #ifdef LUX_ON
      //BH1750 is connected to SCL (analog input A5) and SDA (analog input A4)
      #include <BH1750.h>
      #include <Wire.h>
      #define CHILD_ID_LIGHT 2
      BH1750 lightSensor;
      MyMessage msg(CHILD_ID_LIGHT, V_LIGHT_LEVEL);
      unsigned int lastlux;
      uint8_t heartbeat = 10; //Used to send the light lux to gateway as soon as the device is restarted and after the DHT_LUX_DELAY has happened 10 times
    #endif
    unsigned long sensorPreviousMillis;
    int eepromIndex;
    int tipSensorPin = 3; // Pin the tipping bucket is connected to. Must be interrupt capable pin
    int ledPin = 5; // Pin the LED is connected to.  PWM capable pin required
    #ifdef DEBUG_ON
    unsigned long dataMillis;
    unsigned long serialInterval = 600000UL;
    #endif
    const unsigned long oneHour = 3600000UL;
    unsigned long lastTipTime;
    unsigned long lastRainTime; //Used for rainRate calculation
    unsigned int rainBucket [RAIN_BUCKET_SIZE] ; /* 24 hours x 5 Days = 120 hours */
    unsigned int rainRate = 0;
    uint8_t rainWindow = 72;         //default rain window in hours.  Will be overwritten with msgTrippedVar1.
    volatile int wasTippedBuffer = 0;
    int rainSensorThreshold = 50; //default rain sensor sensitivity in hundredths.  Will be overwritten with msgTrippedVar2.
    uint8_t state = 0;
    uint8_t oldState = 2; //Setting the default to something other than 1 or 0
    unsigned int lastRainRate = 0;
    int lastMeasure = 0;
    bool gotTime = false;
    uint8_t lastHour;
    uint8_t currentHour;
    //
    void presentation()  {
      // Register all sensors to gw (they will be created as child devices)
      sendSketchInfo(SKETCH_NAME, SKETCH_VERSION);
      wait(DWELL_TIME);
      present(CHILD_ID_RAIN_LOG, S_RAIN);
      wait(DWELL_TIME);
      present(CHILD_ID_TRIPPED_INDICATOR, S_MOTION);
      wait(DWELL_TIME);
    
    #ifdef DHT_ON
      present(CHILD_ID_HUM, S_HUM);
      wait(DWELL_TIME);
      present(CHILD_ID_TEMP, S_TEMP);
      wait(DWELL_TIME);
    #endif
    
    
    #ifdef LUX_ON
      present(CHILD_ID_LIGHT, S_LIGHT_LEVEL);
    #endif
    
      M_DEBUG_PRINTLN(F("Sensor Presentation Complete"));
    }
    
    void setup()
    {
      #ifndef MY_DEBUG
      SERIAL_START(115200);  //Start serial if MySensors debugging isn't enabled
      #endif
      //
      // Set up the IO
      pinMode(TIP_SENSOR_PIN, INPUT);
      attachInterrupt (digitalPinToInterrupt(TIP_SENSOR_PIN), sensorTipped, FALLING);  // depending on location of the hall effect sensor may need CHANGE
      pinMode(ledPin, OUTPUT);
      digitalWrite(ledPin, HIGH);
      //
      //Sync time with the server
      //
      unsigned long functionTimeout = millis();
      while (timeStatus() == timeNotSet && millis() - functionTimeout < 30000UL)
      {
        requestTime();
        M_DEBUG_PRINTLN(F("Getting Time"));
        wait(1000); // call once per second
        M_DEBUG_PRINTLN(F("."));
      }
      currentHour = hour();
      lastHour = hour();
      //
      //retrieve from EEPROM stored values on a power cycle.
      //
      bool isDataOnEeprom = false;
      for (int i = 0; i < E_BUFFER_LENGTH; i++)
      {
        uint8_t locator = loadState(EEPROM_BUFFER_LOCATION + i);
        if (locator == 0xFE)  // found the EEPROM circular buffer index
        {
          eepromIndex = EEPROM_BUFFER_LOCATION + i;
          M_DEBUG_PRINT(F("EEPROM Index "));
          M_DEBUG_PRINTLN(eepromIndex);
          //Now that we have the buffer index let's populate the rainBucket[] with data from eeprom
          loadRainArray(eepromIndex);
          isDataOnEeprom = true;
          break;
        }
      }
      //
      if (!isDataOnEeprom) // Added for the first time it is run on a new Arduino
      {
        M_DEBUG_PRINTLN(F("I didn't find valid EEPROM Index, so I'm writing one to location 0"));
        eepromIndex = EEPROM_BUFFER_LOCATION;
        saveState(eepromIndex, 0xFE);
        saveState(eepromIndex + 1, 0xFE);
        //then I will clear out any bad data
        for (int i = 2; i <= E_BUFFER_LENGTH; i++)
        {
          saveState(i, 0x00);
        }
      }
      #ifdef DEBUG_ON
      dataMillis = millis();
      #endif
      lastTipTime = millis(); 
      //
      request(CHILD_ID_TRIPPED_INDICATOR, V_VAR1);
      wait(DWELL_TIME);
      request(CHILD_ID_TRIPPED_INDICATOR, V_VAR2);
      wait(DWELL_TIME);
      //
    #ifdef DHT_ON
    // 20170621 by Enfeet
      #ifndef DHT_ADAFRUIT
        dht.setup(HUMIDITY_SENSOR_DIGITAL_PIN);
      #else
        dht.begin();
      #endif
      metric = getControllerConfig().isMetric;
      wait(DWELL_TIME);
    #endif
      //
    #ifdef LUX_ON
      lightSensor.begin();
    #endif
      //
      transmitRainData(); //Setup complete send any data loaded from eeprom to gateway
    }
    
    void loop()
    {
      if (state)
      {
        prettyFade();  // breathe if tripped
      }
      else
      {
        slowFlash();   // blink if not tripped
      }
    #ifdef DEBUG_ON  // Serial Debug Block
      if ( (millis() - dataMillis) >= serialInterval)
      {
        for (int i = 24; i <= 120; i = i + 24)
        {
          updateSerialData(i);
        }
        dataMillis = millis();
      }
    #endif
      //
      // let's constantly check to see if the rain in the past rainWindow hours is greater than rainSensorThreshold
      //
      int measure = 0; // Check to see if we need to show sensor tripped in this block
      for (int i = 0; i < rainWindow; i++)
      {
        measure += rainBucket [i];
        if (measure != lastMeasure)
        {
          //      M_DEBUG_PRINT(F("measure value (total rainBucket within rainWindow): "));
          //      M_DEBUG_PRINTLN(measure);
          lastMeasure = measure;
        }
      }
      //
      state = (measure >= (rainSensorThreshold * 100));
      if (state != oldState)
      {
        send(msgTripped.set(state));
        wait(DWELL_TIME);
        M_DEBUG_PRINT(F("New Sensor State... Sensor: "));
        M_DEBUG_PRINTLN(state ? "Tripped" : "Not Tripped");
        oldState = state;
      }
      //
      unsigned long tipDelay = millis() - lastRainTime;
      if (wasTippedBuffer) // if was tipped, then update the 24hour total and transmit to Vera
      {
        M_DEBUG_PRINTLN(F("Sensor Tipped"));
        M_DEBUG_PRINT(F("rainBucket [0] value: "));
        M_DEBUG_PRINTLN(rainBucket [0]);
        send(msgRain.set((float)rainTotal(currentHour) / 100, 1)); //Calculate the total rain for the day
        wait(DWELL_TIME);
        wasTippedBuffer--;
        rainRate = ((oneHour) / tipDelay);
        if (rainRate != lastRainRate)
        {
          send(msgRainRate.set(rainRate, 1));
          wait(DWELL_TIME);
          M_DEBUG_PRINT(F("RainRate= "));
          M_DEBUG_PRINTLN(rainRate);
          lastRainRate = rainRate;
        }
        lastRainTime = lastTipTime;
      }
      //
      currentHour = hour();
      if (currentHour != lastHour)
      {
        M_DEBUG_PRINTLN(F("One hour elapsed."));
        send(msgRain.set((float)rainTotal(currentHour) / 100, 1)); // send today's rainfall
        wait(DWELL_TIME);
        saveState(eepromIndex, highByte(rainBucket[0]));
        saveState(eepromIndex + 1, lowByte(rainBucket[0]));
        M_DEBUG_PRINT(F("Saving rainBucket[0] to eeprom. rainBucket[0] = "));
        M_DEBUG_PRINTLN(rainBucket[0]);
        for (int i = RAIN_BUCKET_SIZE - 1; i >= 0; i--)//cascade an hour of values back into the array
        {
          rainBucket [i + 1] = rainBucket [i];
        }
        request(CHILD_ID_TRIPPED_INDICATOR, V_VAR1);
        wait(DWELL_TIME);
        request(CHILD_ID_TRIPPED_INDICATOR, V_VAR2);
        wait(DWELL_TIME);
        rainBucket[0] = 0;
        eepromIndex = eepromIndex + 2;
        if (eepromIndex > EEPROM_BUFFER_LOCATION + E_BUFFER_LENGTH)
        {
          eepromIndex = EEPROM_BUFFER_LOCATION;
        }
        M_DEBUG_PRINT(F("Writing to EEPROM.  Index: "));
        M_DEBUG_PRINTLN(eepromIndex);
        saveState(eepromIndex, 0xFE);
        saveState(eepromIndex + 1, 0xFE);
        requestTime(); // sync the time every hour
        wait(DWELL_TIME);
        transmitRainData();
        rainRate = 0;
        send(msgRainRate.set(rainRate, 1));
        wait(DWELL_TIME);
        M_DEBUG_PRINTLN(F("Sending rainRate is 0 to controller"));
        lastHour = hour();
      }
      if (millis() - sensorPreviousMillis > DHT_LUX_DELAY)
      {
        #ifdef DHT_ON  //DHT Code
          doDHT();
        #endif
        #ifdef LUX_ON
          doLUX();
        #endif
        sensorPreviousMillis = millis();
      }
    }
    //
    #ifdef DHT_ON
    void doDHT(void)
    {
      // 20170621 by Enfeet
      #ifndef DHT_ADAFRUIT
        float temperature = dht.getTemperature();
        if (isnan(temperature))
      #else
        dht.temperature().getEvent(&event);
        float temperature = event.temperature;
        if (isnan(event.temperature))
      #endif
      // /20170621 by Enfeet   
        {
          M_DEBUG_PRINTLN(F("Failed reading temperature from DHT"));
        } else if (temperature != lastTemp) 
        {
          lastTemp = temperature;
          #ifndef DHT_ADAFRUIT
            if (!metric) 
            {
              temperature = dht.toFahrenheit(temperature);
            }
          #endif
          send(msgTemp.set(temperature, 1));
          wait(DWELL_TIME);
          M_DEBUG_PRINT(F("Temperature is: "));
          M_DEBUG_PRINTLN(temperature);
        }
      // 20170621 by Enfeet
      #ifndef DHT_ADAFRUIT
        float humidity = dht.getHumidity();;
        if (isnan(humidity)) 
      #else
        dht.humidity().getEvent(&event);
        float humidity = event.relative_humidity;
        if (isnan(event.relative_humidity))
      #endif
      // /20170621 by Enfeet     
        {
          M_DEBUG_PRINTLN(F("Failed reading humidity from DHT"));
        } else if (humidity != lastHum) 
        {
          lastHum = humidity;
          send(msgHum.set(humidity, 1));
          wait(DWELL_TIME);
          M_DEBUG_PRINT(F("Humidity is: "));
          M_DEBUG_PRINTLN(humidity);
        }
    }
    #endif
    //
    #ifdef LUX_ON
    void doLUX(void)
    {
      unsigned int lux = lightSensor.readLightLevel();// Get Lux value
      M_DEBUG_PRINT(F("Current LUX Level: "));
      M_DEBUG_PRINTLN(lux);
      heartbeat++;
      if (lux != lastlux || heartbeat > 10) 
      {
        send(msg.set(lux));
        lastlux = lux;
      }
      if (heartbeat > 10) 
      {
        heartbeat = 0;
      }
    }
    #endif
    //
    void sensorTipped()
    {
      unsigned long thisTipTime = millis();
      if (thisTipTime - lastTipTime > 100UL)
      {
        rainBucket[0] += CALIBRATE_FACTOR; // adds CALIBRATE_FACTOR hundredths of unit each tip
        wasTippedBuffer++;
      }
      lastTipTime = thisTipTime;
    }
    //
    int rainTotal(int hours)
    {
      int total = 0;
      for ( int i = 0; i <= hours; i++)
      {
        total += rainBucket [i];
      }
      return total;
    }
    
    #ifdef DEBUG_ON
    void updateSerialData(int x)
    {
      M_DEBUG_PRINT(F("Rain last "));
      M_DEBUG_PRINT(x);
      M_DEBUG_PRINTLN(F(" hours: "));
      float tipCount = 0;
      for (int i = 0; i < x; i++)
      {
        tipCount = tipCount + rainBucket [i];
      }
      tipCount = tipCount / 100;
      M_DEBUG_PRINTLN(tipCount);
    }
    #endif
    
    void loadRainArray(int eValue) // retrieve stored rain array from EEPROM on powerup
    {
      for (int i = 1; i < RAIN_BUCKET_SIZE; i++)
      {
        eValue = eValue - 2;
        if (eValue < EEPROM_BUFFER_LOCATION)
        {
          eValue = EEPROM_BUFFER_LOCATION + E_BUFFER_LENGTH;
        }
        M_DEBUG_PRINT(F("EEPROM location: "));
        M_DEBUG_PRINTLN(eValue);
        uint8_t rainValueHigh = loadState(eValue);
        uint8_t rainValueLow = loadState(eValue + 1);
        unsigned int rainValue = rainValueHigh << 8;
        rainValue |= rainValueLow;
        rainBucket[i] = rainValue;
        //
        M_DEBUG_PRINT(F("rainBucket[ value: "));
        M_DEBUG_PRINT(i);
        M_DEBUG_PRINT(F("] value: "));
        M_DEBUG_PRINTLN(rainBucket[i]);
      }
    }
    
    void transmitRainData(void)
    {
      M_DEBUG_PRINT(F("In transmitRainData. currentHour = "));
      M_DEBUG_PRINTLN(currentHour);
      int rainUpdateTotal = 0;
      for (int i = currentHour; i >= 0; i--)
      {
        rainUpdateTotal += rainBucket[i];
        M_DEBUG_PRINT(F("Adding rainBucket["));
        M_DEBUG_PRINT(i);
        M_DEBUG_PRINTLN(F("] to rainUpdateTotal."));
      }
      M_DEBUG_PRINT(F("TX Day 1: rainUpdateTotal = "));
      M_DEBUG_PRINTLN((float)rainUpdateTotal / 100.0);
      send(msgRainVAR1.set((float)rainUpdateTotal / 100.0, 1)); //Send current day rain totals (resets at midnight)
      wait(DWELL_TIME);
    #ifdef USE_DAILY
      rainUpdateTotal = 0;
    #endif
      for (int i = currentHour + 24; i > currentHour; i--)
      {
        rainUpdateTotal += rainBucket[i];
        M_DEBUG_PRINT(F("Adding rainBucket["));
        M_DEBUG_PRINT(i);
        M_DEBUG_PRINTLN(F("] to rainUpdateTotal."));
      }
      M_DEBUG_PRINT(F("TX Day 2: rainUpdateTotal = "));
      M_DEBUG_PRINTLN((float)rainUpdateTotal / 100.0);
      send(msgRainVAR2.set((float)rainUpdateTotal / 100.0, 1));
      wait(DWELL_TIME);
    #ifdef USE_DAILY
      rainUpdateTotal = 0;
    #endif
      for (int i = currentHour + 48; i > currentHour + 24; i--)
      {
        rainUpdateTotal += rainBucket[i];
        M_DEBUG_PRINT(F("Adding rainBucket["));
        M_DEBUG_PRINT(i);
        M_DEBUG_PRINTLN(F("] to rainUpdateTotal."));
      }
      M_DEBUG_PRINT(F("TX Day 3: rainUpdateTotal = "));
      M_DEBUG_PRINTLN((float)rainUpdateTotal / 100.0);
      send(msgRainVAR3.set((float)rainUpdateTotal / 100.0, 1));
      wait(DWELL_TIME);
    #ifdef USE_DAILY
      rainUpdateTotal = 0;
    #endif
      for (int i = currentHour + 72; i > currentHour + 48; i--)
      {
        rainUpdateTotal += rainBucket[i];
        M_DEBUG_PRINT(F("Adding rainBucket["));
        M_DEBUG_PRINT(i);
        M_DEBUG_PRINTLN(F("] to rainUpdateTotal."));
      }
      M_DEBUG_PRINT(F("TX Day 4: rainUpdateTotal = "));
      M_DEBUG_PRINTLN((float)rainUpdateTotal / 100.0);
      send(msgRainVAR4.set((float)rainUpdateTotal / 100.0, 1));
      wait(DWELL_TIME);
    #ifdef USE_DAILY
      rainUpdateTotal = 0;
    #endif
      for (int i = currentHour + 96; i > currentHour + 72; i--)
      {
        rainUpdateTotal += rainBucket[i];
        M_DEBUG_PRINT(F("Adding rainBucket["));
        M_DEBUG_PRINT(i);
        M_DEBUG_PRINTLN(F("] to rainUpdateTotal."));
      }
      M_DEBUG_PRINT(F("TX Day 5: rainUpdateTotal = "));
      M_DEBUG_PRINTLN((float)rainUpdateTotal / 100.0);
      send(msgRainVAR5.set((float)rainUpdateTotal / 100.0, 1));
      wait(DWELL_TIME);
    }
    
    void receive(const MyMessage &message)
    {
      if (message.sensor == CHILD_ID_RAIN_LOG)
      {
        // nothing to do here
      }
      else if (message.sensor == CHILD_ID_TRIPPED_INDICATOR)
      {
        if (message.type == V_VAR1)
        {
          rainWindow = atoi(message.data);
          if (rainWindow > 120)
          {
            rainWindow = 120;
          }
          else if (rainWindow < 1)
          {
            rainWindow = 1;
          }
          if (rainWindow != atoi(message.data))   // if I changed the value back inside the boundries, push that number back to Vera
          {
            send(msgTrippedVar1.set(rainWindow));
          }
        }
        else if (message.type == V_VAR2)
        {
          rainSensorThreshold = atoi(message.data);
          if (rainSensorThreshold > 10000)
          {
            rainSensorThreshold = 10000;
          }
          else if (rainSensorThreshold < 1)
          {
            rainSensorThreshold = 1;
          }
          if (rainSensorThreshold != atoi(message.data))  // if I changed the value back inside the boundries, push that number back to Vera
          {
            send(msgTrippedVar2.set(rainSensorThreshold));
          }
        }
      }
    }
    
    void prettyFade(void)
    {
      float val = (exp(sin(millis() / 2000.0 * PI)) - 0.36787944) * 108.0;
      analogWrite(ledPin, val);
    }
    
    void slowFlash(void)
    {
      static bool ledState = true;
      static unsigned long pulseStart = millis();
      if (millis() - pulseStart < 100UL)
      {
        digitalWrite(ledPin, !ledState);
        pulseStart = millis();
      }
    }
    
    void receiveTime(unsigned long newTime)
    {
      M_DEBUG_PRINTLN(F("Time received..."));
      setTime(newTime);
      char theTime[6];
      sprintf(theTime, "%d:%2d", hour(), minute());
      M_DEBUG_PRINTLN(theTime);
    }
    

    i take an original .stl files from the link provided: https://drive.google.com/drive/folders/0B3KGTJHUgpw1fkwtM3RreEF2QWg4eUdsUHdSQjl6UWx2Q3dPS19WSGdqd0pZQ3hhQk1TMkE

    but in order to save a support material recreate and split it a little 😉

    The result are visible on photos

    here is an .scad code of my modifications on top of original files, also i print them up side down 😉

    $fn=300;
    difference(){
    translate([35,0,0])
    import("Can.stl");
    cube([210,150,150],center=true);
    }
    
    
    
    
    translate([62,0,0])
    rotate([0,90,0])
    difference(){
    cylinder(d=10,h=3,center=true);
    cylinder(d=4,h=6,center=true);
    }
    
    
    difference(){
    translate([-88,0,0])
    sphere(d=300);
    translate([-90,0,0])
    sphere(d=300);
    translate([61,0,0])
    rotate([0,90,0])    
    cylinder(d=4,h=4,center=true);
    rotate([0,90,0])
    difference(){
    cylinder(d=310,h=208,center=true);
    cylinder(d=122.5+4,h=310,center=true);
    }    
    }
    
    
    translate([54,0,0])
    rotate([0,90,0])
    difference(){
    cylinder(d=122.5+4,h=108,center=true);
    cylinder(d=122.5,h=310,center=true);
    } 
    
    $fn=300;
    
    /*
    difference(){
    translate([35,0,0])
    import("Can.stl");
    cube([210,150,150],center=true);
    }
    
    
    
    
    translate([62,0,0])
    rotate([0,90,0])
    difference(){
    cylinder(d=10,h=3,center=true);
    cylinder(d=4,h=6,center=true);
    }
    
    
    difference(){
    translate([-88,0,0])
    sphere(d=300);
    translate([-90,0,0])
    sphere(d=300);
    translate([61,0,0])
    rotate([0,90,0])    
    cylinder(d=4,h=4,center=true);
    rotate([0,90,0])
    difference(){
    cylinder(d=310,h=208,center=true);
    cylinder(d=122.5+4,h=310,center=true);
    }    
    }
    */
    
    translate([54,0,0])
    rotate([0,90,0])
    difference(){
    cylinder(d=122.5+4,h=40
       ,center=true);
    cylinder(d=122.5,h=310,center=true);
    } 
    
    
    translate([32,0,0])
    rotate([0,90,0])
    difference(){
    cylinder(d=122.5+4+4,h=8
       ,center=true);
    cylinder(d=122.5+4,h=9,center=true);
    } 
    

    --
    SY
    Enfeet



  • @Enfeet What type of sensor did you use for the tipping bucket? Reed switch? Hall effect sensor?



  • @dbemowsk

    20mm magnetic contact like this:
    alt text

    SY
    Enfeet



  • @Enfeet Thanks, it was hard to tell from your pics. It almost looked like a hall sensor. I too am using a reed switch. I have some reed switch boards that I salvaged from some old laptops. They were the sensors for closing the LCD.



  • @Enfeet I was checking out your sketch and was confused on some of the numbers you had commented into your sketch. I am gathering that they are numbers you used to figure out your CALIBRATE_FACTOR number, but I am trying to understand them. These are the numbers I am referring to:

    //d=112 mm
    //11689.863832 mm2 =  116,89863832 cm2
    //42,77209787776081 mm
    //88 89 91 91 90 = 89,8
    //0,4763039852757329
    

    I am assuming that 112 mm is the diameter of your catchment funnel. I cannot however figure out your next number 11689.863832 mm2. What formula did you use to come up with that number? Knowing that may help me understand the rest of the numbers.

    Thanks



  • @dbemowsk i use first found online calculator http://onlinemschool.com/math/assistance/figures_area/circle/
    and... strange.... it gives other result 😉 So my calculations are incorrect ;-(
    A = 1 4 π d2 = 1 4 π 1122 = 3136 π ≈ 9852.032512

    SY
    Sergey



  • @Enfeet o! d=122 not 112... uff correct 😉



  • @Enfeet I have been trying to wrap my head around the formulas for this. I have been basing numbers off of the formulas on this instructables page and after looking at his numbers, I think he has them wrong too. He states :

    rainfall height = volume of rain collected / catchment area

    In my rain collector, the length and breadth were 11 cm by 5 cm respectively giving a catchment area of 55 sq.cm. So a collection of 9 milliliters of rain would mean 9 cc/55 sq.cm = 0.16363... cm = 1.6363... mm = 0.394 inches.

    9cc/55 is 0.16363 cm, but 1.6363 mm does not equal 0.394 inches as stated in the article. According to the conversion I did it is 0.064421. Did I do a calculation wrong?



  • @dbemowsk I think it's time to look in a book 😉 "The amount of precipitation is expressed in millimeters of a layer of water that would be formed from the precipitation, if they did not evaporate, did not seep into the soil and would not drain. Numerically, the amount of precipitation in millimeters is equal to the amount of kilograms of water left on the site in 1 sq.meter, i.e. 1 mm = 1 kg / 1 m2.



  • @Enfeet Precipitation intensity
    "Strong" is called rain, if it drops from 15 to 49 mm in 12 hours. Precipitation is also "very strong" when it falls from 50 mm in 12 hours.
    "Strong snow" - the amount of precipitation from 7 to 19 mm for 12 hours. "Very heavy snow," when its amount exceeds 20 mm in 12 hours.



  • @Enfeet I understand that, my point was I guess more that it gets confusing when the person that wrote the article gets the numbers wrong. The other part that can get a little confusing in this at times is the units of measure and the conversions. When you talk about mm (length) vs mm2 (area) vs mm3 (volume) and you start mixing these together in the calculations. I am in the US, so I work with imperial measures, so then there is the conversions from metric to imperial on top of that. The thing that I think the guy that wrote the article got wrong was his conversion to imperial measure (inches of rainfall). That is more what I was trying to wrap my head around.



  • @dbemowsk Sorry, i m living in metric units 😉 But, i think it can be calculated logically. Just look at a DIY project: https://www.education.com/science-fair/article/DIY-rain-gauge/ The logic is to attach a scale to a bottle and measure the mm or inches of rain occured. Our goal is recalculate the number of impulses to the amount of precipitation depending on square of our bucket. So it's possible to take a bottle with the same square like our bucket, attach a scale (inches or mm does not matter) and let collect all water out of our measuring gauge i.e. take a litter or half flow it to a gauge and collect after. And finally just divide measured level of collected water to the number of impulses counted....
    Sorry if method is not clear... 😉 I can draw an idea in a pictures 😉



  • Ups! After 3 days.....

    0_1498752618409_20170629_1909.png



  • What kind of powersupply is a good one, if i have errors with bouncing/fakerain?



  • @schmucke I'm using 5V 1Amp from tiny mobile charger https://www.thingiverse.com/thing:2171813



  • I have the following problem:

    Every Time, if a normal switch with a led bulb is switching, the arduino is count one up...


  • Mod

    Sounds like the hardware debouncing described in the troubleshooting section might be needed.



  • I have just one build, but i use 300ohm. I think, thats to small 😕



  • nice idea, nice project, nice documentation, nice result 👍 ❤ ❤
    but i've a problem with the led. this is only HIGH when the arduino boots up for ~2 secs. then set to 0 (LOW).

    i adjusted some debugging message to find out, what exactly happens, but am stucking here.. in the loop it goes into slowFlash(), but there nothing is called against the led_pin (because of if (millis() - pulseStart < 100UL))

    what am i doing wrong?
    why is the led only fired at startup, but not when trapped (manually closed the reed switch for short time to simulate some rain)?
    what was the intension of the led? (nothing could be found in description & video of pete)
    @petewill I don't see the led in your vid... where is it?



  • Folks, A question of interest. I have had my gauge working great for several months but it has just started to play up. It seems to crash after a few hours. I have not plugged in a debug/console or anything as yet but decided to have a good look at the code and I have noticed that every hour the system cycles through updating EPROM values to cascade the rain rates. I have also noted with interest a comment in the API that mentions some 300K updates as max for the EPROM - I just looked at the Ardunio documentation and it states 100K read/write cycles till EPROM failure. If I am reading this right then maybe my problems are related to dead EPROM storage caused after months of hourly write cycles - Is this a possibility and if yes should we not look at another method of update management for the gauge - I do not want to have to trash an Arduino every few months, I am looking at the code and need more time to get a full handle on it however there appears to be write cycles every hour even if the values have not changed. Is this something to investigate? Is there a way to know if an Arduino EPROM has failed due to excessive write cycles?


  • Mod

    @itbeyond there are 8,760 hours in a year, so 100,000 writes should last more than 10 years.
    MySensors does not re-write the same data if the data has not changed, so a save call does not always result in a write.
    The code uses a ring buffer to lessen the risk of writing too much to a single eeprom position.

    So eeprom writes should not be a problem. But maybe Arduino clones can't handle 100,000 writes?

    I guess an alternative could be to store the data in ram and send it to the controller periodically so the data can be fetched when the Arduino (re)boots. Or do the aggregation on the controller, where ram and storage is plentiful.

    The best way I know to detect eeprom failures is to repeatedly read and measure time for each read. On esp8266 I've seen reads that take more than 100x normal time when the eeprom was damaged.



  • @mfalkvidd thanks for the important info on the saveState - I have not looked at the API code in this respect and if it does not write same data this is a very good. I have also looked into the code some more there are 4 possible writes per hour which using your maths is 35k write per year so it still should be good for a few years (clones well yes who knows). I may have another problem but I am not sure what - if I reboot it is runs fine for several hours and randomly seems to stop sending data however even if the EPROM is stuffed it should not affect the temp, hum and light level sensors. I may be seeing some funny humid reading so the DHT could be faulty also - I may replace this firstly and see what the result is. Thanks for the response.



  • Hi all,

    finally i rewrite a code for myself. There is no More EEPROM usage at all.
    I'm using MajorDoMo (http://majordomohome.com/) and it more suitable for me to have a 10 minutes counts from Rain Gauge.

    Here is my new code:

    #define MY_RFM69_ENABLE_ENCRYPTION
    
    /**
     * 
     Author: Sergey E. Yakovlev
     Date: 2017/02/25 u001
     
     * 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.
     *
    */
    
    #define SKETCH_NAME "Enic Rain Gauge"
    #define SKETCH_VERSION "0.1"
    #define DWELL_TIME 40  // this allows for radio to come back to power after a transmission, ideally 0 
    #define DHT_ON // uncomment out this line to enable DHT sensor
    
    
    
    // Enable debug prints to serial monitor
    //#define MY_DEBUG
    //#define MY_DEBUG_VERBOSE
    //#define MY_NODE_ID AUTO
    #define MY_NODE_ID 15
    #define MY_RADIO_RFM69
    #define MY_IS_RFM69HW
    #define MY_RFM69_FREQUENCY RF69_433MHZ
    #define MY_RFM69_NETWORKID 100
    #define MY_RFM69_TX_POWER 31
    
    #include <MySensors.h>
    #include <Adafruit_Sensor.h>
    #include <DHT_U.h>
    #define CHILD_ID_HUM 0
    #define CHILD_ID_TEMP 1
    #define CHILD_ID_RAIN_LOG 3  // Keeps track of accumulated rainfall
    int tipSensorPin = 3; // Pin the tipping bucket is connected to. Must be interrupt capable pin
    int ledPin = 5; // Pin the LED is connected to.  PWM capable pin required
    #define DHTPIN       8         // Pin which is connected to the DHT sensor.
    // Uncomment the type of sensor in use:
    //#define DHTTYPE           DHT11     // DHT 11 
    #define DHTTYPE           DHT22     // DHT 22 (AM2302)
    //#define DHTTYPE           DHT21     // DHT 21 (AM2301)
    char buff[10];
    unsigned long SEND_FREQUENCY = 60000*10; // Minimum time between send (in milliseconds). We don't wnat to spam the gateway.
    DHT_Unified dht(DHTPIN, DHTTYPE);
    #define TIP_SENSOR_PIN 3
    //d=112 mm
    //11689.863832 mm2 =  116,89863832 cm2
    //42,77209787776081 mm
    //88 89 91 91 90 = 89,8
    //0,4763039852757329
    #define CALIBRATE_FACTOR 48 // amount of rain per rain bucket tip e.g. 5 is .05mm
    MyMessage msgHum(CHILD_ID_HUM, V_HUM);
    MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
    MyMessage msgRain(CHILD_ID_RAIN_LOG, V_RAIN);
    
    sensors_event_t event;
    unsigned long lastSend;               //Last Send millis()
    unsigned long lastTipTime=millis();
    volatile unsigned int rainBucket=0;
    
    void presentation()  {
      // Register all sensors to gw (they will be created as child devices)
      sendSketchInfo(SKETCH_NAME, SKETCH_VERSION);
      wait(DWELL_TIME);
      present(CHILD_ID_RAIN_LOG, S_RAIN);
      wait(DWELL_TIME);
    
    #ifdef DHT_ON
      present(CHILD_ID_HUM, S_HUM);
      wait(DWELL_TIME);
      present(CHILD_ID_TEMP, S_TEMP);
      wait(DWELL_TIME);
    #endif
    
    
    //  M_DEBUG_PRINTLN(F("Sensor Presentation Complete"));
    }
    
    void setup()
    {
      // Set up the IO
      pinMode(TIP_SENSOR_PIN, INPUT);
      attachInterrupt (digitalPinToInterrupt(TIP_SENSOR_PIN), sensorTipped, FALLING);  // depending on location of the hall effect sensor may need CHANGE
      pinMode(ledPin, OUTPUT);
      digitalWrite(ledPin, HIGH);
    
    }
    
    void loop(){
      unsigned long now = millis();
      if (now - lastSend > SEND_FREQUENCY) {
      send(msgRain.set((float)rainBucket / 100, 1));
      rainBucket=0;
      wait(DWELL_TIME);
    
      // Get temperature event and print its value.
      double t = -1;
      dht.temperature().getEvent(&event);
      if (isnan(event.temperature)) {
        debug(PSTR("!USR:DHT:Error reading temperature!\n"));
      } else {
          t = event.temperature;
          dtostrf(t,6,(uint8_t)2,buff); 
          debug(PSTR("USR:DHT:t=%s\n"),buff);
          send(msgTemp.set(buff)); 
      }
      // Get humidity event and print its value.
      double h = -1;
      dht.humidity().getEvent(&event);
      if (isnan(event.relative_humidity)) {
        debug(PSTR("!USR:DHT:Error reading humidity!\n"));
      } else {
          h = event.relative_humidity;
          dtostrf(h,6,(uint8_t)2,buff); 
          debug(PSTR("USR:DHT:h=%s\n"),buff);
          send(msgHum.set(buff));        
      }
        lastSend=now;
      }
    }
    void sensorTipped()
    {
      unsigned long thisTipTime = millis();
      if (thisTipTime - lastTipTime > 100UL)
      {
        rainBucket += CALIBRATE_FACTOR; // adds CALIBRATE_FACTOR hundredths of unit each tip
      }
      lastTipTime = thisTipTime;
    }
    

    0_1505816593504_RainGauge20170918.png

    And now i able to see when it was a rain and how strong it was 😉


    SY
    Sergey


  • Admin

    @itbeyond Like @mfalkvidd pointed out eeprom writes are done to multiple locations so it actually gets 120 hours before the same eeprom location is used. So, 120 X 100,000 is over 1,000 years (if my math is right). That should be enough 🙂

    The good thing about using eeprom is that you won't loose any data if your gateway is down or the communication is lost for some reason.

    I think you are correct debugging other areas like the DHT. Also, is there a chance your arduino got wet? That could also cause issues.



  • Hi, dear how can we connect with application or something to watch and to connect with nidemcu?


  • Hardware Contributor

    Hello! This is my just revised rain gauge sensor. Working with Homeassistant and needs a tipping bucket which closes and opens a reed switch when tipping in the different directions. (Pro Mini 3.3v, Battery operated (voltage divider included in code) and NRF24 radio).

    // Enable debug prints to serial monitor
    #define MY_DEBUG
    
    #define MY_RADIO_RF24
    #define MY_NODE_ID 7
    #define MY_PARENT_NODE_ID 99
    
    #include <SPI.h>
    #include <MySensors.h>
    
    #define DIGITAL_INPUT_SENSOR 3                  // The reed switch you attached.  (Only 2 and 3 generates interrupt!)
    
    #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.2"                    // 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 pulseCount = 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
    int recrequestcount = 0;                        //Counter for how many times we request pulses before we reset it.
    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 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.1                                  //  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()
    {
    
      //=========================
      // BATTERY MEASURER
      //Set internal ref to internal to be able to measure bat 0-1v
      //Make sure this fits other sensors using analogRead()!
      //If you have a sensor reporting 0-5v you need to change analogReference() before reading that sensor.
    
      analogReference(INTERNAL);
      //DEFAULT: the default analog reference of 5 volts (on 5V Arduino boards) or 3.3 volts (on 3.3V Arduino boards)
      //INTERNAL: an built-in reference, equal to 1.1 volts on the ATmega168 or ATmega328 and 2.56 volts on the ATmega8 (not available on the Arduino Mega)
      //EXTERNAL: the voltage applied to the AREF pin (0 to 5V only) is used as the reference.
    
      //Battery inital calc
      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");
      //=========================
    
      delay(500); // Allow time for radio if power used as reset
    
      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();
      //Read if the bucket tipped over
      reedState = digitalRead(DIGITAL_INPUT_SENSOR);
      Serial.println(reedState);
      Serial.println(oldReedState);
    
      boolean tipped = oldReedState != reedState;
    
      if (recrequestcount == 10 && !pcReceived) {
        //For some controllers, if you dont have any V_VAR1 stored node will not get an answer.
        //Try 10 times, then set V_VAR1 to 0 and update controller
        Serial.println("Set p-cnt and update controller");
        pcReceived = true;
        recrequestcount = 0;
        send(lastCounterMsg.set(pulseCount));  // Send pulse count 0 value to gw
        hwRainVolume = 0;
        send(volumeMsg.set((float)hwRainVolume, 1));
        lastSend = currentTime;
      }
    
      //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);
    #ifdef MY_DEBUG
        Serial.println("Req p-cnt");
    #endif
        lastSend = currentTime;
        recrequestcount = recrequestcount + 1;
        return;
      }
      if (!pcReceived) {
        return;
      }
    
      //BUCKET TIPS!
      if (tipped == true) {
        Serial.println("The bucket has tipped over...");
        oldReedState = reedState;
        hwRainVolume = hwRainVolume + bucketSize;
        send(volumeMsg.set((float)hwRainVolume, 1));
        wait(500);
        fullCounter = fullCounter + bucketSize;
    
        //Count so we send the counter for every 1mm
        if (fullCounter >= 1) {
          pulseCount++;
          send(lastCounterMsg.set(pulseCount));
          wait(1000);
          fullCounter = 0;
        }
    
      }
    
      if (tipped == false) {
        //No bucket tipped over last sleep-period, check battery then...
        MeasureBattery();
      }
    
      lastSend = currentTime;
      sleep(digitalPinToInterrupt(DIGITAL_INPUT_SENSOR), CHANGE, SLEEP_TIME); //The interupt can be CHANGE or FALLING depending on how you wired the hardware.
    }
    
    
    void receive(const MyMessage &message)
    {
      if (message.getType() == V_VAR1) {
        pulseCount = message.getLong();
        Serial.print("Received last pulse count value from gw:");
        Serial.println(pulseCount);
        pcReceived = true;
      }
    }
    
    //=========================
    // 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.);
    #ifdef MY_DEBUG
      Serial.print("Battery percent: "); Serial.print(batteryPcnt); Serial.print(" % - "); Serial.print("Battery Voltage: "); Serial.print(Vbat); Serial.println(" Volts");
    #endif
    
      // 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]);
        batteryPcnt = batteryPcnt / 3;
    
        if (batteryPcnt > 100) {
          batteryPcnt = 100;
        }
    #ifdef MY_DEBUG
        Serial.print("Battery Average (Send): "); Serial.print(batteryPcnt); Serial.println(" %");
    #endif
        sendBatteryLevel(batteryPcnt);
        batLoop = 0;
      }
      else
      {
        batLoop++;
      }
    }
    //=========================
    


  • Hi all,
    thanks for sharing the models for 3D printing. I built one 3 years ago and it is still running with one pair of AA batteries, MySensors and Arduino Pro Mini.
    Last year I needed some adjustments and adaptations for friends so I got inspired and remodeled the rain gauge for 3Dprinter.
    Maybe it could be usefull for someone so I decided to share it here (https://www.prusaprinters.org/prints/130513-rain-gauge)


Log in to reply
 

Suggested Topics

  • 3
  • 10
  • 163
  • 110
  • 5
  • 584

0
Online

11.2k
Users

11.1k
Topics

112.5k
Posts