Trying to get a dual mode sleep going.



  • Hello Everyone

    Im trying to get a dual sleep code going. My project is a monitor for my detached shed. It will be powered by either a 12 or 9 volt battery and the radio will have to be the higher powered NRF24 LNA/PNA (Its a good 200 yards from the house).
    I've managed to get the node base code working fine....reports the doors open/closed, sends back temp/humidity/battery percent.......but only when the door are opened or closed, which as you can imagine I don't sped a ton of time in the shed so its not that often.

    What I want to do is have the sensor wake under 2 conditions.....1 every hour or two to send temp/humidity and battery data back, and 2 when the doors are opened or closed (the kids have a habit of leaving the door open after getting their bikes).

    I could use a little help.

    
    /*
     * MySensors Custom Door/Window Sensor, with temperature sensor
     * and battery level reporting Version 2.2
     * 
     * D.B******* 7/13/2018
     * 
     * Version 1 - Initial concept code
     * Version 2 - adds Temp/humidity/ and battery monintoring
     * 
     * The Mysensors libraries will handle all the radio protocols 
     * and create the network.
     * 
     * DO NOT USE REPEATER MODE if this is battery powered
     * 
     * Connect one button or door/window reed switch between
     * digital I/O pin 3 (BUTTON_PIN below) and GND and the other
     * one in similar fashion on digital I/O pin 2.
     * This example is designed to fit Arduino Nano/Pro Mini
     */
    
     //Enble serial monitoring
     #define MY_DEBUG
    
     //Enable radio (Im using NRLF24A)
     #define MY_RADIO_NRF24
    
     // Set blinking period
    #define MY_DEFAULT_LED_BLINK_PERIOD 300
    
    // Inverses the behavior of leds
    #define MY_WITH_LEDS_BLINKING_INVERSE
    
    // Flash leds on rx/tx/err
    // Uncomment to override default HW configurations
    #define MY_DEFAULT_TX_LED_PIN 6  // tramsmit led pin
    
    #include <MyConfig.h>
    #include <MySensors.h>
    #include <DHT.h>
    #include <DHT_U.h>
    
    #define SKETCH_NAME "Shed Monitoring Sensor"
    #define SKETCH_VERSION "2.0"
    
    #define CHILD_ID_BATTERY 1
    #define CHILD_ID_HUMIDITY 2
    #define CHILD_ID_SENSOR1 3
    #define CHILD_ID_SENSOR2 4
    #define CHILD_ID_TEMPF 5
    #define CHILD_ID_TEMPC 6
    
    #define SENSOR1_PIN 2 //digital pin to connect sensors to.
    #define SENSOR2_PIN 3
    
    #define BATTERY_SENSE_PIN  A0  // select the input pin for the battery sense point
    
    #define DHT_PIN 4 //digital pin for the DHT sensor
    #define DHTTYPE 11
    
    #define SENSOR_TEMP_OFFSET 0 //allows for small corrections to sensor innacuracies
    
    unsigned long SLEEP_TIME = 300000; //600000 = 10 min, 300000 = 5 min - Sleep time in MilliSeconds
    
    // Sleep time between sensor updates (in milliseconds)
    // Must be >1000ms for DHT22 and >2000ms for DHT11
    static const uint64_t UPDATE_INTERVAL = 2100;
    // Force sending an update of the temperature after n sensor reads, so a controller showing the
    // timestamp of the last update doesn't show something like 3 hours in the unlikely case, that
    // the value didn't change since;
    // i.e. the sensor would force sending an update every UPDATE_INTERVAL*FORCE_UPDATE_N_READS [ms]
    static const uint8_t FORCE_UPDATE_N_READS = 10;
    
    float lastTempF;  //stores farenheit
    float lastTempC;
    float lastHum;
    uint8_t nNoUpdatesTempF;
    uint8_t nNoUpdatesHum;
    uint8_t nNoUpdatesTempC;
    
    #if (SENSOR1_PIN < 2 || SENSOR1_PIN > 3)
    #error SENSOR1_PIN must be either 2 or 3 for interrupts to work
    #endif
    #if (SENSOR2_PIN < 2 || SENSOR2_PIN > 3)
    #error SENSOR2_PIN must be either 2 or 3 for interrupts to work
    #endif
    #if (SENSOR1_PIN == SENSOR2_PIN)
    #error SENSOR1_PIN and SENSOR2_PIN2 cannot be the same
    #endif
    #if (CHILD_ID_SENSOR1 == CHILD_ID_SENSOR2)
    #error CHILD_ID_SENSOR1 and CHILD_ID_SENSOR2 cannot be the same
    #endif
    
    MyMessage msgBatt(CHILD_ID_BATTERY, V_VAR1);
    MyMessage msgHum(CHILD_ID_HUMIDITY, V_HUM);
    MyMessage msgSensor1(CHILD_ID_SENSOR1, V_TRIPPED);
    MyMessage msgSensor2(CHILD_ID_SENSOR2, V_TRIPPED);
    MyMessage msgTempF(CHILD_ID_TEMPF, V_TEMP);
    MyMessage msgTempC(CHILD_ID_TEMPC, V_TEMP);
    
    int oldBatteryPcnt = 0; //sets initial battery precentage to 0
    
    DHT dht(DHT_PIN, DHTTYPE);
    
    void setup() {
      dht.begin();
      batteryReference();
      pinMode(SENSOR1_PIN, INPUT_PULLUP);
      pinMode(SENSOR2_PIN, INPUT_PULLUP);  
    }
    
    void batteryReference(){
        // use the 1.1 V internal reference
    #if defined(__AVR_ATmega2560__)
        analogReference(INTERNAL1V1);
    #else
        analogReference(INTERNAL);
    #endif
    }
    
    void presentation(){
      sendSketchInfo(SKETCH_NAME, SKETCH_VERSION);
      present(CHILD_ID_BATTERY, S_CUSTOM);
      present(CHILD_ID_HUMIDITY, S_HUM);
      present(CHILD_ID_SENSOR1, S_DOOR);
      present(CHILD_ID_SENSOR2, S_DOOR);
      present(CHILD_ID_TEMPF, S_TEMP);
      present(CHILD_ID_TEMPC, S_TEMP);
    }
    
    void loop() {
     uint8_t value;
      static uint8_t sentValue=2;
      static uint8_t sentValue2=2;
    
      // Short delay to allow buttons to properly settle
      sleep(5);
    
      value = digitalRead(SENSOR1_PIN);
    
      if (value != sentValue) {
        // Value has changed from last transmission, send the updated value
        send(msgSensor1.set(value==HIGH));
        sentValue = value;
      }
    
      value = digitalRead(SENSOR2_PIN);
    
      if (value != sentValue2) {
        // Value has changed from last transmission, send the updated value
        send(msgSensor2.set(value==HIGH));
        sentValue2 = value;
      }
    
       float temperaturef = dht.readTemperature(true);
       float temperaturec = dht.readTemperature(false);
       float humidity = dht.readHumidity();
      if (isnan(temperaturef)) {
        Serial.println("Failed reading temperature from DHT!");
      } else if (temperaturef != lastTempF || nNoUpdatesTempF == FORCE_UPDATE_N_READS) {
        // Only send temperature if it changed since the last measurement or if we didn't send an update for n times
        lastTempF = temperaturef;
        nNoUpdatesTempF = 0;
        temperaturef += SENSOR_TEMP_OFFSET;
        send(msgTempF.set(temperaturef, 1)); 
    
        #ifdef MY_DEBUG
        Serial.print("Temp F: ");
        Serial.println(temperaturef);
        #endif
      } else {
        nNoUpdatesTempF++;
      }
    
       if (isnan(temperaturec)) {
        Serial.println("Failed reading temperature from DHT!");
      } else if (temperaturec != lastTempC || nNoUpdatesTempC == FORCE_UPDATE_N_READS) {
        // Only send temperature if it changed since the last measurement or if we didn't send an update for n times
        lastTempC = temperaturec;
        nNoUpdatesTempC = 0;
        temperaturec += SENSOR_TEMP_OFFSET;
        send(msgTempC.set(temperaturec, 1)); 
    
        #ifdef MY_DEBUG
        Serial.print("Temp C: ");
        Serial.println(temperaturec);
        #endif
      } else {
        nNoUpdatesTempC++;
      }
    
      if (isnan(humidity)) {
        Serial.println("Failed reading humidity from DHT");
      } else if (humidity != lastHum || nNoUpdatesHum == FORCE_UPDATE_N_READS) {
        // Only send humidity if it changed since the last measurement or if we didn't send an update for n times
        lastHum = humidity;
        // Reset no updates counter
        nNoUpdatesHum = 0;
        send(msgHum.set(humidity, 1));
    
        #ifdef MY_DEBUG
        Serial.print("Humidity: ");
        Serial.println(humidity);
        #endif
      } else {
        // Increase no update counter if the humidity stayed the same
        nNoUpdatesHum++;
      }
    
       int sensorValue = analogRead(BATTERY_SENSE_PIN);
      Serial.println(sensorValue);
      
      // 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
      // vout = (sensorvalue x 3.3) / 1023
      //vin = vout /  (R2/(R1+R2)); 
     
      float batteryV  = ( sensorValue * 0.003225806 ) / 0.3; // divide R2/(R1+R2)
      int batteryPcnt = sensorValue / 10 ;
      if ( batteryPcnt > 100 )
      batteryPcnt = 100;
      
      Serial.print("Battery Voltage: ");
      Serial.print(batteryV);
      Serial.println(" V");
      Serial.print("Battery percent: ");
      Serial.print(batteryPcnt);
      Serial.println(" %");
    
      if (oldBatteryPcnt != batteryPcnt)
      {
        // Power up radio after sleep
        send(msgBatt.set(batteryPcnt));
        oldBatteryPcnt = batteryPcnt;
      }
        // Sleep until something happens with the sensor
      sleep(SENSOR1_PIN-2, CHANGE, SENSOR2_PIN-2, CHANGE, 0); 
    }
    

    Ive tried adding the SLEEP_TIME into the sleep line, but when I put in in the door monitor becomes unresponsive.



  • Change this line......

    sleep(SENSOR1_PIN-2, CHANGE, SENSOR2_PIN-2, CHANGE, 0);

    to

    sleep(digitalPinToInterrupt (SENSOR1_PIN), CHANGE, digitalPinToInterrupt (SENSOR2_PIN), CHANGE, SLEEP_TIME);

    Make sure that status of battery/doors is saved and only sent if it changes, add the battery level send (or a heartbeat) in the main loop and you should be there.

    Depending on the controller you are using you could also look into using smartsleep as well, but for now this is perhaps more flexible for your needs.....



  • @skywatch

    Perfect - works like a charm.

    Thank you

    Dave



  • 🙂

    Happy to have helped! 😉


 

390
Online

7.6k
Users

8.5k
Topics

91.3k
Posts