gw.sleep on battery powered magnet door switch



  • Hi all,

    I have made a magnet door contact using a Arduino mini Pro 3v3 powered with 2 coin cells battery. To save battery life, I want to use gw.sleep to let the Arduino mini to sleep and trigger when the door is open.

    Unfortunately, the arduino is not trigger when contact is open or closed due to gw.sleep. I was wonder how to use the sleep comment and still making the debounce action works. I have tried to use INTERRUPT but with no luck.

    Thanks

    /**
     * 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.
     *
     *******************************
     *
     * DESCRIPTION
     *
     * Simple binary switch example 
     * Connect button or door/window reed switch between 
     * digitial I/O pin 3 (BUTTON_PIN below) and GND.
     * http://www.mysensors.org/build/binary
     */
    
    
    #include <MySensor.h>
    #include <SPI.h>
    #include <Bounce2.h>
    
    #define CHILD_ID 3
    #define BUTTON_PIN  3  // Arduino Digital I/O pin for button/reed switch
    #define INTERRUPT BUTTON_PIN -2 // Usually the interrupt = pin -2 (on uno/nano anyway)
    unsigned long SLEEP_TIME = 120000; // Sleep time between reports (in milliseconds)
    
    MySensor gw;
    Bounce debouncer = Bounce(); 
    int oldValue=-1;
    
    // Change to V_LIGHT if you use S_LIGHT in presentation below
    MyMessage msg(CHILD_ID,V_TRIPPED);
    
    void setup()  
    {  
      gw.begin();
    
     // 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);
      
      // 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.
      gw.present(CHILD_ID, S_DOOR);  
    }
    
    
    //  Check if digital input has changed and send in new value
    void loop() 
    {
      debouncer.update();
      // Get the update value
      int value = debouncer.read();
     
      if (value != oldValue) {
         // Send in the new value
         gw.send(msg.set(value==HIGH ? 1 : 0));
         oldValue = value;
      }
     
      gw.sleep(INTERRUPT,CHANGE, SLEEP_TIME);
      
      
    } 
    
    

  • Hardware Contributor

    @Chakkie - Looks right, Do you see anything in the serial debug log when you try?


  • Mod

    The code looks ok to me (except that you might as well set SLEEP_TIME to 0 since the loop only will report on change, regardless of the sleep time).
    Maybe add a few Serial.println statements in different parts of the loop so you can debug what happens?



  • @sundberg84

    I have added some print to debugged. It seems like the code with sleep does not verify and send the high 1 or low 0 when I open and close the contact. See the serial debug log. The repeated sleep in the log is when i open and close the contact. Normally it will send 1 or 0 " send: 204-204-0-0 s=3,c=1,t=16,pt=2,l=2,sg=0,st=ok:0"

    void loop() 
    {
      debouncer.update();
      // Get the update value
      int value = debouncer.read();
    
      if (value != oldValue) {
         // Send in the new value
         Serial.println("Trigger");
         gw.send(msg.set(value==HIGH ? 1 : 0));
         oldValue = value;
      }     
      gw.sleep(INTERRUPT,CHANGE, SLEEP_TIME);
      Serial.println("Sleep");
    
    send: 204-204-0-0 s=255,c=3,t=15,pt=2,l=2,sg=0,st=ok:0
    send: 204-204-0-0 s=255,c=0,t=17,pt=0,l=5,sg=0,st=ok:1.5.4
    send: 204-204-0-0 s=255,c=3,t=6,pt=1,l=1,sg=0,st=ok:0
    read: 0-0-204 s=255,c=3,t=6,pt=0,l=1,sg=0:M
    sensor started, id=204, parent=0, distance=1
    send: 204-204-0-0 s=3,c=0,t=0,pt=0,l=0,sg=0,st=ok:
    Trigger
    send: 204-204-0-0 s=3,c=1,t=16,pt=2,l=2,sg=0,st=ok:0
    Sleep
    Sleep
    Sleep
    Sleep
    Sleep
    Sleep
    Sleep
    Sleep
    


  • @mfalkvidd Hi thanks

    Changing the sleep time to 0 does not help. When I open and close the contact the status will not be sent. That's weird


  • Hardware Contributor

    @Chakkie - add a debugline and see what value and oldvalue says.
    See if you can measure the input when you close the contact and when its open so its not a hardware failure.


  • Hero Member

    @Chakkie debouncer does not function when you use the sleep function. Reason is that sleep puts the internal timer which is used by debouncer to rest. Remove the debouncer routine and debounce by including a gw.wait(40) before going to sleep. This avoids a retrigger by an eventual contact bounce.



  • @sundberg84 I have debugged a several times. I am now sure it is not a hardware failure.



  • @AWI Thank you so much. Yes I have came to the conclusion that the debouncer does not seems to work fine with sleep function. So I have used a method other than debouncer.

    Here the working script below:

    #include <MySensor.h>
    #include <SPI.h>
    
    
    #define CHILD_ID_Deur 11
    #define CHILD_ID_Post 12
    #define BUTTON_PIN_Deur  2  // Arduino Digital I/O pin for button/reed switch
    #define BUTTON_PIN_Post  3  // Arduino Digital I/O pin for button/reed switch
    
    MySensor gw;
    
    
    // Change to V_LIGHT if you use S_LIGHT in presentation below
    MyMessage msgDeur(CHILD_ID_Deur,V_TRIPPED);
    MyMessage msgPost(CHILD_ID_Post,V_TRIPPED);
    
    void setup()  
    {  
      gw.begin();
    gw.sendSketchInfo("Voordeur contacts", "1.0");
     // Setup the button
      pinMode(BUTTON_PIN_Deur,INPUT);
      pinMode(BUTTON_PIN_Post,INPUT);
      // Activate internal pull-up
      digitalWrite(BUTTON_PIN_Deur,HIGH);
      digitalWrite(BUTTON_PIN_Post,HIGH);
    
      // 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.
      gw.present(CHILD_ID_Deur, S_DOOR);
      gw.present(CHILD_ID_Post, S_DOOR);   
    }
    
    
    //  Check if digital input has changed and send in new value
    void loop() 
    {
      uint8_t value;
      static uint8_t sentValue = 2;
      static uint8_t sentValue2 = 2;
    
      // Short delay to allow buttons to properly settle
      gw.sleep(5);
    
      value = digitalRead(BUTTON_PIN_Deur);
    
      if (value != sentValue) {
        // Value has changed from last transmission, send the updated value
        gw.send(msgDeur.set(value == HIGH ? 1 : 0));
        sentValue = value;
      }
    
      value = digitalRead(BUTTON_PIN_Post);
    
      if (value != sentValue2) {
        // Value has changed from last transmission, send the updated value
        gw.send(msgPost.set(value == HIGH ? 1 : 0));
        sentValue2 = value;
      }
    
    
      // Sleep until something happens with the sensor
      gw.sleep(BUTTON_PIN_Deur - 2, CHANGE, BUTTON_PIN_Post - 2, CHANGE, 86400000);// changing Secondary button to correct pin (-3) does not work. So keep it on (-2)
      Serial.println("Sleep");
    
    }
    
    

    Notice that the script does not work properly when I set BUTTON_PIN_Post - 3. The button pin post will not trigger. But when I change it to -2, both switches will work

    gw.sleep(BUTTON_PIN_Deur - 2, CHANGE, BUTTON_PIN_Post - 2, CHANGE, 86400000);
    

  • Hero Member

    @Chakkie Good to hear. Using "-3" makes the interrupt number the same for _Deur and _Post. Using -2 activates both interrupt 0 and 1.
    You'r ready for the next project..


  • Mod

    We should really get rid of the confusing "- 2" stuff in the examples and start using DigtalPinToInterrupt instead.
    I'm annoyed enough to see if I can create a pull request later this week.



  • @AWI Thanks. By the way would you care to explain the interrupt index number? or may be a link for explanation?


  • Hero Member

    @Chakkie In a few words.. The ATMEGA has two external interrupts 0 and 1 which are connected to pins 2 and 3. ("-2" translates the pin number to the interrupt number, which is rather confusing as @mfalkvidd meant)



  • @mfalkvidd Thanks for the info. Does DigitalPinTolnterrupt works better?



  • @AWI Thanks this clear thinks up but at the same time also confusing too.

    So "-2" activates both 0 and 1 on pin 2 or pin 3 as you mentioned earlier. I always though it represents a pin number.


  • Hero Member

    @Chakkie The function digitalPinToInterrupt(pin) translates the pin number to the attached interrupt like "-2" does but in a reliable and more understandable way.



  • @AWI thanks. this looks like more promising.


  • Mod

    Pull request done for the development version: https://github.com/mysensors/Arduino/pull/441



  • I would like to build the same but I am still very confused now. Could you upload some pictures so I can make myself an image of how you wirde things together?

    Also I don´t really understand what happens here: gw.sleep(BUTTON_PIN_Deur - 2, CHANGE, BUTTON_PIN_Post - 2, CHANGE, 86400000);


  • Hero Member

    @siod If you are using a "standard" Atmega328 (pro-mini, etc.) don't make it hard for yourself. This processor has two external interrupts (0 & 1) connected to pins 2 & 3. Taking your line of code gw.sleep(BUTTON_PIN_Deur - 2, CHANGE, BUTTON_PIN_Post - 2, CHANGE, 86400000); the arguments are respectively:

    1. Use interrupt "0" (connected to pin 2 is BUTTON_PIN_Deur)
    2. Have is fired on change (i.e Rising and Falling)
    3. Use interrupt "1" (connected to pin 3 is BUTTON_PIN_Post)
    4. Have is fired on change (i.e Rising and Falling)
    5. Wake after every 86400000 ms (24 hrs) if no interrupt fired. To be safe you should use 86400000UL (the UL indicating that it is an Unsigned long type)


  • @AWI
    Ok thx for explanation, but that means he is using 2 reed switches, right (interrupt at pin2 and int pin3)?


  • Hero Member

    @siod I guess so. But don't ask me why. One should be sufficient to detect if the door is open 😄

    In addition (and for what it is worth). If you use a real low power circuit you can save around a factor 3 on battery lifetime when you get rid of the timed wakeup. The arduino sleeps a lot better when it doesn't have to look at the alarm clock every few ms 💤



  • @AWI
    yes, makes sense, but how should you do this wihout the wakeup ? I guess this is just the disadvantage one must accept...


  • Hero Member

    @siod The wakeup function can be disabled by setting the timer values to 0 (or omitting it). There is no purpose in the sketch above for what I can see. If you want to have a kind of "hey I am still alive"/heartbeat feature you need to do a little more (e.g. sending battery level)



  • @AWI I was going to ask about that.. I dont see any reason to wake up every 24 hours just to go back to sleep again.. I assume the radio doesn't have any reason to send a keepalive or anything? So, you can omit that number, and it will sleep until interrupted? That's cool..

    -Steve


  • Hero Member

    @172pilot yes, no reason to wake up. Especially if there is a regular wake-up from interrupt to let the controller know it it is alive



  • @AWI

    Thanks for the info. I thought you always have to add the sleep time to the gw.sleep. I will disable the a wake timer by removing the 86400000.

    @siod I use one switch for the letterbox and one for the door.



  • well, as you can see, if you don´t know the libraries exactly you accept things as they are or as they seem to be. I wasn´t aware that you can just set the wakeup function to 0. So this said I would like to thank you @AWI for your patience and your willingness of explaining also the most obvious things! 👍



  • The sketch works with both reeds switches (2 windows) but how to integreate it with DS18B20 temp sensor? I also power it with battery, so I would like to check the temp eg every 5min and if it is changed then send the new value to the controler. How to wake up arduino only if any window is opened or temp is changed (after 5 min)
    Thanks
    treb0r



  • @treb0r You can either wake up on the interrupt or on a time period:

    bool sleep(int interrupt, int mode, unsigned long ms=0);

    interrupt - Interrupt that should trigger the wakeup.
    mode - RISING, FALLING, CHANGE
    ms - Number of milliseconds to sleep (or 0 to sleep forever).

    The sleep method returns true if wake up was triggered by pin change and false means timer woke it up.



  • @treb0r the problem is, you need to wake up the arduino to tell the temp sensor to take a new reading, so the best you can do is to trigger on the interrupts for the Windows and then use the timer to wake up and take the temperature reading, and then you'll have to compare to your saved value to decide whether it has been 5 degrees or not, so you can't completely sleep until that happens..



  • Hi guys,

    unfortunately I have to answer again to this topic because I don´t get my nodes work longer then up to two weeks. I guess it is still a sleep function problem and the problem persits though I am usin ver 2.0 now. Please have a look at my code, any hint is very appreciated!!

    I have attached 2 reed switches which should trigger a wakeup and one Hum/Temp Sensor is attached, too. I would like the device to send temp/hum measurements every 15 minutes, what works, but only for a few days or so. Then I also send battery level, that´s all.

    I have 3 devices up and running right now, they all fail once in while...

    // Sensor Node Schlafzimmer mit HTU21D Temp/Hum Sensor, Fensterkontakte an Interrupt PINS Digital 5&6. Sleep Time 15 Minutwn, wake up wenn Fenster geöffnet/geschlossen wird.
    #define MY_RADIO_NRF24 //MySensor Library auf NRF24 Funkmodul einstellen, muss vor MySensor.h Initialisierung geschehen
    // Define Node ID
    #define MY_NODE_ID 200
    
    //Batterysensor
    int BATTERY_SENSE_PIN = A0;  // select the input pin for the battery sense point
    int oldBatteryPcnt = 0;
    #define CHILD_ID_BATT 7
    
    //Kontaktschalter
    //#include <Bounce2.h>
    #define CHILD1_ID 1 // Kontaktschalter 1
    #define CHILD2_ID 2 // Kontaktschalter 2
    #define BUTTON1_PIN  2  // Kontaktschalter 1
    #define BUTTON2_PIN  3  // Kontaktschalter 2
    int oldValueReed1=-1;
    int oldValueReed2=-1;
    
    //Tempsensor
    #include <SparkFunHTU21D.h>
    #include <Wire.h>
    #define CHILD_ID_HUM 3
    #define CHILD_ID_TEMP 4
    unsigned long SLEEP_TIME = 900000; // Sleep time between reads (in milliseconds)
    
    #include <MySensors.h>
    #include <SPI.h>
    
    //tempsensor
    HTU21D myHumidity;
    float lastTemp;
    float lastHum;
    //boolean metric = true; 
    
    //Messages
    //Battery
    MyMessage msgbatt(CHILD_ID_BATT,V_VOLTAGE);
    // Kontaktschalter
    MyMessage msgReed1(CHILD1_ID,V_TRIPPED); // Kontaktschalter 1
    MyMessage msgReed2(CHILD2_ID,V_TRIPPED); // Kontaktschalter 2
    //TempMessage
    MyMessage msgHum(CHILD_ID_HUM, V_HUM);
    MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
    
    //Presentation; present sensors to gateway!
    void presentation(){
      // Send the sketch version information to the gateway and Controller
      sendSketchInfo("Schlafzimmer Messstation", "2.0");
        
      // 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(CHILD1_ID, S_DOOR); 
      present(CHILD2_ID, S_DOOR); 
        
      //Tempsensor
      present(CHILD_ID_HUM, S_HUM);
      present(CHILD_ID_TEMP, S_TEMP); 
      //metric = getConfig().isMetric;
    
      //Battery
      present(CHILD_ID_BATT,V_VOLTAGE);
    }
    
    //Setup
    void setup()  
    {  
      //Serial.begin(9600);
      Serial.println("Hello!");
      //Batterysensor
         // use the 1.1 V internal reference
    #if defined(__AVR_ATmega2560__)
       analogReference(INTERNAL1V1);
    #else
       analogReference(INTERNAL);
    #endif
    
    //Tempsensor
      Serial.println("Setting up TempSensor...");
      myHumidity.begin();
      Serial.println("...done!");
    
    // Setup Kontaktschalter 1
      pinMode(BUTTON1_PIN,INPUT);
        // Activate internal pull-up
      digitalWrite(BUTTON1_PIN,HIGH);
    // Setup Kontaktschalter 2
      pinMode(BUTTON2_PIN,INPUT);
      // Activate internal pull-up
      digitalWrite(BUTTON2_PIN,HIGH);
    }
    
    //Starte den Loop
    void loop() 
    {
      //Batterysensor
      // get the battery Voltage
      delay(1000);
       int sensorValue = analogRead(BATTERY_SENSE_PIN);
       #ifdef DEBUG
       #endif
       
       // 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
       float batteryV  = sensorValue * 0.003363075;
       int batteryPcnt = sensorValue / 10;
    
       #ifdef DEBUG
       Serial.print("Battery Voltage: ");
       Serial.print(batteryV);
       Serial.println(" V");
    
       Serial.print("Battery percent: ");
       Serial.print(batteryPcnt);
       Serial.println(" %");
       #endif
    
       if (oldBatteryPcnt != batteryPcnt) {
         // Power up radio after sleep
         sendBatteryLevel(batteryPcnt);
         send(msgbatt.set(batteryPcnt));
         oldBatteryPcnt = batteryPcnt;
       }
       
      //Kontakstschalter 1
       // Short delay to allow buttons to properly settle
      sleep(10);
      // Get the update value
      int valueReed1 = digitalRead(BUTTON1_PIN);
     
      if (valueReed1 != oldValueReed1) {
         // Send in the new value
         send(msgReed1.set(valueReed1==HIGH ? 1 : 0));
         Serial.println("Button 1 geschaltet");
         oldValueReed1 = valueReed1;
      }
      //Kontakstschalter 2
      // Get the update value
      int valueReed2 = digitalRead(BUTTON2_PIN);
     
      if (valueReed2 != oldValueReed2) {
         // Send in the new value
         send(msgReed2.set(valueReed2==HIGH ? 1 : 0));
         Serial.println("Button 2 geschaltet");
         oldValueReed2 = valueReed2;
      }
     
     //Tempsensor
    Serial.println("Starte Messung...");
      
        float temp = myHumidity.readTemperature();
    
      if (isnan(temp)) {
          Serial.println("Failed reading temperature from DHT");
      } else if (temp != lastTemp) {
        lastTemp = temp;
        send(msgTemp.set(temp, 1));
        Serial.print("T: ");
        Serial.println(temp);
      }
      
     float humd = myHumidity.readHumidity();
      if (isnan(humd)) {
          Serial.println("Failed reading humidity from DHT");
      } else if (humd != lastHum) {
          lastHum = humd;
          send(msgHum.set(humd, 1));
          Serial.print("H: ");
          Serial.println(humd);
      }
    
     Serial.println("Sleep...");
     sleep(BUTTON1_PIN - 2, CHANGE, BUTTON2_PIN - 2, CHANGE, SLEEP_TIME); //sleep a bit 
      
    } 
    
    


  • @siod

    I'm assuming your batteries are empty when you say fail ?
    I built 5 of these last week for my dads place.
    I set internal pullups to LOW and soldered a 3,3MOhm resistor between VCC and Pin2.
    I'm seeing around 30µA when sleeping on two fresh AA batteries.
    With internal pullups that would be around 1ma and that would indeed drain the batteries quite fast.



  • no Sir, batteries are still at around 90% charged.



  • @siod , I had the same problem.
    I actually ordered a original NRF 24 mini and this seemed to solve some of my problems.
    i think another problem I'm having is that my batteries has a huge self discharge (old 3.7v 18650)

    On a side note.. I'm with @sling .
    Loose the pullups and set them LOW´.
    I have a 1MOhm resistor between VCC and PIN 2 and PIN 3 (also 2 switches).
    Using the pullup HIGH draws around 130uA versus LOW it draws between 7 to 10uA!



  • No gentlemen, I don´t think it is a battery problem, maybe a radio problem, but not a battery problem.

    But my sketch seems to be ok?


  • Hardware Contributor

    @Nicklas-Starkel said:

    @siod , I had the same problem.
    I actually ordered a original NRF 24 mini and this seemed to solve some of my problems.
    i think another problem I'm having is that my batteries has a huge self discharge (old 3.7v 18650)

    On a side note.. I'm with @sling .
    Loose the pullups and set them LOW´.
    I have a 1MOhm resistor between VCC and PIN 2 and PIN 3 (also 2 switches).
    Using the pullup HIGH draws around 130uA versus LOW it draws between 7 to 10uA!

    That's the best solution with a normal reed switch.
    But the best way is to use a "double" reed switch, with both normally opened and normally closed contacts. I use that connected between GND and pin 2 & 3 and set only the unconnected pin to high (so, with pullup). Current will flow only a very short time through the pullup while the node is waking up from sleep, then first thing I do is set connected input low. So nearly 100% of the time input is not connected and current through the reed switch is 0.
    I've put a test node on my entrance door, it's been running for over 3 months on a CR2032 cell and has lost only 0.02V meaning it will last at least 2 years, maybe 3.

    /**
     * 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.
     *
     *******************************
     *
     * DESCRIPTION
     *
     * Interrupt driven binary switch example with dual interrupts
     * Author: Patrick 'Anticimex' Fallberg
     * Connect one button or door/window reed switch between 
     * digitial 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
     * 
     * NCA78: Updated to work with one dual normally open/normally closed reed switch on both interrupt pins.
    
     */
    
    
    // Enable debug prints
    //#define MY_DEBUG 
    
    // Enable and select radio type attached
    #define MY_RADIO_NRF24
    
    #include <SPI.h>
    #include <MyConfig.h>
    #include <MySensors.h>
    #include <SystemStatus.h>
    #define SKETCH_NAME "NCA Door Sensor"
    #define SKETCH_MAJOR_VER "0"
    #define SKETCH_MINOR_VER "7"
    
    #define PRIMARY_CHILD_ID 3
    
    #define PRIMARY_BUTTON_PIN 2   // Arduino Digital I/O pin for button/reed switch
    #define SECONDARY_BUTTON_PIN 3 // Arduino Digital I/O pin for button/reed switch
    
    #if (PRIMARY_BUTTON_PIN < 2 || PRIMARY_BUTTON_PIN > 3)
    #error PRIMARY_BUTTON_PIN must be either 2 or 3 for interrupts to work
    #endif
    #if (SECONDARY_BUTTON_PIN < 2 || SECONDARY_BUTTON_PIN > 3)
    #error SECONDARY_BUTTON_PIN must be either 2 or 3 for interrupts to work
    #endif
    #if (PRIMARY_BUTTON_PIN == SECONDARY_BUTTON_PIN)
    #error PRIMARY_BUTTON_PIN and BUTTON_PIN2 cannot be the same
    #endif
    #if (PRIMARY_CHILD_ID == SECONDARY_CHILD_ID)
    #error PRIMARY_CHILD_ID and SECONDARY_CHILD_ID cannot be the same
    #endif
    
    #define MY_PARENT_NODE_ID 0
     
    
    // Change to V_LIGHT if you use S_LIGHT in presentation below
    MyMessage msg(PRIMARY_CHILD_ID, V_TRIPPED);
    //MyMessage msg2(SECONDARY_CHILD_ID, V_TRIPPED);
    
    
    // Parameters for VCC measurement
    const int VccMin        = 2000;  // Minimum expected Vcc level, in Volts. At 2V the cell should be dead
    const int VccMax        = 2900;  // Maximum expected Vcc level, in Volts.
    SystemStatus vcc();
    int LastBatteryPercent = 200; // so we are sure to send the battery level at first check
    bool isEven = false; // to check+send battery level only for each open+close cycles
    
    bool revertValue = false;  // to change this put a jumper on D4/D7 and it is tested at startup
    
    
    // This is the activated pin, on which the interrupt is set
    byte connectedPin = PRIMARY_BUTTON_PIN;
    byte connectedPinAtLastSending = 0; // Initialized at 0 so we will always send the first time
    
    void setup()  
    {  
      // First thing to do: change clock prescaling to 8 to change from 8MHz to 1MHz
      //  of course not necessary if you already have updated fuses and bootloader...
      #ifndef MY_DEBUG           // only if we are not in debug mode, so we can keep the fast baudrate in debug
        clock_prescale_set (clock_div_8);   
      #endif
    
      
      
    }
    
    void presentation() {
      sleep(250); // sleep to let capacitor recharge a bit
      // Send the sketch version information to the gateway and Controller
      sendSketchInfo(SKETCH_NAME, SKETCH_MAJOR_VER "." SKETCH_MINOR_VER);
      sleep(250); // sleep to let capacitor recharge a bit
      // Register binary input sensor to sensor_node (they will be created as child devices)
      present(PRIMARY_CHILD_ID, S_DOOR);
      sleep(250); // sleep to let capacitor recharge a bit
    }
    
    // Loop will iterate on changes on the BUTTON_PINs
    void loop() 
    {
      // Short delay to allow buttons to properly settle
      sleep(5);
    
      deActivatePin(PRIMARY_BUTTON_PIN);
      deActivatePin(SECONDARY_BUTTON_PIN);
    
      // Check if the previously connected pin is now connected. We do that because it's the most likely to be unconnected now
      //  so it's the best way not to lose any current
      byte newConnectedPin = GetNonConnectedPin();
      if (checkPinIsConnected(connectedPin)) {
        // If pin is still connected we set back the value to connected pin
        newConnectedPin = connectedPin;
        #ifdef MY_DEBUG
          Serial.println("Connected pin is connected !");
        #endif
        
      }
      connectedPin = newConnectedPin;
      // If connected pin is different that the one during the last sending of status, we send again
      #ifdef MY_DEBUG
        Serial.print("Connected pin = ");
        Serial.println(connectedPin);
        Serial.print("New Connected pin = ");
        Serial.println(newConnectedPin);
      #endif
      
      if (connectedPin != connectedPinAtLastSending) {
         // Value has changed from last transmission, send the updated value
         send(msg.set(connectedPin==PRIMARY_BUTTON_PIN ? (revertValue ? 0 : 1) : (revertValue ? 1 : 0)));
         connectedPinAtLastSending = connectedPin;
         isEven = !isEven;
      }
      
      if (isEven) {  // send only every two changes for a full open + close cycle
        int currentBatteryPercent = SystemStatus().getVCCPercent(VccMin, VccMax);
        if (currentBatteryPercent != LastBatteryPercent) {
            sleep(100); // sleep 100ms (+65ms wake up time) to let capacitor recharge a bit
            LastBatteryPercent = currentBatteryPercent;
            sendBatteryLevel(currentBatteryPercent);
        }
      }
    
      #ifdef MY_DEBUG
        Serial.print("Preparing to sleep, pin ");
        Serial.println(GetNonConnectedPin());
        wait(50);
      #endif
    
      // Activate the non connected pin before setting up interrupt
      activatePin(GetNonConnectedPin());    
      // Sleep until something happens with the door sensor
      sleep(GetNonConnectedPin()-2, CHANGE);
    } 
    
    void activatePin(byte pin) {
      // Set pin as input
      pinMode(pin, INPUT);
      // Activate internal pull up
      digitalWrite(pin, HIGH);
    }
    
    void deActivatePin(byte pin) {
      // Set back pin as output, low
      pinMode(pin, OUTPUT);
      digitalWrite(pin, LOW);
    }
    
    // Will check if pin is grounded (returns true) or not
    boolean checkPinIsConnected(byte pin) {
      activatePin(pin);
    
      // Read value
      byte valPin = digitalRead(pin);
      deActivatePin(pin);
    
      #ifdef MY_DEBUG
        Serial.print("checkPinIsConnected pin = ");
        Serial.print(pin);
        Serial.print(", value = ");
        Serial.println(valPin);
      #endif
      
      return valPin != HIGH;
    }
    
    // Returns the pin that is not connected
    byte GetNonConnectedPin() {
      return (connectedPin == PRIMARY_BUTTON_PIN) ? SECONDARY_BUTTON_PIN : PRIMARY_BUTTON_PIN;
    }
    
    

    https://www.aliexpress.com/item/20pcs-lot-3-pin-Reed-Switch-2-5X14MM-GLASS-Green-3-pin-Normally-Open-and-Normally/32507762756.html?spm=2114.13010608.0.0.4LJb9I



  • Ok guys you convinced me, I will set them LOW instead of HIGH.

    So now the reed switches are connected: GND | Reed Switch | PIN 2
    Doing it your way I must connect them: VCC | 1M Ohm Resistor | Reed Switch | PIN2

    Correct?

    I just did it the way described here: https://www.mysensors.org/build/binary
    There is nothing abaout any resistor...

    But will this solve my problem? I am not sure. I had the feeling that the sensors won´t wake up from sleep or so...


  • Hardware Contributor

    I would be interested too as I have some battery problems with my reed switches too. I guess its VCC | Reed Switch | GND and Reed Switch |1M Ohm Resistor | inputpin, right?



  • @siod and @LastSamurai
    Connect the REED Switch with one leg to GND and the other leg to PIN2.
    And then you put a 1MOhm resistor between VCC and PIN2.



  • @siod
    @Nicklas-Starkel said:

    put a 1MOhm resistor between VCC and PIN2.

    This is used as a pull-up resistor to keep the signal to PIN2 active HIGH until the reed switch is closed.

    I have never tested and don't know how much of a difference it would make, but you can do the reverse of that too and connect it like this:
    GND -- 1MOhm -- PIN2 -- Reed Switch -- VCC

    With this setup PIN2 would stay active LOW and in your code you would check to see if it goes HIGH for the switch contact. My thought is that doing it with the resistor to VCC from PIN2, which would be active HIGH, would use a slight bit more power than keeping it active LOW with the resistor from PIN2 to GND . As I said, I have never tested this, so I may be wrong.



  • @siod

    new observation: I have two temp nodes with red Htu21d in them. One keeps locking up randomly. Have to go outside and reset the arduino. I'll try another sensor today and see if it fixes things. Have completely rebuild the node twice now with new parts except the sensor.


Log in to reply
 

Suggested Topics

  • 8
  • 44
  • 1
  • 7
  • 3
  • 5

58
Online

11.4k
Users

11.1k
Topics

112.7k
Posts