Water leak sensor



  • Finally I made my water leak sensor that I have been dreaming about for a long time now 🙂
    I used those items:
    Enclosure
    2 x AA batteris incl holder
    nRF24L01+
    Home made PCB with ATmega328P-PU
    red, green LED
    si7021, temp & hum
    some capactitors and resistors
    Kitchen aluminum foil
    Copper wire

    I am measuring temperature and humidity with a Si7021, measuring battery voltage with voltage divider and internal reference, just to test which one that shows most correct.

    /**
     * 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.
     *
     *******************************
     *
     * REVISION HISTORY
     * Version 1.0 - Henrik EKblad
     * 
     */
    // Enable and select radio type attached
    #define MY_RADIO_NRF24
    
    // Enable debug prints to serial monitor
    #define MY_DEBUG
    
    #define MY_NODE_ID 27
    
    #include <SPI.h>
    #include <MySensors.h>
    #include <Wire.h>
    #include <SI7021.h>
    
    #define CHILD_SIHUM 0
    #define CHILD_SITEMP 1
    #define CHILD_BATT 2
    #define CHILD_SIDEW 3
    #define CHILD_BATTRES 4
    
    #define CHILD_WATER 10
    
    #define CHILD_FAILS 250
    #define CHILD_PARENT 251
    #define CHILD_DISTANCE 252
    #define CHILD_SLEEPTIME 253
    
    //LED
    int GREEN = 7;
    int RED = 8;
    
    //Water alarm
    int Interrupt = 1; // pin 3 on UNO/Nano
    
    //SleepTime
    float SleepTime = 30; // Sleep time between reads (in minutes)
    int OldSleepTime = -1;
    int SleepTimeLoopCount = 10;
    
    //ReadVCC
    long result;
    float BatteryVolt;
    float OldBatteryVolt;
    int BatteryVoltLoopCount = 5;
    
    //ReadVCCRes
    int sensorValue;
    float BatteryResVolt;
    int BATTERY_SENSE_PIN = A2;  // select the input pin for the battery sense point
    
    //SI7021
    SI7021 SI;
    int SILoopCount = 5;
    int SIHum;
    int OldSIHum = -1;
    float SITemp;
    float OldSITemp = -1;
    float SIDew;
    float OldSIDew = -1;
    
    //NRF
    int Fails = 0;
    int OldFails = -1;
    int FailsLoopCount = 10;
    int OldParentNode = -1;
    int ParentNodeLoopCount = 10;
    int OldDistanceNode = -1;
    int DistanceLoopCount = 10;
    
    MyMessage msgSIHum(CHILD_SIHUM, V_HUM);
    MyMessage msgSITemp(CHILD_SITEMP, V_TEMP);
    MyMessage msgSIDew(CHILD_SIDEW, V_TEMP);
    MyMessage msgBatt(CHILD_BATT, V_VOLTAGE);
    MyMessage msgBattRes(CHILD_BATTRES, V_VOLTAGE);
    
    MyMessage msgWater(CHILD_WATER, V_TRIPPED);
    
    MyMessage msgFails(CHILD_FAILS, V_VA);
    MyMessage msgParent(CHILD_PARENT, V_VA);
    MyMessage msgDistance(CHILD_DISTANCE, V_VA);
    MyMessage msgSleepTime(CHILD_SLEEPTIME, V_VA);
    
    void setup() {
    
      //Water Alarm
      pinMode(3, INPUT_PULLUP);
      attachInterrupt(Interrupt, Water, FALLING);
    
      //Battery measurement
      analogReference(INTERNAL); // use the 1.1 V internal reference
      sensorValue = analogRead(BATTERY_SENSE_PIN); // read once to activate the change of reference
    
      pinMode(GREEN, OUTPUT);
      pinMode(RED, OUTPUT);
      digitalWrite(GREEN, HIGH);
      digitalWrite(RED, HIGH);
      delay(200);
      digitalWrite(GREEN, LOW);
      digitalWrite(RED, LOW);
    
      SI.begin();
    }
    void presentation() {
      // Send the sketch version information to the gateway and Controller
      sendSketchInfo("Temp/Humidity/WaterLeak", "20180226");
      // Register all sensors to gateway (they will be created as child devices)
      present(CHILD_SIHUM, S_HUM, "SIHum");
      present(CHILD_SITEMP, S_TEMP, "SITemp");
      present(CHILD_SIDEW, S_TEMP, "SIDew");
      present(CHILD_BATT, S_MULTIMETER, "Volt");
      present(CHILD_BATTRES, S_MULTIMETER, "VoltRes");
    
      present(CHILD_WATER, S_WATER_LEAK, "Water Alarm");
      
      present(CHILD_FAILS, S_POWER, "Fails");
      present(CHILD_PARENT, S_POWER, "Parent");
      present(CHILD_DISTANCE, S_POWER, "Distance");  
      present(CHILD_SLEEPTIME, S_DIMMER, "SleepTime");
    }
    void loop() {
      //Voltage
      readVcc();
      sensorValue = analogRead(BATTERY_SENSE_PIN);
      BatteryResVolt  = sensorValue * 0.003363075;
      
      //SI read both temperature and humidity
      si7021_env SIdata = SI.getHumidityAndTemperature();
      
      //SI Humidity  
      SIHum = SIdata.humidityPercent;
      //Serial.print("SIHum=");
      //Serial.println(SIHum);
      if(SIHum >99)
      {
        SIHum = 99;
      }
      if(SIHum < 1)
      {
        SIHum = 0;
      }
      
      //SI Temperature
      SITemp = SIdata.celsiusHundredths / 100.0;
      SITemp = round(SITemp*10)/10.0;
      //Serial.print("SITemp=");
      //Serial.println(SITemp,1);
    
      //SI Dew
      double a = 17.271;
      double b = 237.7;
      double dewtemp = (a * SITemp) / (b + SITemp) + log(SIHum*0.01);
      SIDew = (b * dewtemp) / (a - dewtemp);
    
      //Get SleepTime from controller
      request(CHILD_SLEEPTIME, V_PERCENTAGE);
      wait(1000);
    
      //Water Alarm
      int WaterLeak = digitalRead(3);
      if (WaterLeak == 0){
        resend((msgWater.set(1)), 100);
      } 
      else{
        resend((msgWater.set(0)), 100);
      }
    
      //Send data to controller
      if ((OldBatteryVolt != BatteryVolt) | (BatteryVoltLoopCount >= 5))
      {
        send(msgBatt.set(BatteryVolt, 3));
        send(msgBattRes.set(BatteryResVolt, 3));
        OldBatteryVolt = BatteryVolt;
        BatteryVoltLoopCount = 0;
      }
        
      if ((OldSIHum != SIHum) | (OldSITemp != SITemp) | (OldSIDew != SIDew) | (SILoopCount >= 5))
      {
        resend((msgSIHum.set(SIHum)), 1);
        resend((msgSITemp.set(SITemp, 1)), 1);
        resend((msgSIDew.set(SIDew, 1)), 1);
        OldSIHum = SIHum;
        OldSITemp = SITemp;
        OldSIDew = SIDew;
        SILoopCount = 0;
      }
      
      if ((OldParentNode != _transportConfig.parentNodeId) | (ParentNodeLoopCount >= 10))
      {
        resend((msgParent.set(_transportConfig.parentNodeId)),1);
        OldParentNode = _transportConfig.parentNodeId;
        ParentNodeLoopCount = 0;
      }
        
      if ((OldDistanceNode != _transportConfig.distanceGW) | (DistanceLoopCount >= 10))
      {
        resend((msgDistance.set(_transportConfig.distanceGW)),1);
        OldDistanceNode = _transportConfig.distanceGW;
        DistanceLoopCount = 0;
      }
    
      if ((OldSleepTime != SleepTime) | (SleepTimeLoopCount >= 10))
      {
        resend((msgSleepTime.set(SleepTime,0)),10);
        OldSleepTime = SleepTime;
        SleepTimeLoopCount = 0;
      }
    
      if ((OldFails != Fails) | (FailsLoopCount >= 10))
      {
        failsend((msgFails.set(Fails)),1);
        OldFails = Fails;
        FailsLoopCount = 0;
      }
         
      BatteryVoltLoopCount++;
      SILoopCount++;
      ParentNodeLoopCount++;
      DistanceLoopCount++;
      SleepTimeLoopCount++;
      FailsLoopCount++;
    
      digitalWrite(GREEN, HIGH);
      delay(200);
      digitalWrite(GREEN, LOW);
      
      sleep(SleepTime*60000); //sleep a bit
    }
    void 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
      //batteryPcnt = (result - 1900) * 0.090909;
      BatteryVolt = result / 1000.000;
      //sendBatteryLevel(batteryPcnt);
      //Serial.print("battery volt:");
      //Serial.println(batteryVolt, 3);
      //Serial.print("battery percent:");
      //Serial.println(batteryPcnt);
    }
    void resend(MyMessage & msg, int repeats) {
      int repeat = 0;
      int repeatdelay = 0;
      boolean sendOK = false;
      while ((sendOK == false) and(repeat < repeats))
      {
        if (send(msg))
        {
          sendOK = true;
        }
        else
        {
          
          digitalWrite(RED, HIGH);
          delay(200);
          digitalWrite(RED, LOW);
          Fails++;
          sendOK = false;
          Serial.print("Error ");
          Serial.println(repeat);
          repeatdelay += 250;
          repeat++;
          sleep(repeatdelay);
        }
      }
    }
    
    void failsend(MyMessage &msg, int repeats) {
      int repeat = 0;
      int repeatdelay = 0;
      boolean sendOK = false;
    
      while ((sendOK == false) and (repeat < repeats)) {
        if (send(msg))
        {
          Fails = 0;
          sendOK = true;
        }
        else
        {
          Fails++;
          sendOK = false;
          Serial.print("Error ");
          Serial.println(repeat);
          repeatdelay += 250;
          repeat++;
          sleep(repeatdelay);
        }
      }
    }
    
    void receive(const MyMessage &message) {
      if (message.sender == 0) {
        if(message.type == V_PERCENTAGE) {
          //Serial.println( "V_PERCENTAGE command received..." );
          SleepTime = atoi(message.data);
          if ((SleepTime <= 0) | (SleepTime >= 700))
          {
            SleepTime = 30;
          }
          else
          {
            SleepTime = SleepTime / 6.6;
            //Serial.println(SleepTime);
            if (SleepTime < 1)
            {
              SleepTime = 1;  
            }
          }
          //Serial.println(SleepTime);
        }
      } 
    }
    
    void Water() {
      Serial.println("Water");
      resend((msgWater.set(1)), 1000);
      digitalWrite(GREEN, HIGH);
      delay(200);
      digitalWrite(GREEN, LOW);
    }
    

    0_1519677466024_20180226_193839617_iOS.jpg
    0_1519677539241_20180226_193922845_iOS.jpg



  • @flopp said in Water leak:

    Finally I made my water leak that I have been dreaming about for a long time now

    Sorry, I know this wasn't meant the way it was written, but at first quick read, I had to do a double take. I said to myself, who dreams about making their water leak...



  • @dbemowsk Plumber looking for work ?



  • @zboblamont said in Water leak sensor:

    Plumber looking for work ?

    NO, but I know some that wouldn't mind the work.



  • @flopp great setup! May I ask what controller you are using and how this works with getting the sleep time from the controller?



  • @helvetian
    Thanks.
    I am using Domoticz as Controller.
    After you first start-up of node you will get a Light device, change this device to Dimmer, then in Setup-Hardware-MySensorsSetup, select Node then select Child for SleepTime and disable Ack.


Log in to reply
 

Suggested Topics

  • 8
  • 3
  • 1
  • 1
  • 2
  • 2

27
Online

11.2k
Users

11.1k
Topics

112.5k
Posts