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
    #13

    In one sketch I am using pin change interrupt. But that is a node I built from scratch. I have the feeling the issues arise with the MyS function "sleep()" in combination with a set time. As long as I call sleep(0xff,0x00, 0xff, 0x00, 0);
    pin change interrupts work. As soon as I change any of the parameters, the node will not wake up anymore.

    That was on 2.0 I have yet to convert and try it on 2.1.

    As soon as I have done that, I will post the code .

    YveauxY 1 Reply Last reply
    0
    • D DavidZH

      In one sketch I am using pin change interrupt. But that is a node I built from scratch. I have the feeling the issues arise with the MyS function "sleep()" in combination with a set time. As long as I call sleep(0xff,0x00, 0xff, 0x00, 0);
      pin change interrupts work. As soon as I change any of the parameters, the node will not wake up anymore.

      That was on 2.0 I have yet to convert and try it on 2.1.

      As soon as I have done that, I will post the code .

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

      @DavidZH Just a shot in the dark, but could you try @tekka workaround from https://github.com/mysensors/MySensors/issues/725 and see if it still crashes ?

      http://yveaux.blogspot.nl

      D 1 Reply Last reply
      0
      • YveauxY Yveaux

        @DavidZH Just a shot in the dark, but could you try @tekka workaround from https://github.com/mysensors/MySensors/issues/725 and see if it still crashes ?

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

        @Yveaux I will try that as soon as I'm back from my winter sports vacation (as far as you can call lush green Alpine meadows that. At least the slopes are well maintained!). I have no access to a node and gateway now.

        For me it worked for that sketch as it's main function is reading momentary switches, either on mains power or on battery. As soon as I want to add a sensor that needs to send it's info on a set interval I needed it to be on mains power.

        But like I said, I will convert the sketch to 2.1 this week, and next week I'll give the workaround a shot.
        Keep you posted!

        1 Reply Last reply
        1
        • YveauxY Yveaux

          @idstone thanks!
          If I understand it correctly, the feedback states the pinout of arduino pro mini clones is often slightly different, especially on interrupt pins and analog.
          For analog pins this is certainly true, for interrupt pins I have not experienced this myself (yet).

          I Offline
          I Offline
          idstone
          wrote on last edited by idstone
          #16

          @Yveaux

          Hey!
          Got some news... the new charge of Arduino Pros arrived, but the problem persists. So I started more trail ' n error and got something:

          I installed the Arduino-IDE and mysensors-1.5.4-library on an manjaro-based notebook. I had to do some symlinking to get a newer version of avrdude working and now the same sketch I used before works now!

          Back to my Mac, flashing the same sketch, the node doesn't work correctly?!
          So problem seems to be the version of avrdude, which is offered by the arduino-ide?!


          I finally downgraded to IDE 1.6.8 and especially AVR Boards 1.6.8.
          Now everything works as expected .... :D

          1 Reply Last reply
          0
          • gohanG Offline
            gohanG Offline
            gohan
            Mod
            wrote on last edited by
            #17

            So it was just a bug in the latest updates of the ide and boards? I'm having probably the same problem on a mega2560

            I 1 Reply Last reply
            0
            • gohanG gohan

              So it was just a bug in the latest updates of the ide and boards? I'm having probably the same problem on a mega2560

              I Offline
              I Offline
              idstone
              wrote on last edited by
              #18

              @gohan

              I'm not familiar with your problem, but mine was, that the interrupt on pin3 didn't work as expected. So I was not able to use my new sensor as watchdog for my windows/doors. With downgrade of the Arduino-IDE AND especially AVR Boards 1.6.8 my problem is solved now and every change on that interrupt-pin is correctly recognised and send to gateway.

              gohanG 1 Reply Last reply
              0
              • I idstone

                @gohan

                I'm not familiar with your problem, but mine was, that the interrupt on pin3 didn't work as expected. So I was not able to use my new sensor as watchdog for my windows/doors. With downgrade of the Arduino-IDE AND especially AVR Boards 1.6.8 my problem is solved now and every change on that interrupt-pin is correctly recognised and send to gateway.

                gohanG Offline
                gohanG Offline
                gohan
                Mod
                wrote on last edited by
                #19

                @idstone if you don't mind, please take a look at last line of my code https://forum.mysensors.org/topic/5807/interrupt-and-sleep

                I 1 Reply Last reply
                0
                • gohanG gohan

                  @idstone if you don't mind, please take a look at last line of my code https://forum.mysensors.org/topic/5807/interrupt-and-sleep

                  I Offline
                  I Offline
                  idstone
                  wrote on last edited by
                  #20

                  @gohan

                  Hi again. I can confirm, that I got similar problems... the state of the interrupt pin wasn't correctly recognized, too.
                  May be You could try downgrading Arduino-IDE and (very important) avr boards (1.6.8) ?!

                  elysionE gohanG 2 Replies Last reply
                  0
                  • I idstone

                    @gohan

                    Hi again. I can confirm, that I got similar problems... the state of the interrupt pin wasn't correctly recognized, too.
                    May be You could try downgrading Arduino-IDE and (very important) avr boards (1.6.8) ?!

                    elysionE Offline
                    elysionE Offline
                    elysion
                    wrote on last edited by
                    #21

                    I'll see if I can find time today or tomorrow to try this. Also might be interesting to see whether it would be possible to get around the issue using Platform.io.

                    1 Reply Last reply
                    0
                    • I idstone

                      @gohan

                      Hi again. I can confirm, that I got similar problems... the state of the interrupt pin wasn't correctly recognized, too.
                      May be You could try downgrading Arduino-IDE and (very important) avr boards (1.6.8) ?!

                      gohanG Offline
                      gohanG Offline
                      gohan
                      Mod
                      wrote on last edited by
                      #22

                      @idstone
                      I'll give it a try maybe on another computer just to be safe

                      I 1 Reply Last reply
                      0
                      • gohanG gohan

                        @idstone
                        I'll give it a try maybe on another computer just to be safe

                        I Offline
                        I Offline
                        idstone
                        wrote on last edited by
                        #23

                        @gohan

                        any news?

                        gohanG 1 Reply Last reply
                        0
                        • elysionE Offline
                          elysionE Offline
                          elysion
                          wrote on last edited by
                          #24

                          I updated my sensors to use v2 of the MySensors library and this issue went away. Used the same board with same fuses and same Arduino IDE and boards file version. Imho this would suggest that there is an issue in MySensors.

                          Before migrating to v2 I ran some tests using a button in place of the PIR sensor and it seemed that using a short timeout for the gw.sleep would work, but a longer would not. Did not dig deeper into this though, so might be that it just seemed to work better.

                          1 Reply Last reply
                          0
                          • I idstone

                            @gohan

                            any news?

                            gohanG Offline
                            gohanG Offline
                            gohan
                            Mod
                            wrote on last edited by
                            #25

                            @idstone

                            No, I tried different ways without success and I am waiting for new arduino boards to arrive and start testing from there, probably my MEGA isn't the right platform for these tests

                            1 Reply Last reply
                            0
                            • 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
                                          Reply
                                          • Reply as topic
                                          Log in to reply
                                          • Oldest to Newest
                                          • Newest to Oldest
                                          • Most Votes


                                          13

                                          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