[SOLVED] Development branch: st=fails after node sleep



  • I decided to start with the development branch because of the improved support for the RFM69. I have one outside weather node running without problems for over a month now. My gateway is on 1.5 and my controller is Pimatic.

    My next node will be a wall switch with extra's. I want to make it super versatile and configurable in the same way as the MySensors settings in the 2.0 branch (that will show in the code I have so far...). It consists of 2 boards: one withe the radio and buttons mounted on a standard (in DE and NL) pulse switch, and one with the relays and a power supply. If you only use the mcu board it will be powered by a CR2032.

    That's my project in short, now the challenge:
    Slowly building up the sketch I now come to the sleeping part for when the node is battery powered. I used the code from a LowPowerLab forum user (bottom post on page 2) because at first I was unable to get the PCInt function working. Later I found I used a outdated version of the lib (2.19 in stead of 2.42).
    Without sleep the code loops through the updateChan() function. Works perfectly. ChanA is a momentary button and ChanB toggles. All the changes are sent to the controller like I want them to. Now enter "sleep": when I use sleep(0, FALLING, 0) , all I get after the node sleeps are st=fail:x. The node sleeps only after 5 seconds. In the time before sleeping it registers all changes well.

    Starting sensor (RRNNA-, 2.0.0-beta)
    Radio init successful.
    
    Reading config...
    
    Starting up...
    Start radio and sensors
    Send node info.
    send: 117-117-0-0 s=255,c=3,t=15,pt=0,l=2,sg=0,st=ok:
    send: 117-117-0-0 s=255,c=0,t=17,pt=0,l=10,sg=0,st=ok:2.0.0-beta
    send: 117-117-0-0 s=255,c=3,t=6,pt=1,l=1,sg=0,st=ok:0
    read: 0-0-117 s=255,c=3,t=6,pt=0,l=1,sg=0:M
    send: 117-117-0-0 s=255,c=3,t=11,pt=0,l=19,sg=0,st=ok:switchNode(battery)
    send: 117-117-0-0 s=255,c=3,t=12,pt=0,l=3,sg=0,st=ok:0.9
    send: 117-117-0-0 s=0,c=0,t=3,pt=0,l=0,sg=0,st=ok:
    send: 117-117-0-0 s=1,c=0,t=3,pt=0,l=0,sg=0,st=ok:
    Init complete, id=117, parent=0, distance=1
    Function 1
    Pressed
    send: 117-117-0-0 s=0,c=1,t=16,pt=1,l=1,sg=0,st=ok:1
    Function 1
    Released
    send: 117-117-0-0 s=0,c=1,t=16,pt=1,l=1,sg=0,st=ok:0
    Function 1
    Pressed
    send: 117-117-0-0 s=0,c=1,t=16,pt=1,l=1,sg=0,st=ok:1
    Function 1
    Released
    send: 117-117-0-0 s=0,c=1,t=16,pt=1,l=1,sg=0,st=ok:0
    Sleeping
    Function 1
    Pressed
    send: 117-117-0-0 s=0,c=1,t=16,pt=1,l=1,sg=0,st=fail:1
    Function 1
    Released
    send: 117-117-0-0 s=0,c=1,t=16,pt=1,l=1,sg=0,st=fail:0
    Sleeping
    

    If I use sleep(ms) the code fails to register the first button press while sleeping. Not exactly what you want in a light switch.

    Do I do something wrong? I also tried the LowPower.h library but that will not compile because of double declarations of enum period_t

    And finally: the code...

    /***************************************************************************
    **
    ** Light switch v1.0 with additional relay/power supply daughter board
    **
    ** Designed by D Hille. MySensors library by Henrik Ekblad. 
    **    Interrupt and debounce by 
    **
    ***************************************************************************/
    // Enable debug prints
    #define MY_DEBUG
    
    // Set serial baudrate
    #define MY_BAUD_RATE 57600
    
    // Enable and select radio type attached
    #define MY_RADIO_RFM69
    
    #define MY_NODE_ID 117
    
    /**************************************************************************/
    
    #define LED_FUNCTION 0
    // LED functions:
    // 0.: no LED present
    // 1.: ACK				(LED will flash briefly when ACk is received)
    // 2.: Notification			(LED wil diplay a function of the controller)
    
    #define NODE_CHAN_A_FUNCTION 1
    
    #define NODE_CHAN_B_FUNCTION 2
    
    // Node functions:
    // 0.: channel off
    // 1.: button only momentary  ("ON" while button pushed, "OFF" when released)
    // 2.: button only toggle     (every button push toggles state)
    
    /**************************************************************************/
    
    
    #include <SPI.h>
    #include <MySensor.h>
    #include <PinChangeInt.h>
    //#include "LowPower.h"
    
    #define buttApin  4  // Arduino Digital I/O pin number for buttons
    #define buttBpin  5
    #define LEDpin 9
    
    #define pulseMinimal 200
    #define bounceTime 10
    #define awakeTime 5000
    
    #define sketchName "switchNode(battery)"
    #define sketchVer "0.9" 
    
    #define ChanA 0
    #define ChanB 1
    #define ChanC 2
    #define ChanD 3
    
    int pinChanged = 255;
    bool loopRead;
    bool reqAck = false;
    bool stateLED = 0;
    
    unsigned long pulseTime = 0;
    static unsigned long lastInterruptTime = 0;
    
    int inputPin[4] = {0, 0, 0, 0};
    int function[4] = {0, 0, 0, 0};
    bool currLvl[4] = {1, 1, 1, 1};
    bool lastLvl[4] = {1, 1, 1, 1};
    bool debouncer[4] = {1, 1, 1, 1};
    bool outState[4] = {0, 0, 0, 0};
    unsigned long lastButtonPressed[4] = {0, 0, 0, 0};
    
    bool setDebug = false;
    bool startUp = true;
    
    bool noRFchanB = false;
    
    MyMessage msgButton(0, V_TRIPPED);
    MyMessage msgToggle(0, V_STATUS);
    MyMessage msgLED(LEDpin, V_LIGHT);
    
    #if (NODE_CHAN_A_FUNCTION == 0)
    #error Channel A cannot be turned off. For single channel use turn off channel B.
    #endif
    
    
    void setup()  
    {  
      #ifdef MY_DEBUG                //Differentiate between global debug including radio and local debug 
        setDebug = true;             //for the sketch alone.
      #endif
      
      if (setDebug){
        Serial.println("\nReading config...");
      }
      
      if (NODE_CHAN_B_FUNCTION == 0) {
        noRFchanB = true;
      }
      if (LED_FUNCTION == 1) {
        reqAck = true;
      }
      inputPin[ChanA] = buttApin;
      inputPin[ChanB] = buttBpin;
      
      function[ChanA] = NODE_CHAN_A_FUNCTION;
      function[ChanB] = NODE_CHAN_B_FUNCTION;
      
      if (setDebug) {
        Serial.println("\nStarting up...");
        Serial.println("Start radio and sensors");  
        Serial.println("Send node info.");
      }
      
      pinMode(inputPin[ChanA],INPUT_PULLUP);
      pinMode(inputPin[ChanB],INPUT_PULLUP);
      pinMode(LEDpin, OUTPUT);
      
      attachPinChangeInterrupt(inputPin[ChanA], ChanA_ISR, FALLING);
      attachPinChangeInterrupt(inputPin[ChanB], ChanB_ISR, FALLING);
    }
    
    
    void presentation()  
    {
      sendSketchInfo(sketchName, sketchVer);
    
      present(ChanA, S_BINARY);
    
      if (!noRFchanB) {
        present(ChanB, S_LIGHT);
      }
      
      if (LED_FUNCTION == 2) {
        present(LEDpin, S_LIGHT);
      }
      lastInterruptTime = millis();
    }
    
    
    void loop() 
    { 
      updateChan(pinChanged);
      sleepNow();
    }
    
    
    void sleepNow(void)
    {
     if (millis()-lastInterruptTime > awakeTime) {
       //delay (50);  
       Serial.println ("Sleeping");
       lastInterruptTime = millis();
       //delay (100);
       sleep(0, RISING, 0); 
     }
    }
    
     
    void receive(const MyMessage &message) 
    {
      if (message.isAck()) {
        flashLED();
      }
      
      if (message.type == V_LIGHT) 
      {
        if (message.sensor == LEDpin) {
          stateLED = message.getBool();
          changeNotification();
        }
      } 
    }
    
    
    void flashLED()
    {
      digitalWrite(LEDpin, HIGH);
      wait(50);
      digitalWrite(LEDpin, LOW);
    }
    
    
    void changeNotification()
    {
      
    }
    
    
    void ChanA_ISR()
    {
      pinChanged = ChanA;
      lastInterruptTime = millis();
    }
    
    
    void ChanB_ISR()
    {
      pinChanged = ChanB;
      lastInterruptTime = millis();
    }
    
      
    void updateChan(byte bttnNo)
    {
      currLvl[bttnNo] = digitalRead(inputPin[bttnNo]);
      unsigned long currTme = millis();
      if (currLvl[bttnNo] != lastLvl[bttnNo]) {
        lastButtonPressed[bttnNo] = currTme;
      }
      if (currTme - lastButtonPressed[bttnNo] > bounceTime) {
        if (currLvl[bttnNo] != debouncer[bttnNo]) {
          debouncer[bttnNo] = currLvl[bttnNo];
          if (function[bttnNo] == 1) {
            Serial.println("Function 1");
            if (currLvl[bttnNo] == LOW) {
              Serial.println("Pressed");
              send(msgButton.setSensor(bttnNo).set(true));      
            }
            else {
              Serial.println("Released");
              send(msgButton.setSensor(bttnNo).set(false));
            }
          }  
          if (function[bttnNo] >= 2)  {
            Serial.println("Function 2");
            if (currLvl[bttnNo] == LOW) {
              Serial.println("Toggle");
              outState[bttnNo] = !outState[bttnNo];
              send(msgToggle.setSensor(bttnNo).set(outState[bttnNo]), reqAck);
            }
          }
        }
      }
      lastLvl[bttnNo] = currLvl[bttnNo];
    }
    


  • Well, I DID do it wrong!
    Thanks to @Dirk_H in another topic I changed my call to sleep to sleep(0xff, 0x00, 0xff, 0x00, 0);, and presto, goin'....

    SOLVED!


  • Contest Winner

    Glad it helped David. I just thought about it again, maybe sleep(0xff, 0x00, 0) does work too. I did not test it but I think it calls the same function anyway.

    However the method of direct calling sleep(0xff, 0x00, 0xff, 0x00, 0) should save some clocks because one less jmp is required 🙂


Log in to reply
 

Suggested Topics

23
Online

11.2k
Users

11.1k
Topics

112.5k
Posts