Interupt not waking sensor



  • Hi

    For some reason the innterput is not waking my sensor, can you please see if you spot something in the sketch

    /**
     * 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
     * Version 1.1 - 2016-07-20: Converted to MySensors v2.0 and added various improvements - Torben Woltjen (mozzbozz)
     *
     * DESCRIPTION
     * This sketch provides an example of how to implement a humidity/temperature
     * sensor using a DHT11/DHT-22.
     *
     * For more information, please visit:
     * http://www.mysensors.org/build/humidity
     *
     */
    
    // Enable debug prints
    #define MY_DEBUG
    
    // Enable REPORT_BATTERY_LEVEL to measure battery level and send changes to gateway
    #define REPORT_BATTERY_LEVEL
    
    // Enable and select radio type attached
    #define MY_RADIO_RF24
    //#define MY_RADIO_RFM69
    //#define MY_RS485
    
    #include <SPI.h>
    #include <MySensors.h>
    #include <DHT.h>
    #include <Bounce2.h>
    
    // Set this to the pin you connected the DHT's data pin to
    #define DHT_DATA_PIN 4
    #define CHILD_ID 3
    #define BUTTON_PIN  3  // Arduino Digital I/O pin for button/reed switch
    
    // Set this offset if the sensor has a permanent small offset to the real temperatures.
    // In Celsius degrees (as measured by the device)
    #define SENSOR_TEMP_OFFSET 0
    
    // Sleep time between sensor updates (in milliseconds)
    // Must be >1000ms for DHT22 and >2000ms for DHT11
    static const uint64_t UPDATE_INTERVAL = 60000;
    
    // 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;
    
    #define CHILD_ID_HUM 0
    #define CHILD_ID_TEMP 1
    
    float lastTemp;
    float lastHum;
    uint8_t nNoUpdatesTemp;
    uint8_t nNoUpdatesHum;
    bool metric = true;
    
    MyMessage msgHum(CHILD_ID_HUM, V_HUM);
    MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
    DHT dht;
    
    Bounce debouncer = Bounce();
    int oldValue=-1;
    
    // Change to V_LIGHT if you use S_LIGHT in presentation below
    MyMessage msg(CHILD_ID,V_TRIPPED);
    
    #ifdef REPORT_BATTERY_LEVEL
    #include <Vcc.h>
    static uint8_t oldBatteryPcnt = 200;  // Initialize to 200 to assure first time value will be sent.
    const float VccMin        = 1.8;      // Minimum expected Vcc level, in Volts: Brownout at 1.8V    -> 0%
    const float VccMax        = 2.0*1.6;  // Maximum expected Vcc level, in Volts: 2xAA fresh Alkaline -> 100%
    const float VccCorrection = 1.0;      // Measured Vcc by multimeter divided by reported Vcc
    static Vcc vcc(VccCorrection);
    #endif
    
    void setup()
    {
      dht.setup(DHT_DATA_PIN); // set data pin of DHT sensor
      if (UPDATE_INTERVAL <= dht.getMinimumSamplingPeriod()) {
        Serial.println("Warning: UPDATE_INTERVAL is smaller than supported by the sensor!");
      }
      // Sleep for the time of the minimum sampling period to give the sensor time to power up
      // (otherwise, timeout errors might occure for the first reading)
      sleep(dht.getMinimumSamplingPeriod());
    
      // Setup the button
      pinMode(BUTTON_PIN,INPUT);
      // Activate internal pull-up
      digitalWrite(BUTTON_PIN,HIGH);
    
      // After setting up the button, setup debouncer
      debouncer.attach(BUTTON_PIN);
      debouncer.interval(5);
    }
    
    void presentation()
    {
      // Send the sketch version information to the gateway
      sendSketchInfo("DHT&Door", "1.1");
    
      // Register all sensors to gw (they will be created as child devices)
      present(CHILD_ID_HUM, S_HUM);
      present(CHILD_ID_TEMP, S_TEMP);
    
      metric = getControllerConfig().isMetric;
    
      // Register binary input sensor to gw (they will be created as child devices)
      // You can use S_DOOR, S_MOTION or S_LIGHT here depending on your usage.
      // If S_LIGHT is used, remember to update variable type you send in. See "msg" above.
      present(CHILD_ID, S_DOOR);
    }
    
    
    void loop()
    {
      // Force reading sensor, so it works also after sleep()
      dht.readSensor(true);
    
      // Get temperature from DHT library
      float temperature = dht.getTemperature();
      if (isnan(temperature)) {
        Serial.println("Failed reading temperature from DHT!");
      } else if (temperature != lastTemp || nNoUpdatesTemp == 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
        lastTemp = temperature;
    
        // apply the offset before converting to something different than Celsius degrees
        temperature += SENSOR_TEMP_OFFSET;
    
        if (!metric) {
          temperature = dht.toFahrenheit(temperature);
        }
        // Reset no updates counter
        nNoUpdatesTemp = 0;
        send(msgTemp.set(temperature, 1));
    
        #ifdef MY_DEBUG
          Serial.print("T: ");
          Serial.println(temperature);
        #endif
      } else {
        // Increase no update counter if the temperature stayed the same
        nNoUpdatesTemp++;
      }
    
      // Get humidity from DHT library
      float humidity = dht.getHumidity();
      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("H: ");
          Serial.println(humidity);
        #endif
      } else {
        // Increase no update counter if the humidity stayed the same
        nNoUpdatesHum++;
      }
    
       debouncer.update();
        // Get the update value
       int value = debouncer.read();
    
       if (value != oldValue) {
          // Send in the new value
          send(msg.set(value==HIGH ? 1 : 0));
          oldValue = value;
        }
    
      #ifdef REPORT_BATTERY_LEVEL
      const uint8_t batteryPcnt = static_cast<uint8_t>(0.5 + vcc.Read_Perc(VccMin, VccMax));
    
    #ifdef MY_DEBUG
      Serial.print(F("Vbat "));
      Serial.print(vcc.Read_Volts());
      Serial.print(F("\tPerc "));
      Serial.println(batteryPcnt);
    #endif
    
      // Battery readout should only go down. So report only when new value is smaller than previous one.
      if ( batteryPcnt < oldBatteryPcnt )
      {
          sendBatteryLevel(batteryPcnt);
          oldBatteryPcnt = batteryPcnt;
      }
    #endif
      // Sleep for a while to save energy
      sleep(UPDATE_INTERVAL);
    
    }
    

  • Mod

    @terence-faul the sketch you posted has no code to handle interrupts.



  • That would make alot of sense, sorry NOOB. I imagine then it is only reporting when the sensor wakes up from sleep.

    how do I go about including this. I was under the impression that this was automatic for pin 2 and 3


  • Mod

    @terence-faul use sleep(digitalPinToInterrupt(PIN), CHANGE, SLEEP_TIME);
    Example sketch that uses interrupt: https://www.mysensors.org/build/motion
    Documentation: https://www.mysensors.org/download/sensor_api_20#sleeping



  • so I have the intercuts working now, but when I activate the interrupt the sensor wakes up and reports everything except the reed switch. What am I missing, surly when the interput triggers the void loop runs from start to finnish again?

    If I remove the Interupt then the reed switch reports but only when the sensor wakes up

    /**
     * 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
     * Version 1.1 - 2016-07-20: Converted to MySensors v2.0 and added various improvements - Torben Woltjen (mozzbozz)
     *
     * DESCRIPTION
     * This sketch provides an example of how to implement a humidity/temperature
     * sensor using a DHT11/DHT-22.
     *
     * For more information, please visit:
     * http://www.mysensors.org/build/humidity
     *
     */
    
    // Enable debug prints
    #define MY_DEBUG
    
    // Enable REPORT_BATTERY_LEVEL to measure battery level and send changes to gateway
    #define REPORT_BATTERY_LEVEL
    
    // Enable and select radio type attached
    #define MY_RADIO_RF24
    //#define MY_RADIO_RFM69
    //#define MY_RS485
    
    #include <SPI.h>
    #include <MySensors.h>
    #include <DHT.h>
    #include <Bounce2.h>
    
    // Set this to the pin you connected the DHT's data pin to
    #define DHT_DATA_PIN 4
    #define CHILD_ID 3
    #define BUTTON_PIN  3  // Arduino Digital I/O pin for button/reed switch
    
    // Set this offset if the sensor has a permanent small offset to the real temperatures.
    // In Celsius degrees (as measured by the device)
    #define SENSOR_TEMP_OFFSET 0
    
    // Sleep time between sensor updates (in milliseconds)
    // Must be >1000ms for DHT22 and >2000ms for DHT11
    static const uint64_t UPDATE_INTERVAL = 60000;
    
    // 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;
    
    #define CHILD_ID_HUM 0
    #define CHILD_ID_TEMP 1
    
    float lastTemp;
    float lastHum;
    uint8_t nNoUpdatesTemp;
    uint8_t nNoUpdatesHum;
    bool metric = true;
    
    MyMessage msgHum(CHILD_ID_HUM, V_HUM);
    MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
    DHT dht;
    
    Bounce debouncer = Bounce();
    int oldValue=-1;
    
    // Change to V_LIGHT if you use S_LIGHT in presentation below
    MyMessage msg(CHILD_ID,V_TRIPPED);
    
    #ifdef REPORT_BATTERY_LEVEL
    #include <Vcc.h>
    static uint8_t oldBatteryPcnt = 200;  // Initialize to 200 to assure first time value will be sent.
    const float VccMin        = 1.8;      // Minimum expected Vcc level, in Volts: Brownout at 1.8V    -> 0%
    const float VccMax        = 2.0*1.6;  // Maximum expected Vcc level, in Volts: 2xAA fresh Alkaline -> 100%
    const float VccCorrection = 1.0;      // Measured Vcc by multimeter divided by reported Vcc
    static Vcc vcc(VccCorrection);
    #endif
    
    void setup()
    {
      dht.setup(DHT_DATA_PIN); // set data pin of DHT sensor
      if (UPDATE_INTERVAL <= dht.getMinimumSamplingPeriod()) {
        Serial.println("Warning: UPDATE_INTERVAL is smaller than supported by the sensor!");
      }
      // Sleep for the time of the minimum sampling period to give the sensor time to power up
      // (otherwise, timeout errors might occure for the first reading)
      sleep(dht.getMinimumSamplingPeriod());
    
      // Setup the button
      pinMode(BUTTON_PIN,INPUT);
      // Activate internal pull-up
      digitalWrite(BUTTON_PIN,HIGH);
    
      // After setting up the button, setup debouncer
      debouncer.attach(BUTTON_PIN);
      debouncer.interval(5);
    }
    
    void presentation()
    {
      // Send the sketch version information to the gateway
      sendSketchInfo("DHT&Door", "1.1");
    
      // Register all sensors to gw (they will be created as child devices)
      present(CHILD_ID_HUM, S_HUM);
      present(CHILD_ID_TEMP, S_TEMP);
    
      metric = getControllerConfig().isMetric;
    
      // Register binary input sensor to gw (they will be created as child devices)
      // You can use S_DOOR, S_MOTION or S_LIGHT here depending on your usage.
      // If S_LIGHT is used, remember to update variable type you send in. See "msg" above.
      present(CHILD_ID, S_DOOR);
    }
    
    
    void loop()
    {
      #ifdef REPORT_BATTERY_LEVEL
      const uint8_t batteryPcnt = static_cast<uint8_t>(0.5 + vcc.Read_Perc(VccMin, VccMax));
    
    #ifdef MY_DEBUG
      Serial.print(F("Vbat "));
      Serial.print(vcc.Read_Volts());
      Serial.print(F("\tPerc "));
      Serial.println(batteryPcnt);
    #endif
    
      // Battery readout should only go down. So report only when new value is smaller than previous one.
      if ( batteryPcnt < oldBatteryPcnt )
      {
          sendBatteryLevel(batteryPcnt);
          oldBatteryPcnt = batteryPcnt;
      }
    #endif
    
      // Force reading sensor, so it works also after sleep()
      dht.readSensor(true);
    
      // Get temperature from DHT library
      float temperature = dht.getTemperature();
      if (isnan(temperature)) {
        Serial.println("Failed reading temperature from DHT!");
      } else if (temperature != lastTemp || nNoUpdatesTemp == 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
        lastTemp = temperature;
    
        // apply the offset before converting to something different than Celsius degrees
        temperature += SENSOR_TEMP_OFFSET;
    
        if (!metric) {
          temperature = dht.toFahrenheit(temperature);
        }
        // Reset no updates counter
        nNoUpdatesTemp = 0;
        send(msgTemp.set(temperature, 1));
    
        #ifdef MY_DEBUG
          Serial.print("T: ");
          Serial.println(temperature);
        #endif
      } else {
        // Increase no update counter if the temperature stayed the same
        nNoUpdatesTemp++;
      }
    
      // Get humidity from DHT library
      float humidity = dht.getHumidity();
      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("H: ");
          Serial.println(humidity);
        #endif
      } else {
        // Increase no update counter if the humidity stayed the same
        nNoUpdatesHum++;
      }
    
       debouncer.update();
        // Get the update value
       int value = debouncer.read();
    
       if (value != oldValue) {
          // Send in the new value
          send(msg.set(value==HIGH ? 1 : 0));
          oldValue = value;
        }
    
      // Sleep until interrupt comes in on motion sensor. Send update every two minute.
      sleep(digitalPinToInterrupt(BUTTON_PIN), CHANGE, UPDATE_INTERVAL);
      // Sleep for a while to save energy
      //sleep(UPDATE_INTERVAL);
    
    }
    

    When I close the reed switch

    Vbat 3.35       Perc 100
    Failed reading temperature from DHT!
    Failed reading humidity from DHT
    4765 MCO:SLP:MS=60000,SMS=0,I1=1,M1=1,I2=255,M2=255
    4775 TSF:TDI:TSL
    4777 MCO:SLP:WUP=1
    4780 TSF:TRI:TSB
    Vbat 3.35       Perc 100
    4812 TSF:MSG:SEND,1-1-0-0,s=0,c=1,t=1,pt=7,l=5,sg=0,ft=0,st=OK:34.0
    H: 34.00
    4820 MCO:SLP:MS=60000,SMS=0,I1=1,M1=1,I2=255,M2=255
    4827 TSF:TDI:TSL
    4827 MCO:SLP:WUP=1
    4829 TSF:TRI:TSB
    Vbat 3.35       Perc 100
    
    4861 TSF:MSG:SEND,1-1-0-0,s=1,c=1,t=0,pt=7,l=5,sg=0,ft=0,st=OK:22.0
    T: 22.00
    4870 MCO:SLP:MS=60000,SMS=0,I1=1,M1=1,I2=255,M2=255
    4876 TSF:TDI:TSL
    4878 MCO:SLP:WUP=1
    4880 TSF:TRI:TSB
    Vbat 3.35       Perc 100
    4911 MCO:SLP:MS=60000,SMS=0,I1=1,M1=1,I2=255,M2=255
    4915 TSF:TDI:TSL
    4917 MCO:SLP:WUP=1
    4919 TSF:TRI:TSB
    Vbat 3.35       Perc 100
    4950 MCO:SLP:MS=60000,SMS=0,I1=1,M1=1,I2=255,M2=255
    4956 TSF:TDI:TSL```

  • Mod

    @terence-faul MCO:SLP:WUP=1 indicates that the node woke up by interrupt 1, which is pin 3 on atmega328. So if you are using an Arduino based on atmega328, that part looks good.

    For how long is the reed switch closed? Maybe the reed switch is open again when debouncer update is called?
    You could check the value by adding this

       // Get the update value
       int value = debouncer.read();
       Serial.println(value);
    


  • @mfalkvidd said in Interupt not waking sensor:

    Serial.println(value);

    It looks as if the Interupt is waking the sensor correctly, but not changing the value.
    If I wait for UPDATE_INTERVAL to expire though then the value is updated?

    when the Interupt is called does that invoke the loop from the beginning?
    What do you think?

    0
    6565 MCO:SLP:MS=60000,SMS=0,I1=1,M1=1,I2=255,M2=255
    6572 TSF:TDI:TSL
    6574 MCO:SLP:WUP=1
    6576 TSF:TRI:TSB
    Vbat 3.36       Perc 100
    0
    6658 MCO:SLP:MS=60000,SMS=0,I1=1,M1=1,I2=255,M2=255
    6662 TSF:TDI:TSL
    6664 MCO:SLP:WUP=1
    6666 TSF:TRI:TSB
    Vbat 3.35       Perc 100
    0
    6748 MCO:SLP:MS=60000,SMS=0,I1=1,M1=1,I2=255,M2=255
    6752 TSF:TDI:TSL
    
    6754 MCO:SLP:WUP=1
    6756 TSF:TRI:TSB
    Vbat 3.36       Perc 100
    6789 TSF:MSG:SEND,1-1-0-0,s=1,c=1,t=0,pt=7,l=5,sg=0,ft=0,st=OK:22.0
    T: 22.00
    0
    6848 MCO:SLP:MS=60000,SMS=0,I1=1,M1=1,I2=255,M2=255
    6852 TSF:TDI:TSL```


  • Is it possible the reed switch is causing a wake up, but not detecting a change in the state of the reed switch and that is why the value is not changing?


  • Mod

    @terence-faul when sleep returns, code execution will continue on the line after sleep.
    Since sleep is at the end of loop() in your sketch, loop() will be exited and then called again from the start.
    The DHT readings take some time (in your case it seems to take 6848 - 6754 = 94 milliseconds. Then the debouncer is updated (debouncer.update()). If the reed switch has opened again before the debouncer is updated, debouncer will read the reed switch as open.

    Moving debouncer.update() to right after sleep will avoid the delay caused by DHT reading and should catch the reed switch before it has time to open again.


  • Hardware Contributor

    @terence-faul said in Interupt not waking sensor:

    when the Interupt is called does that invoke the loop from the beginning?```

    No, it resumes. But in your case, as sleep is your last function in Loop(), loop is relaunched.

    I just quick looked at your code (no time).
    Have you tried to remove others sensors code, and run a reedswitch only code.
    It should be the first step in your debugging. Better do step by step to check what's the culprit.
    If your reedswitch code is working ok, if there is any interference with other sensors/libraries, the logic order/algo etc.

    Are you using sleep() for saving energy (so a batt powered device)?? then imho I would have choosen a better sensor. I don't get why people still uses these dht..
    Eg. cheap si7021, Bosch BMEs : better power consumption, voltage range.

    DHT libs has lot of delays, yuk!
    eg. minimum 10ms just for a read start signal (more for the complete reading), imho it needs refactoring to be used in non blocking way.

    So, you can:

    • disable your DHT code and try reedswitch code only.
    • if it works. then you have a problem with 1) your code logics 2) external lib (but imho it's a bad sensor choice)
    • Check 1) by maybe changing a bit your code logics(order of functions calls like testing your reedswith right after your sleep call).
    • if it doesn't fix, rewrite sensor lib in non blocking way to be used with your sketch
    • if you don't feel enough good for rewriting lib, then change sensor brand/model, and you may fix this problem 😉

    As a rule of thumb, libs are not all well optimized even if their examples works, but sometimes it needs tinkering so it can work in larger projects like a mysensors multisensors sketch.
    So before using a lib, I often check&fix if there are any delays/loops/blocking stuff and others details which could bring some problems and slow down my dev.

    Edit: ahah I didn't notice, you beat me @mfalkvidd 🙂


 

161
Online

8.7k
Users

9.5k
Topics

99.9k
Posts