Skip to content
  • MySensors
  • OpenHardware.io
  • Categories
  • Recent
  • Tags
  • Popular
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Brand Logo
  1. Home
  2. Troubleshooting
  3. Pin change interrupt not firing with MySensors

Pin change interrupt not firing with MySensors

Scheduled Pinned Locked Moved Troubleshooting
39 Posts 7 Posters 11.3k Views 5 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • D Offline
    D Offline
    DavidZH
    wrote on last edited by
    #26

    So I've returned to this thread after 2 months, as I finally found the time to test the workaround @Yveaux suggested on Januari 8th. In the mean time I had updated my library to the latest version (2.1.1).
    When I run my sketch now, it never goes to sleep. Actually it does, but wakes up immediately. I use int testInt = sleep(0xff, 0x00, 0xff, 0x00, 0);, testInt returns -1, as in; MCU woke by timer. That is both with and without the workaround, and I am not sure that it's caused by the interrupt definitions. Up to 2.0 that worked fine (I rolled back yesterday to try).

    Now I found this other thread where @tekka stated that he corrected some stuff that as out of line with the datasheet for the 328(p).

    So what would be the correct way to make a node sleep forever without using the ExternalInterrupts (INT_0 and INT_1)? I am in no rush to get this going, because my first nodes are going to be mains powered, so they will be happily looping along without sleeping. But as this node has 4 buttons, PinChange is a route I'd like to go.

    (Now I have to go and retract my statements in another thread, because they are null and void now.)

    tekkaT 1 Reply Last reply
    1
    • D DavidZH

      So I've returned to this thread after 2 months, as I finally found the time to test the workaround @Yveaux suggested on Januari 8th. In the mean time I had updated my library to the latest version (2.1.1).
      When I run my sketch now, it never goes to sleep. Actually it does, but wakes up immediately. I use int testInt = sleep(0xff, 0x00, 0xff, 0x00, 0);, testInt returns -1, as in; MCU woke by timer. That is both with and without the workaround, and I am not sure that it's caused by the interrupt definitions. Up to 2.0 that worked fine (I rolled back yesterday to try).

      Now I found this other thread where @tekka stated that he corrected some stuff that as out of line with the datasheet for the 328(p).

      So what would be the correct way to make a node sleep forever without using the ExternalInterrupts (INT_0 and INT_1)? I am in no rush to get this going, because my first nodes are going to be mains powered, so they will be happily looping along without sleeping. But as this node has 4 buttons, PinChange is a route I'd like to go.

      (Now I have to go and retract my statements in another thread, because they are null and void now.)

      tekkaT Offline
      tekkaT Offline
      tekka
      Admin
      wrote on last edited by tekka
      #27

      @DavidZH Can you post your sketch & full debug log?

      1 Reply Last reply
      0
      • D Offline
        D Offline
        DavidZH
        wrote on last edited by DavidZH
        #28

        Sure!

        ***************************************************************************
        **
        ** Light switch v1.0 with additional relay/power supply daughter board
        **
        ** Scraped together by D Hille. MySensors library by Henrik Ekblad et al.
        **    Button lib.:              github.com/JChristensen/Button
        **    PinChangeInterrupt lib.:  github.com/NicoHood/PinChangeInterrupt
        **    FastLED lib.:             github.com/FastLED
        **
        ***************************************************************************/
        //                    MySensors definitions
        
        #define MY_DEBUG                 // Comment out after finishing sketch (saves over 6kB flash)
        //#define MY_DEBUG_VERBOSE_SIGNING // Comment out when no signing is used or when everything is OK
        
        #define MY_BAUD_RATE 57600       // Lower as max because of 8 MHz Arduino
        
        #define MY_RADIO_RFM69
        #define MY_IS_RFM69HW
        
        #define MY_NODE_ID 85            // Delete to use automatic ID assignment
        
        #define MY_TRANSPORT_WAIT_READY_MS 100 //Start the node even if no connection to the GW could be made
        //#define MY_TRANSPORT_STATE_RETRIES 1
        //#define MY_TRANSPORT_MAX_TSM_FAILURES    (2u)                 //Uncomment these three when usung battery powered node
        //#define MY_TRANSPORT_TIMEOUT_EXT_FAILURE_STATE (5*60*1000ul)
        
        
        /**************************************************************************/
        //                        Security
        /**************************************************************************/
        
        //#define MY_SIGNING_SOFT
        //#define MY_SIGNING_SOFT_RANDOMSEED_PIN 7
        //#define MY_SIGNING_REQUEST_SIGNATURES
        
        //#define MY_RFM69_ENABLE_ENCRYPTION
        
        
        /**************************************************************************/
        //                    Switch definitions
        /**************************************************************************/
        
        #define BATTERY_POWERED
        #define battUpdater 50            // Number of TX actions to count before a new battery status update is sent.
        
        #define LED_FUNCTION 2
        // LED functions:
        // 0.: no LED present
        // 1.: ACK                        (LED will flash briefly when ACK is received)
        // 2.: Notification               (RGB-LED wil display a function of the controller, or flash white when ACK is received)
        
        #define NODE_CHAN_A_FUNCTION 1
        
        #define NODE_CHAN_B_FUNCTION 3
        
        #define NODE_CHAN_C_FUNCTION 0
        
        #define NODE_CHAN_D_FUNCTION 0
        // 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)
        // 3.: normal                    (relay controlled via RF and local)
        // 4.: local relay               (no RF control, only button)
        
        //#define SAFETY_BUTTON_A          // When defined button needs to be pressed for a set time to activate the button.
        //#define SAFETY_BUTTON_B          // Comment out to deactivate.
        //#define SAFETY_BUTTON_C
        //#define SAFETY_BUTTON_D        
        
        #define SAFETY_PRESS_TIME 1      // time in seconds the button needs to be pressed.
        
        
        /**************************************************************************/
        //                  Debug and interrupt definitions
        /**************************************************************************/
        
        #define LOCAL_DEBUG                              // Comment out to switch all debug messages off (saves 1kb flash)
        
        /*#ifdef MY_DEBUG                                  // Differentiate between global debug including radio and local debug 
          #define LOCAL_DEBUG                            // for the sketch alone.
        #endif*/
        
        #ifdef LOCAL_DEBUG 
          #define Sprint(a) (Serial.print(a))            // Macro as substitute for serial debug. Will be an empty macro when
          #define Sprintln(a) (Serial.println(a))        // debug is switched off
        #else
          #define Sprint(a)                                       
          #define Sprintln(a)
        #endif
        
        #define EI_NOTEXTERNAL
        #define EI_NOTPORTB
        #define EI_NOTPORTD
        #define EI_ARDUINO_INTERRUPTED_PIN
        
        
        /**************************************************************************/
        
        #include <Button.h>
        #include <EnableInterrupt.h>
        #include <MySensors.h>
        #include <FastLED.h>
        #include <Vcc.h>
        
        
        #define BMEaddr 0x76
        #define Max44099Addr 0x4A
        #define sketchName "switchNode(Hal)"
        #define sketchVer "1.0" 
        
        #define buttApin  14              // Arduino Digital I/O pin numbers for connected buttons 
        #define buttBpin  15              // when connected to '`official' PCB.
        #define buttCpin  8
        #define buttDpin  9
        
        #define relayApin 16
        #define relayBpin 17
        
        #define LEDpinACK 5
        #define LEDpinWS 6
        #define WS_Power 9
        
        #define ChanA 0
        #define ChanB 1
        #define ChanC 2
        #define ChanD 3
                                  
        #define PULLUP true        
        #define INVERT true        
        #define bounceTime 20             // A debounce time of 20 milliseconds usually works well for tactile button switches.
        #define sleepWait 2000           // Time to wait in ms before node sleeps (to be able to receive notification messages).
        
        volatile int pinChanged = 255;
        int indexButton = 255;
        int currDim = 255;                // Bright value of notificator at startup.
        int newDim = 0;
        int currLED = 30;                 // Hue value of notificator at startup.
        int newLED = 0;
        bool buttonPressed = false;
        bool changeLED = false;
        bool flashLED = false;
        int flashNumber = 1;
        bool flashWait = false;
        bool dimLED = false;
        bool flashOn = false;
        
        bool battPower = true;
        int inputPin[5] = {0, 0, 0, 0, 0};          // State machine registers
        int actuatorPin[2] = {0, 0};
        int function[4] = {0, 0, 0, 0};
        bool safetyBttn[4] = {0, 0, 0, 0};
        bool reqAck[4] = {0, 0, 0, 0};
        bool inState[5] = {0, 0, 0, 0, 0};
        bool longPr[5] = {0, 0, 0, 0, 0};
        bool outState[4] = {0, 0, 0, 0};
        bool longPress = false;
        
        unsigned long lastTimeButton;               // Timer registers
        unsigned long flashTime;
        unsigned long lightsOut;
        unsigned long buttonTime;
        unsigned long longPressTime;
        
        bool startUp = true;
        bool transportDown = false;
        bool metric = true; 
        
        int battStatCounter = 0;
        const float VccMin = 0.0;                   // Minimum expected Vcc level, in Volts.
        const float VccMax = 5.0;                   // Maximum expected Vcc level, in Volts.
        const float VccCorrection = 3.41/3.35;      // Measured Vcc by multimeter divided by reported Vcc
        
        
        /**************************************************************************/
        //                  Library declarations
        /**************************************************************************/
        
        Button BtnA(buttApin, PULLUP, INVERT, bounceTime);    
        Button BtnB(buttBpin, PULLUP, INVERT, bounceTime);
        Button BtnC(buttCpin, PULLUP, INVERT, bounceTime);
        Button BtnD(buttDpin, PULLUP, INVERT, bounceTime);
        
        CRGB notifier[1];                           // define notification LED
        
        MyMessage msgButton(0, V_TRIPPED);
        MyMessage msgToggle(0, V_STATUS);
        MyMessage msgLED(LEDpinWS, V_RGB);
        
        Vcc vcc(VccCorrection);
        
        
        /**************************************************************************/
        //                  Error messages
        /**************************************************************************/
        
        #if (NODE_CHAN_A_FUNCTION == 0)
        #error Channel A cannot be turned off. For single channel use turn off channel B.
        #endif
        #if (NODE_CHAN_C_FUNCTION >= 3 || NODE_CHAN_D_FUNCTION >= 3)
        #error Channels C and D do not have relays attached, can only be used as buttons.
        #endif
        
        
        /**************************************************************************/
        
        void before(void)
        {
          Sprintln("\nStarting up...");
          Sprintln("\nReading config...");
            
        //                  Fill state machine registers
        
          inputPin[ChanA] = buttApin;
          #ifdef SAFETY_BUTTON_A
            safetyBttn[ChanA] = true;
          #endif
          function[ChanA] = NODE_CHAN_A_FUNCTION;
          enableInterrupt(inputPin[ChanA], ChanA_ISR, CHANGE);
          if (function[ChanA] <= 2 && LED_FUNCTION >= 1) {
            reqAck[ChanA] = true;
          }
          else {
            actuatorPin[ChanA] = relayApin;
          }
            
          if (NODE_CHAN_B_FUNCTION >= 1) {
            inputPin[ChanB] = buttBpin;
            #ifdef SAFETY_BUTTON_B
              safetyBttn[ChanB] = true;
            #endif
            function[ChanB] = NODE_CHAN_B_FUNCTION;
            enableInterrupt(inputPin[ChanB], ChanB_ISR, CHANGE);
            if (function[ChanB] <= 2 && LED_FUNCTION >= 1) {
              reqAck[ChanB] = true;
            }
            else {
              actuatorPin[ChanB] = relayBpin;
            }
          }
          
          if (NODE_CHAN_C_FUNCTION >= 1) {
            inputPin[ChanC] = buttCpin;
            #ifdef SAFETY_BUTTON_C
              safetyBttn[ChanC] = true;
            #endif
            function[ChanC] = NODE_CHAN_C_FUNCTION;
            enableInterrupt(inputPin[ChanC], ChanC_ISR, CHANGE);
            if (function[ChanC] <= 2 && LED_FUNCTION >= 1) {
              reqAck[ChanC] = true;
            }    
          }
          
          if (NODE_CHAN_D_FUNCTION >= 1) {
            inputPin[ChanD] = buttDpin;
            #ifdef SAFETY_BUTTON_D
              safetyBttn[ChanD] = true;
            #endif
            function[ChanD] = NODE_CHAN_D_FUNCTION;
            enableInterrupt(inputPin[ChanD], ChanD_ISR, CHANGE);
            if (function[ChanD] <= 2 && LED_FUNCTION >= 1) {
              reqAck[ChanD] = true;
            }
          }
        
          longPressTime = SAFETY_PRESS_TIME * 1000;
        }
        
        
        /**************************************************************************/
        
        void presentation()  
        {
          Sprintln("Start radio and sensors");  
          Sprintln("Send node info. \n");
          
          sendSketchInfo(sketchName, sketchVer);
          
          for (int i = ChanA; i < ChanD+1; i++) {
            Sprint("\nPresent channel "); Sprint(i); Sprint(", function: "); Sprint(function[i]); Sprint(", safety: "); Sprintln(safetyBttn[i]);
            if (function[i] == 1) {
              present(i, S_BINARY);
            }
            else if (function[i] >= 2) { 
              present(i, S_LIGHT);
            }
          }
        
          if (LED_FUNCTION == 2) {
            Sprintln("\nPresent notifier.");   
            present(LEDpinWS, S_RGB_LIGHT);
          }
        
          synchronizeChannels();
        }
        
        
        /**************************************************************************/
        
        void setup(void)
        {  
          #ifndef BATTERY_POWERED
            battPower = false;
          #endif
        
          pinMode(LEDpinACK, OUTPUT);
        
          if (LED_FUNCTION == 2) {
            pinMode(WS_Power, OUTPUT);
            digitalWrite(WS_Power, HIGH);    
            FastLED.addLeds<WS2812B, LEDpinWS, GRB>(notifier, 1);
            wait(30);
            notifier[0] = CHSV(currLED, 255, currDim);    // give LED initial color
            FastLED.show();
          }
        
          if (function[ChanA] >= 3) {
            pinMode(actuatorPin[ChanA], OUTPUT);
          }
          if (function[ChanB] >= 3) {
            pinMode(actuatorPin[ChanB], OUTPUT);
          }
          
          Sprintln("\nDone. \nStarting program.");
          lastTimeButton = millis();
        
          checkTransportStatus();
        }
        
        
        /**************************************************************************/
        
        
        void loop(void)
        {
          if (indexButton <= 25) {                          // Measure time when safety feature is enabled.
            if (millis() >= buttonTime + longPressTime) {
              Sprint("\nChannel "); Sprint(indexButton); Sprintln(" long-pressed");
              flashLED = true;
              pinChanged = indexButton;
              longPr[indexButton] = true;
              indexButton = 255;
              wait(30);
            }
          }  
        
          //if (buttonPressed) {
          //  readInputs();
          //}
          
          switch (function[pinChanged]) {
            case 1:
              Sprint("\nChannel "); Sprint(pinChanged);       
              if (inState[pinChanged] && !buttonPressed) {
                Sprintln(" pressed.");
                if ((!safetyBttn[pinChanged]) || (longPr[pinChanged])){
                  if (!transportDown) {
                    send(msgButton.setSensor(pinChanged).set(true));
                  }
                }
                else {
                  indexButton = pinChanged;
                  buttonTime = millis();
                }
                pinChanged = 255;
                //buttonPressed = true;
                wait(30);
                break;
              }
              else if (!inState[pinChanged]) {
                lastTimeButton = millis();
                Sprintln(" released.");
                if ((!safetyBttn[pinChanged]) || (longPr[pinChanged])) {
                  if (!transportDown) {
                    send(msgButton.setSensor(pinChanged).set(false),reqAck[pinChanged]);
                  }
                  else {
                    flashLED = true;
                    flashNumber = 3;
                  }
                }
                longPr[pinChanged] = false;
                indexButton = 255;
                pinChanged = 255;
                wait(30);
                battStatCounter++;
              }
              break;
            case 2:
            case 3:
            case 4:
              lastTimeButton = millis();
              if (inState[pinChanged]) {
                if ((!safetyBttn[pinChanged]) || (longPr[pinChanged])) {
                  Sprint("\nChannel "); Sprint(pinChanged); Sprint(" toggled");
                  outState[pinChanged] = !outState[pinChanged]; 
                  if (function[pinChanged] >= 3) {
                    digitalWrite(actuatorPin[pinChanged], outState[pinChanged]);
                    Sprint(", relay changed");
                  }
                  if (function[pinChanged] == 2 || function[pinChanged] == 3) {
                    if (!transportDown) {
                      send(msgToggle.setSensor(pinChanged).set(outState[pinChanged]),true);
                      Sprint(", sent"); 
                    }
                    else {
                      flashLED = true;
                      flashNumber = 3;
                    }
                  }            
                  Sprint(". State: "); Sprintln(outState[pinChanged]);
                  longPr[pinChanged] = false;
                }  
                else {
                  buttonTime = millis();
                  indexButton = pinChanged;
                }
                pinChanged = 255;
                battStatCounter++;
              }
              else {
                pinChanged = 255;
              }        
            break;
          }
          
          if (battPower && (battStatCounter >= battUpdater)) {  
            batteryStats();
            battStatCounter = 0;
          }
        
          checkTransportStatus();
          
          if (pinChanged > 25) {  
            if ((battPower) && (millis() >= lastTimeButton + sleepWait)) {
              if (!dimLED) {
                newDim = 0;
              }
              dimLED = true;
              if (currDim <= 0) {
                lightsOUT();
                newDim = 255;
                dimLED = true;
              } 
            }
          }
          updateLED();
        }
        
        
        /**************************************************************************/
        
        void ChanA_ISR()                        
        {
           pinChanged = ChanA;
           inState[ChanA] = BtnA.read();
        }
        
        
        void ChanB_ISR()
        {
           pinChanged = ChanB;
           inState[ChanB] = BtnB.read();
        }
        
        
        void ChanC_ISR()
        {
          pinChanged = ChanC;
          inState[ChanC] = BtnC.read();
        }
        
        
        void ChanD_ISR()
        {
          pinChanged = ChanD;
          inState[ChanD] = BtnD.read();
        }
        
        
        /**************************************************************************/
        
        void readInputs()
        {
          inState[ChanA] = BtnA.read();
          inState[ChanB] = BtnB.read();
          inState[ChanC] = BtnC.read();
          inState[ChanD] = BtnD.read();
        }
        
        
        /**************************************************************************/
        
        void receive(const MyMessage &message) 
        {
          Sprintln("\nMessage received");
          if (message.isAck()) {
            Sprintln("ACK\n");
            flashLED = true;
          }
          
          if (message.type == V_VAR1) 
          {
            Sprint("Notifier value; ");
            if (message.sensor == LEDpinWS) {
              newLED = message.getInt();
              Sprint("received hue-value: "); Sprint(newLED); Sprintln("\n");
              changeLED = true;
            }
          }
          if (message.type == V_STATUS) {
            outState[message.sensor] = message.getBool();
            Sprint("Channel "); Sprint(message.sensor); Sprint(" switched to "); Sprintln(outState[message.sensor]); Sprintln("\n");
            digitalWrite(actuatorPin[message.sensor], outState[message.sensor]);
          }
        }
        
        
        /**************************************************************************/
        
        void lightsOUT()
        {
          Sprintln("\nSleep\n");
          digitalWrite(WS_Power, HIGH);
          pinMode(WS_Power, INPUT);
          wait(30);
          int testInt = sleep(0xff, 0x00, 0xff, 0x00, 0); 
          pinMode(WS_Power, OUTPUT);
          digitalWrite(WS_Power, HIGH);
          Sprintln(testInt);
          wait(30);
        }
        
        
        /**************************************************************************/
        
        void updateLED()
        {
          if ((millis() >= flashTime + 100) && flashWait)  {
            flashWait = false;
          }
          
          if (flashLED) {                         // Flash the LED white (or whatever color)as confirmation.
            if (!flashOn && !flashWait) {
              flashTime = millis();               // Use millis() to prevent blocking the code with wait() or delay().
              flashOn = true;
              if (LED_FUNCTION == 1) {
                digitalWrite(LEDpinACK, HIGH);
              }
              else if (LED_FUNCTION == 2) {
                notifier[0] = CHSV(currLED, 0, currDim);    // Set the saturation to 0 (no color, just light -> white).
              }
            }
            else if ((millis() >= flashTime + 50) && !flashWait) {
              if (LED_FUNCTION == 1) {
                digitalWrite(LEDpinACK, LOW);       
              }
              else if (LED_FUNCTION == 2) {
                notifier[0] = CHSV(currLED, 255, currDim);  // Set the saturation back to original.
              }
              flashOn = false;
              flashWait = true;
              flashNumber--;
              if (flashNumber <= 0) {
                flashNumber = 1;
                flashLED = false; 
                flashWait = false;
              }
            }
          }
          else if (changeLED) {                   // Morph the next color in the current for the notification LED.
            int deltaHSV = currLED - newLED;
            if (currLED != newLED) {
              if (deltaHSV < 0) {
                currLED += 1;
              }
              else if (deltaHSV > 0) {
                currLED -= 1;
              }
              notifier[0] = CHSV(currLED, 255, currDim);
              Sprintln(currLED);
            }
            else {
              changeLED = false;
            }
          }
          else if (dimLED) {                      // Dim the notification LED to 0 when battery powered.
            if (currDim != newDim) {
              if (currDim >= newDim) {
                currDim -= 1;                     // Slowly dim the indicator before sleep time and...
              }
              else if (currDim <= newDim) {
                currDim += 5;                     // ...bring it back up in a hurry.
              }
              notifier[0] = CHSV(currLED, 255, currDim);
            }
            else {
              dimLED = false;
            }
          }
          FastLED.show();                         
        }
        
        
        /**************************************************************************/
        
        void checkTransportStatus()
        {
          /*if (isTransportSearchingParent()) {
            if (!transportDown); {
              transportDown = true;
            }
          }
          else if (transportDown) {
            transportDown = false;
            synchronizeChannels();
          }*/
        }
        
        
        /**************************************************************************/
        
        void synchronizeChannels()
        {
          for (int i = ChanA; i < ChanD+1; i++) {             // Syncing switch states to controller.
            if ((function[i] == 2) || (function[i] == 3)) {
              Sprint("\nChannel "); Sprint(i); Sprintln(" sync.");
              send(msgToggle.setSensor(i).set(false));
            }
          }
        }
        
        
        /**************************************************************************/
        
        void indication(const indication_t)
        {
          
        }
        
        /**************************************************************************/
        
        void batteryStats()
        {
          if (battPower) {
            float battPct = vcc.Read_Perc();
            float battVolt = vcc.Read_Volts();
            wait(50);
            sendBatteryLevel(battPct);
            Sprint("Battery level: "); Sprintln(battVolt); Sprintln("V.\n");
          }  
        }
        
        0 MCO:BGN:INIT NODE,CP=RRNNA--,VER=2.1.1
        6 MCO:BGN:BFR
        
        Starting up...
        
        Reading config...
        10 TSM:INIT
        16 TSF:WUR:MS=100
        22 TSM:INIT:TSP OK
        26 TSM:INIT:STATID=85
        28 TSF:SID:OK,ID=85
        32 TSM:FPAR
        165 TSF:MSG:SEND,85-85-255-255,s=255,c=3,t=7,pt=0,l=0,sg=0,ft=0,st=OK:
        178 MCO:BGN:STP
        
        Done. 
        Starting program.
        210 MCO:BGN:INIT OK,TSP=0
        985 TSF:MSG:READ,0-0-85,s=255,c=3,t=8,pt=1,l=1,sg=0:0
        993 TSF:MSG:FPAR OK,ID=0,D=1
        2179 TSM:FPAR:OK
        2181 TSM:ID
        2185 TSM:ID:OK
        2187 TSM:UPL
        2197 TSF:MSG:SEND,85-85-0-0,s=255,c=3,t=24,pt=1,l=1,sg=0,ft=0,st=OK:1
        2246 TSF:MSG:READ,0-0-85,s=255,c=3,t=25,pt=1,l=1,sg=0:1
        2256 TSF:MSG:PONG RECV,HP=1
        2263 TSM:UPL:OK
        2265 TSM:READY:ID=85,PAR=0,DIS=1
        2277 TSF:MSG:SEND,85-85-0-0,s=255,c=3,t=15,pt=6,l=2,sg=0,ft=0,st=OK:0100
        2326 TSF:MSG:READ,0-0-85,s=255,c=3,t=15,pt=6,l=2,sg=0:0100
        2344 TSF:MSG:SEND,85-85-0-0,s=255,c=0,t=17,pt=0,l=5,sg=0,ft=0,st=OK:2.1.1
        2367 TSF:MSG:SEND,85-85-0-0,s=255,c=3,t=6,pt=1,l=1,sg=0,ft=0,st=OK:0
        2422 TSF:MSG:READ,0-0-85,s=255,c=3,t=6,pt=0,l=1,sg=0:M
        Start radio and sensors
        Send node info. 
        
        2443 TSF:MSG:SEND,85-85-0-0,s=255,c=3,t=11,pt=0,l=15,sg=0,ft=0,st=OK:switchNode(Hal)
        2465 TSF:MSG:SEND,85-85-0-0,s=255,c=3,t=12,pt=0,l=3,sg=0,ft=0,st=OK:1.0
        
        Present channel 0, function: 1, safety: 0
        2488 TSF:MSG:SEND,85-85-0-0,s=0,c=0,t=3,pt=0,l=0,sg=0,ft=0,st=OK:
        
        Present channel 1, function: 3, safety: 0
        2508 TSF:MSG:SEND,85-85-0-0,s=1,c=0,t=3,pt=0,l=0,sg=0,ft=0,st=OK:
        
        Present channel 2, function: 0, safety: 0
        
        Present channel 3, function: 0, safety: 0
        
        Present notifier.
        2535 TSF:MSG:SEND,85-85-0-0,s=6,c=0,t=26,pt=0,l=0,sg=0,ft=0,st=OK:
        
        Channel 1 sync.
        2549 !MCO:SND:NODE NOT REG
        2557 MCO:REG:REQ
        2568 TSF:MSG:SEND,85-85-0-0,s=255,c=3,t=26,pt=1,l=1,sg=0,ft=0,st=OK:2
        2617 TSF:MSG:READ,0-0-85,s=255,c=3,t=27,pt=1,l=1,sg=0:1
        2627 MCO:PIM:NODE REG=1
        
        Sleep
        
        3268 MCO:SLP:MS=0,SMS=0,I1=255,M1=0,I2=255,M2=0
        3276 MCO:SLP:TPD
        3278 MCO:SLP:WUP=-1
        -1
        
        Sleep
        
        4112 MCO:SLP:MS=0,SMS=0,I1=255,M1=0,I2=255,M2=0
        4120 MCO:SLP:TPD
        4122 MCO:SLP:WUP=-1
        -1
        
        Sleep
        
        4956 MCO:SLP:MS=0,SMS=0,I1=255,M1=0,I2=255,M2=0
        4964 MCO:SLP:TPD
        4966 MCO:SLP:WUP=-1
        -1
        
        Sleep
        
        5799 MCO:SLP:MS=0,SMS=0,I1=255,M1=0,I2=255,M2=0
        5808 MCO:SLP:TPD
        5810 MCO:SLP:WUP=-1
        -1
        
        Sleep
        
        6643 MCO:SLP:MS=0,SMS=0,I1=255,M1=0,I2=255,M2=0
        6651 MCO:SLP:TPD
        6653 MCO:SLP:WUP=-1
        -1
        
        Sleep
        
        7487 MCO:SLP:MS=0,SMS=0,I1=255,M1=0,I2=255,M2=0
        7495 MCO:SLP:TPD
        7497 MCO:SLP:WUP=-1
        -1
        
        Sleep
        
        8331 MCO:SLP:MS=0,SMS=0,I1=255,M1=0,I2=255,M2=0
        8339 MCO:SLP:TPD
        8341 MCO:SLP:WUP=-1
        -1
        

        And so on...

        The only funny thing I see is at 2549 !MCO:SND:NODE NOT REG.

        ( I actually just noticed that the setupis run before the presentation. I thought that had been changed)

        edit: I forgot to mention my hardware!
        328p-AU on a custom board on the 8MHz internal clock. The interrupt pins are connected via a RC network (debounce) to the pins with the internal pullups. I used the button.h library because I'm lazy :) it also keeps the code a bit neater to look at.

        tekkaT 1 Reply Last reply
        0
        • D DavidZH

          Sure!

          ***************************************************************************
          **
          ** Light switch v1.0 with additional relay/power supply daughter board
          **
          ** Scraped together by D Hille. MySensors library by Henrik Ekblad et al.
          **    Button lib.:              github.com/JChristensen/Button
          **    PinChangeInterrupt lib.:  github.com/NicoHood/PinChangeInterrupt
          **    FastLED lib.:             github.com/FastLED
          **
          ***************************************************************************/
          //                    MySensors definitions
          
          #define MY_DEBUG                 // Comment out after finishing sketch (saves over 6kB flash)
          //#define MY_DEBUG_VERBOSE_SIGNING // Comment out when no signing is used or when everything is OK
          
          #define MY_BAUD_RATE 57600       // Lower as max because of 8 MHz Arduino
          
          #define MY_RADIO_RFM69
          #define MY_IS_RFM69HW
          
          #define MY_NODE_ID 85            // Delete to use automatic ID assignment
          
          #define MY_TRANSPORT_WAIT_READY_MS 100 //Start the node even if no connection to the GW could be made
          //#define MY_TRANSPORT_STATE_RETRIES 1
          //#define MY_TRANSPORT_MAX_TSM_FAILURES    (2u)                 //Uncomment these three when usung battery powered node
          //#define MY_TRANSPORT_TIMEOUT_EXT_FAILURE_STATE (5*60*1000ul)
          
          
          /**************************************************************************/
          //                        Security
          /**************************************************************************/
          
          //#define MY_SIGNING_SOFT
          //#define MY_SIGNING_SOFT_RANDOMSEED_PIN 7
          //#define MY_SIGNING_REQUEST_SIGNATURES
          
          //#define MY_RFM69_ENABLE_ENCRYPTION
          
          
          /**************************************************************************/
          //                    Switch definitions
          /**************************************************************************/
          
          #define BATTERY_POWERED
          #define battUpdater 50            // Number of TX actions to count before a new battery status update is sent.
          
          #define LED_FUNCTION 2
          // LED functions:
          // 0.: no LED present
          // 1.: ACK                        (LED will flash briefly when ACK is received)
          // 2.: Notification               (RGB-LED wil display a function of the controller, or flash white when ACK is received)
          
          #define NODE_CHAN_A_FUNCTION 1
          
          #define NODE_CHAN_B_FUNCTION 3
          
          #define NODE_CHAN_C_FUNCTION 0
          
          #define NODE_CHAN_D_FUNCTION 0
          // 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)
          // 3.: normal                    (relay controlled via RF and local)
          // 4.: local relay               (no RF control, only button)
          
          //#define SAFETY_BUTTON_A          // When defined button needs to be pressed for a set time to activate the button.
          //#define SAFETY_BUTTON_B          // Comment out to deactivate.
          //#define SAFETY_BUTTON_C
          //#define SAFETY_BUTTON_D        
          
          #define SAFETY_PRESS_TIME 1      // time in seconds the button needs to be pressed.
          
          
          /**************************************************************************/
          //                  Debug and interrupt definitions
          /**************************************************************************/
          
          #define LOCAL_DEBUG                              // Comment out to switch all debug messages off (saves 1kb flash)
          
          /*#ifdef MY_DEBUG                                  // Differentiate between global debug including radio and local debug 
            #define LOCAL_DEBUG                            // for the sketch alone.
          #endif*/
          
          #ifdef LOCAL_DEBUG 
            #define Sprint(a) (Serial.print(a))            // Macro as substitute for serial debug. Will be an empty macro when
            #define Sprintln(a) (Serial.println(a))        // debug is switched off
          #else
            #define Sprint(a)                                       
            #define Sprintln(a)
          #endif
          
          #define EI_NOTEXTERNAL
          #define EI_NOTPORTB
          #define EI_NOTPORTD
          #define EI_ARDUINO_INTERRUPTED_PIN
          
          
          /**************************************************************************/
          
          #include <Button.h>
          #include <EnableInterrupt.h>
          #include <MySensors.h>
          #include <FastLED.h>
          #include <Vcc.h>
          
          
          #define BMEaddr 0x76
          #define Max44099Addr 0x4A
          #define sketchName "switchNode(Hal)"
          #define sketchVer "1.0" 
          
          #define buttApin  14              // Arduino Digital I/O pin numbers for connected buttons 
          #define buttBpin  15              // when connected to '`official' PCB.
          #define buttCpin  8
          #define buttDpin  9
          
          #define relayApin 16
          #define relayBpin 17
          
          #define LEDpinACK 5
          #define LEDpinWS 6
          #define WS_Power 9
          
          #define ChanA 0
          #define ChanB 1
          #define ChanC 2
          #define ChanD 3
                                    
          #define PULLUP true        
          #define INVERT true        
          #define bounceTime 20             // A debounce time of 20 milliseconds usually works well for tactile button switches.
          #define sleepWait 2000           // Time to wait in ms before node sleeps (to be able to receive notification messages).
          
          volatile int pinChanged = 255;
          int indexButton = 255;
          int currDim = 255;                // Bright value of notificator at startup.
          int newDim = 0;
          int currLED = 30;                 // Hue value of notificator at startup.
          int newLED = 0;
          bool buttonPressed = false;
          bool changeLED = false;
          bool flashLED = false;
          int flashNumber = 1;
          bool flashWait = false;
          bool dimLED = false;
          bool flashOn = false;
          
          bool battPower = true;
          int inputPin[5] = {0, 0, 0, 0, 0};          // State machine registers
          int actuatorPin[2] = {0, 0};
          int function[4] = {0, 0, 0, 0};
          bool safetyBttn[4] = {0, 0, 0, 0};
          bool reqAck[4] = {0, 0, 0, 0};
          bool inState[5] = {0, 0, 0, 0, 0};
          bool longPr[5] = {0, 0, 0, 0, 0};
          bool outState[4] = {0, 0, 0, 0};
          bool longPress = false;
          
          unsigned long lastTimeButton;               // Timer registers
          unsigned long flashTime;
          unsigned long lightsOut;
          unsigned long buttonTime;
          unsigned long longPressTime;
          
          bool startUp = true;
          bool transportDown = false;
          bool metric = true; 
          
          int battStatCounter = 0;
          const float VccMin = 0.0;                   // Minimum expected Vcc level, in Volts.
          const float VccMax = 5.0;                   // Maximum expected Vcc level, in Volts.
          const float VccCorrection = 3.41/3.35;      // Measured Vcc by multimeter divided by reported Vcc
          
          
          /**************************************************************************/
          //                  Library declarations
          /**************************************************************************/
          
          Button BtnA(buttApin, PULLUP, INVERT, bounceTime);    
          Button BtnB(buttBpin, PULLUP, INVERT, bounceTime);
          Button BtnC(buttCpin, PULLUP, INVERT, bounceTime);
          Button BtnD(buttDpin, PULLUP, INVERT, bounceTime);
          
          CRGB notifier[1];                           // define notification LED
          
          MyMessage msgButton(0, V_TRIPPED);
          MyMessage msgToggle(0, V_STATUS);
          MyMessage msgLED(LEDpinWS, V_RGB);
          
          Vcc vcc(VccCorrection);
          
          
          /**************************************************************************/
          //                  Error messages
          /**************************************************************************/
          
          #if (NODE_CHAN_A_FUNCTION == 0)
          #error Channel A cannot be turned off. For single channel use turn off channel B.
          #endif
          #if (NODE_CHAN_C_FUNCTION >= 3 || NODE_CHAN_D_FUNCTION >= 3)
          #error Channels C and D do not have relays attached, can only be used as buttons.
          #endif
          
          
          /**************************************************************************/
          
          void before(void)
          {
            Sprintln("\nStarting up...");
            Sprintln("\nReading config...");
              
          //                  Fill state machine registers
          
            inputPin[ChanA] = buttApin;
            #ifdef SAFETY_BUTTON_A
              safetyBttn[ChanA] = true;
            #endif
            function[ChanA] = NODE_CHAN_A_FUNCTION;
            enableInterrupt(inputPin[ChanA], ChanA_ISR, CHANGE);
            if (function[ChanA] <= 2 && LED_FUNCTION >= 1) {
              reqAck[ChanA] = true;
            }
            else {
              actuatorPin[ChanA] = relayApin;
            }
              
            if (NODE_CHAN_B_FUNCTION >= 1) {
              inputPin[ChanB] = buttBpin;
              #ifdef SAFETY_BUTTON_B
                safetyBttn[ChanB] = true;
              #endif
              function[ChanB] = NODE_CHAN_B_FUNCTION;
              enableInterrupt(inputPin[ChanB], ChanB_ISR, CHANGE);
              if (function[ChanB] <= 2 && LED_FUNCTION >= 1) {
                reqAck[ChanB] = true;
              }
              else {
                actuatorPin[ChanB] = relayBpin;
              }
            }
            
            if (NODE_CHAN_C_FUNCTION >= 1) {
              inputPin[ChanC] = buttCpin;
              #ifdef SAFETY_BUTTON_C
                safetyBttn[ChanC] = true;
              #endif
              function[ChanC] = NODE_CHAN_C_FUNCTION;
              enableInterrupt(inputPin[ChanC], ChanC_ISR, CHANGE);
              if (function[ChanC] <= 2 && LED_FUNCTION >= 1) {
                reqAck[ChanC] = true;
              }    
            }
            
            if (NODE_CHAN_D_FUNCTION >= 1) {
              inputPin[ChanD] = buttDpin;
              #ifdef SAFETY_BUTTON_D
                safetyBttn[ChanD] = true;
              #endif
              function[ChanD] = NODE_CHAN_D_FUNCTION;
              enableInterrupt(inputPin[ChanD], ChanD_ISR, CHANGE);
              if (function[ChanD] <= 2 && LED_FUNCTION >= 1) {
                reqAck[ChanD] = true;
              }
            }
          
            longPressTime = SAFETY_PRESS_TIME * 1000;
          }
          
          
          /**************************************************************************/
          
          void presentation()  
          {
            Sprintln("Start radio and sensors");  
            Sprintln("Send node info. \n");
            
            sendSketchInfo(sketchName, sketchVer);
            
            for (int i = ChanA; i < ChanD+1; i++) {
              Sprint("\nPresent channel "); Sprint(i); Sprint(", function: "); Sprint(function[i]); Sprint(", safety: "); Sprintln(safetyBttn[i]);
              if (function[i] == 1) {
                present(i, S_BINARY);
              }
              else if (function[i] >= 2) { 
                present(i, S_LIGHT);
              }
            }
          
            if (LED_FUNCTION == 2) {
              Sprintln("\nPresent notifier.");   
              present(LEDpinWS, S_RGB_LIGHT);
            }
          
            synchronizeChannels();
          }
          
          
          /**************************************************************************/
          
          void setup(void)
          {  
            #ifndef BATTERY_POWERED
              battPower = false;
            #endif
          
            pinMode(LEDpinACK, OUTPUT);
          
            if (LED_FUNCTION == 2) {
              pinMode(WS_Power, OUTPUT);
              digitalWrite(WS_Power, HIGH);    
              FastLED.addLeds<WS2812B, LEDpinWS, GRB>(notifier, 1);
              wait(30);
              notifier[0] = CHSV(currLED, 255, currDim);    // give LED initial color
              FastLED.show();
            }
          
            if (function[ChanA] >= 3) {
              pinMode(actuatorPin[ChanA], OUTPUT);
            }
            if (function[ChanB] >= 3) {
              pinMode(actuatorPin[ChanB], OUTPUT);
            }
            
            Sprintln("\nDone. \nStarting program.");
            lastTimeButton = millis();
          
            checkTransportStatus();
          }
          
          
          /**************************************************************************/
          
          
          void loop(void)
          {
            if (indexButton <= 25) {                          // Measure time when safety feature is enabled.
              if (millis() >= buttonTime + longPressTime) {
                Sprint("\nChannel "); Sprint(indexButton); Sprintln(" long-pressed");
                flashLED = true;
                pinChanged = indexButton;
                longPr[indexButton] = true;
                indexButton = 255;
                wait(30);
              }
            }  
          
            //if (buttonPressed) {
            //  readInputs();
            //}
            
            switch (function[pinChanged]) {
              case 1:
                Sprint("\nChannel "); Sprint(pinChanged);       
                if (inState[pinChanged] && !buttonPressed) {
                  Sprintln(" pressed.");
                  if ((!safetyBttn[pinChanged]) || (longPr[pinChanged])){
                    if (!transportDown) {
                      send(msgButton.setSensor(pinChanged).set(true));
                    }
                  }
                  else {
                    indexButton = pinChanged;
                    buttonTime = millis();
                  }
                  pinChanged = 255;
                  //buttonPressed = true;
                  wait(30);
                  break;
                }
                else if (!inState[pinChanged]) {
                  lastTimeButton = millis();
                  Sprintln(" released.");
                  if ((!safetyBttn[pinChanged]) || (longPr[pinChanged])) {
                    if (!transportDown) {
                      send(msgButton.setSensor(pinChanged).set(false),reqAck[pinChanged]);
                    }
                    else {
                      flashLED = true;
                      flashNumber = 3;
                    }
                  }
                  longPr[pinChanged] = false;
                  indexButton = 255;
                  pinChanged = 255;
                  wait(30);
                  battStatCounter++;
                }
                break;
              case 2:
              case 3:
              case 4:
                lastTimeButton = millis();
                if (inState[pinChanged]) {
                  if ((!safetyBttn[pinChanged]) || (longPr[pinChanged])) {
                    Sprint("\nChannel "); Sprint(pinChanged); Sprint(" toggled");
                    outState[pinChanged] = !outState[pinChanged]; 
                    if (function[pinChanged] >= 3) {
                      digitalWrite(actuatorPin[pinChanged], outState[pinChanged]);
                      Sprint(", relay changed");
                    }
                    if (function[pinChanged] == 2 || function[pinChanged] == 3) {
                      if (!transportDown) {
                        send(msgToggle.setSensor(pinChanged).set(outState[pinChanged]),true);
                        Sprint(", sent"); 
                      }
                      else {
                        flashLED = true;
                        flashNumber = 3;
                      }
                    }            
                    Sprint(". State: "); Sprintln(outState[pinChanged]);
                    longPr[pinChanged] = false;
                  }  
                  else {
                    buttonTime = millis();
                    indexButton = pinChanged;
                  }
                  pinChanged = 255;
                  battStatCounter++;
                }
                else {
                  pinChanged = 255;
                }        
              break;
            }
            
            if (battPower && (battStatCounter >= battUpdater)) {  
              batteryStats();
              battStatCounter = 0;
            }
          
            checkTransportStatus();
            
            if (pinChanged > 25) {  
              if ((battPower) && (millis() >= lastTimeButton + sleepWait)) {
                if (!dimLED) {
                  newDim = 0;
                }
                dimLED = true;
                if (currDim <= 0) {
                  lightsOUT();
                  newDim = 255;
                  dimLED = true;
                } 
              }
            }
            updateLED();
          }
          
          
          /**************************************************************************/
          
          void ChanA_ISR()                        
          {
             pinChanged = ChanA;
             inState[ChanA] = BtnA.read();
          }
          
          
          void ChanB_ISR()
          {
             pinChanged = ChanB;
             inState[ChanB] = BtnB.read();
          }
          
          
          void ChanC_ISR()
          {
            pinChanged = ChanC;
            inState[ChanC] = BtnC.read();
          }
          
          
          void ChanD_ISR()
          {
            pinChanged = ChanD;
            inState[ChanD] = BtnD.read();
          }
          
          
          /**************************************************************************/
          
          void readInputs()
          {
            inState[ChanA] = BtnA.read();
            inState[ChanB] = BtnB.read();
            inState[ChanC] = BtnC.read();
            inState[ChanD] = BtnD.read();
          }
          
          
          /**************************************************************************/
          
          void receive(const MyMessage &message) 
          {
            Sprintln("\nMessage received");
            if (message.isAck()) {
              Sprintln("ACK\n");
              flashLED = true;
            }
            
            if (message.type == V_VAR1) 
            {
              Sprint("Notifier value; ");
              if (message.sensor == LEDpinWS) {
                newLED = message.getInt();
                Sprint("received hue-value: "); Sprint(newLED); Sprintln("\n");
                changeLED = true;
              }
            }
            if (message.type == V_STATUS) {
              outState[message.sensor] = message.getBool();
              Sprint("Channel "); Sprint(message.sensor); Sprint(" switched to "); Sprintln(outState[message.sensor]); Sprintln("\n");
              digitalWrite(actuatorPin[message.sensor], outState[message.sensor]);
            }
          }
          
          
          /**************************************************************************/
          
          void lightsOUT()
          {
            Sprintln("\nSleep\n");
            digitalWrite(WS_Power, HIGH);
            pinMode(WS_Power, INPUT);
            wait(30);
            int testInt = sleep(0xff, 0x00, 0xff, 0x00, 0); 
            pinMode(WS_Power, OUTPUT);
            digitalWrite(WS_Power, HIGH);
            Sprintln(testInt);
            wait(30);
          }
          
          
          /**************************************************************************/
          
          void updateLED()
          {
            if ((millis() >= flashTime + 100) && flashWait)  {
              flashWait = false;
            }
            
            if (flashLED) {                         // Flash the LED white (or whatever color)as confirmation.
              if (!flashOn && !flashWait) {
                flashTime = millis();               // Use millis() to prevent blocking the code with wait() or delay().
                flashOn = true;
                if (LED_FUNCTION == 1) {
                  digitalWrite(LEDpinACK, HIGH);
                }
                else if (LED_FUNCTION == 2) {
                  notifier[0] = CHSV(currLED, 0, currDim);    // Set the saturation to 0 (no color, just light -> white).
                }
              }
              else if ((millis() >= flashTime + 50) && !flashWait) {
                if (LED_FUNCTION == 1) {
                  digitalWrite(LEDpinACK, LOW);       
                }
                else if (LED_FUNCTION == 2) {
                  notifier[0] = CHSV(currLED, 255, currDim);  // Set the saturation back to original.
                }
                flashOn = false;
                flashWait = true;
                flashNumber--;
                if (flashNumber <= 0) {
                  flashNumber = 1;
                  flashLED = false; 
                  flashWait = false;
                }
              }
            }
            else if (changeLED) {                   // Morph the next color in the current for the notification LED.
              int deltaHSV = currLED - newLED;
              if (currLED != newLED) {
                if (deltaHSV < 0) {
                  currLED += 1;
                }
                else if (deltaHSV > 0) {
                  currLED -= 1;
                }
                notifier[0] = CHSV(currLED, 255, currDim);
                Sprintln(currLED);
              }
              else {
                changeLED = false;
              }
            }
            else if (dimLED) {                      // Dim the notification LED to 0 when battery powered.
              if (currDim != newDim) {
                if (currDim >= newDim) {
                  currDim -= 1;                     // Slowly dim the indicator before sleep time and...
                }
                else if (currDim <= newDim) {
                  currDim += 5;                     // ...bring it back up in a hurry.
                }
                notifier[0] = CHSV(currLED, 255, currDim);
              }
              else {
                dimLED = false;
              }
            }
            FastLED.show();                         
          }
          
          
          /**************************************************************************/
          
          void checkTransportStatus()
          {
            /*if (isTransportSearchingParent()) {
              if (!transportDown); {
                transportDown = true;
              }
            }
            else if (transportDown) {
              transportDown = false;
              synchronizeChannels();
            }*/
          }
          
          
          /**************************************************************************/
          
          void synchronizeChannels()
          {
            for (int i = ChanA; i < ChanD+1; i++) {             // Syncing switch states to controller.
              if ((function[i] == 2) || (function[i] == 3)) {
                Sprint("\nChannel "); Sprint(i); Sprintln(" sync.");
                send(msgToggle.setSensor(i).set(false));
              }
            }
          }
          
          
          /**************************************************************************/
          
          void indication(const indication_t)
          {
            
          }
          
          /**************************************************************************/
          
          void batteryStats()
          {
            if (battPower) {
              float battPct = vcc.Read_Perc();
              float battVolt = vcc.Read_Volts();
              wait(50);
              sendBatteryLevel(battPct);
              Sprint("Battery level: "); Sprintln(battVolt); Sprintln("V.\n");
            }  
          }
          
          0 MCO:BGN:INIT NODE,CP=RRNNA--,VER=2.1.1
          6 MCO:BGN:BFR
          
          Starting up...
          
          Reading config...
          10 TSM:INIT
          16 TSF:WUR:MS=100
          22 TSM:INIT:TSP OK
          26 TSM:INIT:STATID=85
          28 TSF:SID:OK,ID=85
          32 TSM:FPAR
          165 TSF:MSG:SEND,85-85-255-255,s=255,c=3,t=7,pt=0,l=0,sg=0,ft=0,st=OK:
          178 MCO:BGN:STP
          
          Done. 
          Starting program.
          210 MCO:BGN:INIT OK,TSP=0
          985 TSF:MSG:READ,0-0-85,s=255,c=3,t=8,pt=1,l=1,sg=0:0
          993 TSF:MSG:FPAR OK,ID=0,D=1
          2179 TSM:FPAR:OK
          2181 TSM:ID
          2185 TSM:ID:OK
          2187 TSM:UPL
          2197 TSF:MSG:SEND,85-85-0-0,s=255,c=3,t=24,pt=1,l=1,sg=0,ft=0,st=OK:1
          2246 TSF:MSG:READ,0-0-85,s=255,c=3,t=25,pt=1,l=1,sg=0:1
          2256 TSF:MSG:PONG RECV,HP=1
          2263 TSM:UPL:OK
          2265 TSM:READY:ID=85,PAR=0,DIS=1
          2277 TSF:MSG:SEND,85-85-0-0,s=255,c=3,t=15,pt=6,l=2,sg=0,ft=0,st=OK:0100
          2326 TSF:MSG:READ,0-0-85,s=255,c=3,t=15,pt=6,l=2,sg=0:0100
          2344 TSF:MSG:SEND,85-85-0-0,s=255,c=0,t=17,pt=0,l=5,sg=0,ft=0,st=OK:2.1.1
          2367 TSF:MSG:SEND,85-85-0-0,s=255,c=3,t=6,pt=1,l=1,sg=0,ft=0,st=OK:0
          2422 TSF:MSG:READ,0-0-85,s=255,c=3,t=6,pt=0,l=1,sg=0:M
          Start radio and sensors
          Send node info. 
          
          2443 TSF:MSG:SEND,85-85-0-0,s=255,c=3,t=11,pt=0,l=15,sg=0,ft=0,st=OK:switchNode(Hal)
          2465 TSF:MSG:SEND,85-85-0-0,s=255,c=3,t=12,pt=0,l=3,sg=0,ft=0,st=OK:1.0
          
          Present channel 0, function: 1, safety: 0
          2488 TSF:MSG:SEND,85-85-0-0,s=0,c=0,t=3,pt=0,l=0,sg=0,ft=0,st=OK:
          
          Present channel 1, function: 3, safety: 0
          2508 TSF:MSG:SEND,85-85-0-0,s=1,c=0,t=3,pt=0,l=0,sg=0,ft=0,st=OK:
          
          Present channel 2, function: 0, safety: 0
          
          Present channel 3, function: 0, safety: 0
          
          Present notifier.
          2535 TSF:MSG:SEND,85-85-0-0,s=6,c=0,t=26,pt=0,l=0,sg=0,ft=0,st=OK:
          
          Channel 1 sync.
          2549 !MCO:SND:NODE NOT REG
          2557 MCO:REG:REQ
          2568 TSF:MSG:SEND,85-85-0-0,s=255,c=3,t=26,pt=1,l=1,sg=0,ft=0,st=OK:2
          2617 TSF:MSG:READ,0-0-85,s=255,c=3,t=27,pt=1,l=1,sg=0:1
          2627 MCO:PIM:NODE REG=1
          
          Sleep
          
          3268 MCO:SLP:MS=0,SMS=0,I1=255,M1=0,I2=255,M2=0
          3276 MCO:SLP:TPD
          3278 MCO:SLP:WUP=-1
          -1
          
          Sleep
          
          4112 MCO:SLP:MS=0,SMS=0,I1=255,M1=0,I2=255,M2=0
          4120 MCO:SLP:TPD
          4122 MCO:SLP:WUP=-1
          -1
          
          Sleep
          
          4956 MCO:SLP:MS=0,SMS=0,I1=255,M1=0,I2=255,M2=0
          4964 MCO:SLP:TPD
          4966 MCO:SLP:WUP=-1
          -1
          
          Sleep
          
          5799 MCO:SLP:MS=0,SMS=0,I1=255,M1=0,I2=255,M2=0
          5808 MCO:SLP:TPD
          5810 MCO:SLP:WUP=-1
          -1
          
          Sleep
          
          6643 MCO:SLP:MS=0,SMS=0,I1=255,M1=0,I2=255,M2=0
          6651 MCO:SLP:TPD
          6653 MCO:SLP:WUP=-1
          -1
          
          Sleep
          
          7487 MCO:SLP:MS=0,SMS=0,I1=255,M1=0,I2=255,M2=0
          7495 MCO:SLP:TPD
          7497 MCO:SLP:WUP=-1
          -1
          
          Sleep
          
          8331 MCO:SLP:MS=0,SMS=0,I1=255,M1=0,I2=255,M2=0
          8339 MCO:SLP:TPD
          8341 MCO:SLP:WUP=-1
          -1
          

          And so on...

          The only funny thing I see is at 2549 !MCO:SND:NODE NOT REG.

          ( I actually just noticed that the setupis run before the presentation. I thought that had been changed)

          edit: I forgot to mention my hardware!
          328p-AU on a custom board on the 8MHz internal clock. The interrupt pins are connected via a RC network (debounce) to the pins with the internal pullups. I used the button.h library because I'm lazy :) it also keeps the code a bit neater to look at.

          tekkaT Offline
          tekkaT Offline
          tekka
          Admin
          wrote on last edited by tekka
          #29

          @DavidZH IRQ triggers only on LOW level when sleeping (see at328 datasheet) - what happens if you substitute all enableInterrupt(xyz, CHANGE) to enableInterrupt(xyz, LOW)?

          The only funny thing I see is at 2549 !MCO:SND:NODE NOT REG

          this is because you set a 100ms timeout here:

          #define MY_TRANSPORT_WAIT_READY_MS 100 //Start the node even if no connection to the GW could be made
          

          set it to 0 or increase to e.g. 10000...

          D 1 Reply Last reply
          0
          • tekkaT tekka

            @DavidZH IRQ triggers only on LOW level when sleeping (see at328 datasheet) - what happens if you substitute all enableInterrupt(xyz, CHANGE) to enableInterrupt(xyz, LOW)?

            The only funny thing I see is at 2549 !MCO:SND:NODE NOT REG

            this is because you set a 100ms timeout here:

            #define MY_TRANSPORT_WAIT_READY_MS 100 //Start the node even if no connection to the GW could be made
            

            set it to 0 or increase to e.g. 10000...

            D Offline
            D Offline
            DavidZH
            wrote on last edited by
            #30

            @tekka said in Pin change interrupt not firing with MySensors:

            @DavidZH IRQ triggers only on LOW level when sleeping (see at328 datasheet) - what happens if you substitute all enableInterrupt(xyz, CHANGE) to enableInterrupt(xyz, LOW)?

            That is not true! Chapter 13, page 70, second part, first line: The External Interrupts can be triggered by a falling or rising edge or a low level. For completeness I tried, but the outcome is the same; node wakes up immediately.

            The only funny thing I see is at 2549 !MCO:SND:NODE NOT REG

            this is because you set a 100ms timeout here:

            #define MY_TRANSPORT_WAIT_READY_MS 100 //Start the node even if no connection to the GW could be made
            

            set it to 0 or increase to e.g. 10000...

            You're right! My bad. I'll change that to 2700, that's the approximate time the node needs to start up.

            tekkaT 1 Reply Last reply
            0
            • D DavidZH

              @tekka said in Pin change interrupt not firing with MySensors:

              @DavidZH IRQ triggers only on LOW level when sleeping (see at328 datasheet) - what happens if you substitute all enableInterrupt(xyz, CHANGE) to enableInterrupt(xyz, LOW)?

              That is not true! Chapter 13, page 70, second part, first line: The External Interrupts can be triggered by a falling or rising edge or a low level. For completeness I tried, but the outcome is the same; node wakes up immediately.

              The only funny thing I see is at 2549 !MCO:SND:NODE NOT REG

              this is because you set a 100ms timeout here:

              #define MY_TRANSPORT_WAIT_READY_MS 100 //Start the node even if no connection to the GW could be made
              

              set it to 0 or increase to e.g. 10000...

              You're right! My bad. I'll change that to 2700, that's the approximate time the node needs to start up.

              tekkaT Offline
              tekkaT Offline
              tekka
              Admin
              wrote on last edited by tekka
              #31

              @DavidZH

              That is not true! Chapter 13, page 70, second part, first line: The External Interrupts can be triggered by a falling or rising edge or a low level.

              For sleeping MCUs, you may have missed this here:
              http://www.atmel.com/images/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A-88PA-168A-168PA-328-328P_datasheet_Complete.pdf

              Chapter 10.1 Sleep Modes (pg 39) => read note 3

              If the node still wakes up, it could be triggered by the radio - this is something we need to investigate further. If you disable all IRQs (on ChanA-D) - does it still wake up?

              1 Reply Last reply
              0
              • D Offline
                D Offline
                DavidZH
                wrote on last edited by
                #32

                I respectfully disagree: That states only INT_0 and INT_1, I am using PCI. Different mechanism and vectors.

                About the radio waking it up: you mean interference? Or the interrupt? I think those are not the case, as he wake reason states -1, by timer. And if I flash the exact same sketch using the 2.0 library, the node stays asleep properly and wakes with the press of a button.
                The thing I ran into when developing this node was that I could use PCI when using deep sleep, but when I wanted to add a timer to send a sensor value periodically as well, the node would only wake up with the timer, and only then register the interrupt events.

                tekkaT 1 Reply Last reply
                0
                • D DavidZH

                  I respectfully disagree: That states only INT_0 and INT_1, I am using PCI. Different mechanism and vectors.

                  About the radio waking it up: you mean interference? Or the interrupt? I think those are not the case, as he wake reason states -1, by timer. And if I flash the exact same sketch using the 2.0 library, the node stays asleep properly and wakes with the press of a button.
                  The thing I ran into when developing this node was that I could use PCI when using deep sleep, but when I wanted to add a timer to send a sensor value periodically as well, the node would only wake up with the timer, and only then register the interrupt events.

                  tekkaT Offline
                  tekkaT Offline
                  tekka
                  Admin
                  wrote on last edited by
                  #33

                  @DavidZH Now I see, indeed, missed the PCI part - my bad :) Maybe @Yveaux can chip in here?

                  1 Reply Last reply
                  0
                  • D Offline
                    D Offline
                    DavidZH
                    wrote on last edited by
                    #34

                    No worries man! We're all learning as we're moving along with this project. And there's so much info in most of the posts that some parts will be missed. Inevitably.

                    YveauxY 1 Reply Last reply
                    0
                    • D DavidZH

                      No worries man! We're all learning as we're moving along with this project. And there's so much info in most of the posts that some parts will be missed. Inevitably.

                      YveauxY Offline
                      YveauxY Offline
                      Yveaux
                      Mod
                      wrote on last edited by
                      #35

                      @DavidZH before I dive into this could you please strip your sketch to the bare minimum that demonstrates the problem (mySensors 2.0.0 vs 2.1.1), preferably without using any hardware connections? Thanks!

                      http://yveaux.blogspot.nl

                      1 Reply Last reply
                      0
                      • D Offline
                        D Offline
                        DavidZH
                        wrote on last edited by
                        #36

                        Hi @Yveaux,

                        I have stripped it to one button on a RC-net and one led to see what I am doing, without changing the basic flow of the sketch. Also the node has been stripped bare. I have used a DIP version with the same bootloader (8MHz internal, 1V8 BOD by GertSanders, 3V3 power source) and the outcome is exactly the same:

                        • directly waking with 2.1.1, sleeping with 2.0.0.
                        • In both tests, all button presses are registered without problems.
                        • button library has nothing to do with it. When I use a simple digitalRead(), all remains the same.
                        • when I comment out the library call for the Interrupt (line 48), nothing changes.
                        /***************************************************************************/
                        //                    MySensors definitions
                        
                        #define MY_DEBUG    
                        #define MY_CORE_ONLY      
                        
                        #define MY_BAUD_RATE 57600       // Lower as max because of 8 MHz Arduino
                        
                        #define EI_NOTEXTERNAL               // Options for the EnableInterrupt library
                        #define EI_NOTPORTB                  // to save flash space
                        #define EI_NOTPORTD
                        #define EI_ARDUINO_INTERRUPTED_PIN
                        
                        /**************************************************************************/
                        
                        #include <Button.h>
                        #include <EnableInterrupt.h>
                        #include <MySensors.h>
                        
                        #define buttonPin 14            //A0
                        #define ledPin 8
                        
                        #define PULLUP true        
                        #define INVERT true        
                        #define bounceTime 20            // A debounce time of 20 milliseconds usually works well for tactile button switches.
                        #define sleepWait 1000           // Time to wait in ms before node sleeps (to be able to receive notification messages).
                        
                        volatile uint8_t interruptCount = 0;
                        volatile bool buttonChanged;
                        volatile bool buttonState;
                        long lastButton;
                        
                        Button BtnA(buttonPin, PULLUP, INVERT, bounceTime); 
                        
                        /**************************************************************************/
                        
                        void presentation(void)
                        {
                        
                        }
                        
                        /**************************************************************************/
                        
                        void setup(void)
                        {
                          Serial.begin(57600);
                          Serial.println("\nStarting test");
                          enableInterrupt(buttonPin, interrupted, CHANGE);
                          pinMode(ledPin, OUTPUT);
                          //pinMode(buttonPin, INPUT_PULLUP);             //uncomment when testing without Button library
                          lastButton = millis();
                        }
                        
                        /**************************************************************************/
                        
                        void loop(void)
                        {
                          if (buttonChanged) {
                            if (buttonState) {
                              Serial.print("\nButton has changed "); Serial.print(interruptCount); Serial.println(" times.");
                              digitalWrite(ledPin, HIGH);
                            }
                            else {
                              Serial.println("\nButton is released.");
                              digitalWrite(ledPin,LOW);
                            }
                            lastButton = millis();
                            buttonChanged = false;
                          }
                        
                          if (!buttonChanged) {
                            if (millis() > (lastButton + sleepWait)) {
                              sleepNode();
                            }
                          }
                        }
                        
                        /**************************************************************************/
                        
                        void interrupted()
                        {
                          interruptCount++;
                          buttonChanged = true;
                          //buttonState = !digitalRead(buttonPin);
                          buttonState = BtnA.read();                                      
                        }
                        
                        /**************************************************************************/
                        
                        void sleepNode()
                        {
                          Serial.println("\nSleep...");
                          wait(30);
                          sleep(0xff, 0x00, 0xff, 0x00, 0);
                          wait(30);
                        }
                        

                        Two other things caught my attention:

                        • In MY_CORE_ONLY there's no serial.begin(), makes one wait awfully long for debug output...
                        • When the node is in PWR_DOWN, my (Chinesium) USB-serial converter is unable to wake the node to upload new code. I have to keep the node awake with the button, and if that fails, shoot the bootloader again. I know the DTS-pin is functional, as the node resets when I start a serial window.
                        YveauxY 1 Reply Last reply
                        0
                        • D DavidZH

                          Hi @Yveaux,

                          I have stripped it to one button on a RC-net and one led to see what I am doing, without changing the basic flow of the sketch. Also the node has been stripped bare. I have used a DIP version with the same bootloader (8MHz internal, 1V8 BOD by GertSanders, 3V3 power source) and the outcome is exactly the same:

                          • directly waking with 2.1.1, sleeping with 2.0.0.
                          • In both tests, all button presses are registered without problems.
                          • button library has nothing to do with it. When I use a simple digitalRead(), all remains the same.
                          • when I comment out the library call for the Interrupt (line 48), nothing changes.
                          /***************************************************************************/
                          //                    MySensors definitions
                          
                          #define MY_DEBUG    
                          #define MY_CORE_ONLY      
                          
                          #define MY_BAUD_RATE 57600       // Lower as max because of 8 MHz Arduino
                          
                          #define EI_NOTEXTERNAL               // Options for the EnableInterrupt library
                          #define EI_NOTPORTB                  // to save flash space
                          #define EI_NOTPORTD
                          #define EI_ARDUINO_INTERRUPTED_PIN
                          
                          /**************************************************************************/
                          
                          #include <Button.h>
                          #include <EnableInterrupt.h>
                          #include <MySensors.h>
                          
                          #define buttonPin 14            //A0
                          #define ledPin 8
                          
                          #define PULLUP true        
                          #define INVERT true        
                          #define bounceTime 20            // A debounce time of 20 milliseconds usually works well for tactile button switches.
                          #define sleepWait 1000           // Time to wait in ms before node sleeps (to be able to receive notification messages).
                          
                          volatile uint8_t interruptCount = 0;
                          volatile bool buttonChanged;
                          volatile bool buttonState;
                          long lastButton;
                          
                          Button BtnA(buttonPin, PULLUP, INVERT, bounceTime); 
                          
                          /**************************************************************************/
                          
                          void presentation(void)
                          {
                          
                          }
                          
                          /**************************************************************************/
                          
                          void setup(void)
                          {
                            Serial.begin(57600);
                            Serial.println("\nStarting test");
                            enableInterrupt(buttonPin, interrupted, CHANGE);
                            pinMode(ledPin, OUTPUT);
                            //pinMode(buttonPin, INPUT_PULLUP);             //uncomment when testing without Button library
                            lastButton = millis();
                          }
                          
                          /**************************************************************************/
                          
                          void loop(void)
                          {
                            if (buttonChanged) {
                              if (buttonState) {
                                Serial.print("\nButton has changed "); Serial.print(interruptCount); Serial.println(" times.");
                                digitalWrite(ledPin, HIGH);
                              }
                              else {
                                Serial.println("\nButton is released.");
                                digitalWrite(ledPin,LOW);
                              }
                              lastButton = millis();
                              buttonChanged = false;
                            }
                          
                            if (!buttonChanged) {
                              if (millis() > (lastButton + sleepWait)) {
                                sleepNode();
                              }
                            }
                          }
                          
                          /**************************************************************************/
                          
                          void interrupted()
                          {
                            interruptCount++;
                            buttonChanged = true;
                            //buttonState = !digitalRead(buttonPin);
                            buttonState = BtnA.read();                                      
                          }
                          
                          /**************************************************************************/
                          
                          void sleepNode()
                          {
                            Serial.println("\nSleep...");
                            wait(30);
                            sleep(0xff, 0x00, 0xff, 0x00, 0);
                            wait(30);
                          }
                          

                          Two other things caught my attention:

                          • In MY_CORE_ONLY there's no serial.begin(), makes one wait awfully long for debug output...
                          • When the node is in PWR_DOWN, my (Chinesium) USB-serial converter is unable to wake the node to upload new code. I have to keep the node awake with the button, and if that fails, shoot the bootloader again. I know the DTS-pin is functional, as the node resets when I start a serial window.
                          YveauxY Offline
                          YveauxY Offline
                          Yveaux
                          Mod
                          wrote on last edited by
                          #37

                          @DavidZH The issue is caused because the way you use the sleep() function.
                          You 'abuse' the sleep() implementation that takes 2 interrupts (this prototype) to be able to sleep 'forever' (timeout 0).
                          However, by passing two invalid interrupt numbers, the MySensors stack translates this into a regular sleep() (this prototype) for which a timeout value of 0 means to return immediately.

                          In the core, calling either sleep(0xff, 0x00, 0xff, 0x00, 0) or sleep(0) will lead to the same call to the hwSleep() implementation, which will return immediately.

                          As a quick test, could you try replacing the code starting here:

                          if (interrupt1 != INTERRUPT_NOT_DEFINED && interrupt2 != INTERRUPT_NOT_DEFINED) {
                              // both IRQs
                              result = hwSleep(interrupt1, mode1, interrupt2, mode2, sleepingTimeMS);
                          } else if (interrupt1 != INTERRUPT_NOT_DEFINED && interrupt2 == INTERRUPT_NOT_DEFINED) {
                              // one IRQ
                              result = hwSleep(interrupt1, mode1, sleepingTimeMS);
                          } else if (interrupt1 == INTERRUPT_NOT_DEFINED && interrupt2 == INTERRUPT_NOT_DEFINED) {
                              // no IRQ
                              result = hwSleep(sleepingTimeMS);
                          }
                          

                          by

                          result = hwSleep(interrupt1, mode1, interrupt2, mode2, sleepingTimeMS);
                          

                          and see if that solves your issue?

                          http://yveaux.blogspot.nl

                          1 Reply Last reply
                          0
                          • D Offline
                            D Offline
                            DavidZH
                            wrote on last edited by DavidZH
                            #38

                            @Yveaux

                            It did! Thanks a bunch! I had a feeling it was to be found in that part of the code.

                            Strange thing is: it still returns -1 as wake up reason. And that brings me back to my original problem.

                            • When I want to add a timed sensor by setting a time as last argument, the node will not wake up when an interrupt takes place. It does register the interrupt, as the counter increases with every press. But it will only wake when the timer expires and only then display the updated counter.

                            I do see use cases for this: like an alarm-base station. With multiple inputs for the various detector loops. When the power fails (either by accident or intentionally) the base should go in low power mode to save the battery. And send a periodical heartbeat.
                            Or a scene controller in an inaccessible spot with a sensor attached.

                            edit: I've been browsing around MyHwAVR.cpp for a while, but my coding is not at that high of a level at this moment, that I can provide any useful input.

                            YveauxY 1 Reply Last reply
                            0
                            • D DavidZH

                              @Yveaux

                              It did! Thanks a bunch! I had a feeling it was to be found in that part of the code.

                              Strange thing is: it still returns -1 as wake up reason. And that brings me back to my original problem.

                              • When I want to add a timed sensor by setting a time as last argument, the node will not wake up when an interrupt takes place. It does register the interrupt, as the counter increases with every press. But it will only wake when the timer expires and only then display the updated counter.

                              I do see use cases for this: like an alarm-base station. With multiple inputs for the various detector loops. When the power fails (either by accident or intentionally) the base should go in low power mode to save the battery. And send a periodical heartbeat.
                              Or a scene controller in an inaccessible spot with a sensor attached.

                              edit: I've been browsing around MyHwAVR.cpp for a while, but my coding is not at that high of a level at this moment, that I can provide any useful input.

                              YveauxY Offline
                              YveauxY Offline
                              Yveaux
                              Mod
                              wrote on last edited by
                              #39

                              @DavidZH said in Pin change interrupt not firing with MySensors:

                              It did! Thanks a bunch! I had a feeling it was to be found in that part of the code.

                              Great!

                              Strange thing is: it still returns -1 as wake up reason. And that brings me back to my original problem.

                              Well, that function is setup to either return the interrupt number, or -1 if it didn't wake from interrupt.
                              You woke it differently, hence the return code of -1, see here.

                              • When I want to add a timed sensor by setting a time as last argument, the node will not wake up when an interrupt takes place. It does register the interrupt, as the counter increases with every press. But it will only wake when the timer expires and only then display the updated counter.

                              The actual sleep method differs whether a timeout is passed or not, see here.
                              I would have to consult the datasheet and dive into the different sleeping methods, but that probably is the reason of not waking up.

                              Again, you are using the library in an undocumented/untested way, so, unless you're able to read/modify the code yourself, I advise you to stick to the suggested use cases.

                              http://yveaux.blogspot.nl

                              1 Reply Last reply
                              0
                              Reply
                              • Reply as topic
                              Log in to reply
                              • Oldest to Newest
                              • Newest to Oldest
                              • Most Votes


                              12

                              Online

                              11.7k

                              Users

                              11.2k

                              Topics

                              113.1k

                              Posts


                              Copyright 2025 TBD   |   Forum Guidelines   |   Privacy Policy   |   Terms of Service
                              • Login

                              • Don't have an account? Register

                              • Login or register to search.
                              • First post
                                Last post
                              0
                              • MySensors
                              • OpenHardware.io
                              • Categories
                              • Recent
                              • Tags
                              • Popular