Direct pairing of two nodes implementation



  • I've been looking for some time for implementation of pairing two nodes to each other to be able to send messages directly omitting controller. I've seen some other posts suggesting to add this functionality to mysensors core, and proposing base scheme of how it should look like. After some reading I realized that it is not hard to write such code by myself. So I tried my best and now I have what seems to be a working code for two test nodes and a gateway. One of the nodes is modified sketch for binary button the other one is simple one channel relay. I'm not a professional programmer, so code can be optimized more, I guess, and maybe rewritten in better manner.

    It's primarily useful for direct communication between a button node (a light switch, or motion sensor) and some relay or other actuator. The key feature is the ability to avoid necessity of controller presence for some simple usage like light switching. Also it provides better reliability in case of controller failure.

    Both nodes must have specific pairing button which also serves as "Clear EEPROM" button if pressed before node is powered on. So basically when pairing button is pressed node enters pairing mode for required amount of time (in my case 10 seconds) and sends special message to controller which collects its node and children id's and then waits for 10 seconds for another node to send request in which case it then sends id's vice versa. My code is written only for single button/relay nodes, but it can be made to pair specific child sensors on every node.

    Let me know what do you think of it, and if it's useful to anybody.

    Binary button code:

    // Enable debug prints to serial monitor
    #define MY_DEBUG
    
    // Enable and select radio type attached
    #define MY_RADIO_NRF24
    
    #include <MySensors.h>
    
    #define CHILD_ID 3
    
    #define SET_BUTTON_PIN 5// Arduino Digital I/O pin for button/reed switch
    #define BUTTON_PIN 3
    
    MyMessage msg(CHILD_ID, V_TRIPPED);
    bool firstLoop = 1;
    bool pairing = 0;
    int node_pair=-1;
    int sensor_pair=-1;
    bool paired=0;
    bool lastButState=0;
    unsigned long timer1 = 0;
    int debounceTime = 1000;
    unsigned long timer2 = 0;
    int pairWaitTime = 10000;
    unsigned long timer3;
    int holdTime = 3000;
    
    //Time counter function instead of delay
    boolean isTime(unsigned long *timeMark, unsigned long timeInterval) {
        if (millis() - *timeMark >= timeInterval) {
            *timeMark = millis();
            return true;
        }
        return false;
    }
    
    void before()
    {
      Serial.begin(115200);
      Serial.println("Starting node...");
      pinMode(SET_BUTTON_PIN, INPUT_PULLUP); //Eneble button pin for detect  request for resetting node's EEPROM
      bool clr = digitalRead(SET_BUTTON_PIN);
      if (!clr) {
        Serial.println("Clearing EEPROM");
        for (int i=0; i<EEPROM_LOCAL_CONFIG_ADDRESS; i++) {
        hwWriteConfig(i,0xFF);
        }
        //Clearing paired nodes address and paired state
        for (int i=245; i<=255; i++) {
        hwWriteConfig(i,0xFF);
        }
        Serial.println("EEPROM is clean");
      }
      //Reading pairing state from EEPROM and then reading paired nodes id's if paired
      paired = loadState(255);
      Serial.print("Paired state: ");
      Serial.println(paired);
        if (paired) {
        node_pair = loadState(245);
        sensor_pair = loadState(246);
        Serial.print("Paired node: ");
        Serial.print(node_pair);
        Serial.print("-");
        Serial.println(sensor_pair);
      }
    }
    
    void setup()
    {
    	// Setup the buttons
    	pinMode(BUTTON_PIN, INPUT_PULLUP);
    }
    
    void presentation()
    {
    	// Send the sketch version information to the Controller in case node is'nt paired
    	if (!paired) {
        sendSketchInfo("Binary paired button", "1.0");
        present(CHILD_ID, S_MOTION);
    	}
    
    }
    
    // Loop will iterate on changes on the BUTTON_PINs
    void loop()
    {
      bool butState = !digitalRead(BUTTON_PIN);
      if (!paired) {
        if (firstLoop) {
          timer3 = millis(); //Starting delay for pairing button on first loop
        }
        //If pairing button hold for required amount of seconds initiate pairing process
        if (!digitalRead(SET_BUTTON_PIN)) {
          if(isTime(&timer3, holdTime)){
            Serial.println("Pair button pressed");
            pair();
            if (!paired) {
              Serial.println("Pairing timeout");
            }
          }
        } else {
          timer3 = millis();
        }
      }
      //Processing main button press
      if (butState != lastButState) {
        if (butState) {
          lastButState = butState;
          if (isTime(&timer1, debounceTime)) {
            Serial.println("Button pressed");
            //If node is paired to other node send message directly to paired node omitting controller
            if (paired) {
             MyMessage msg(sensor_pair, V_TRIPPED);
             msg.setDestination(node_pair);
             Serial.println("Sent message to paired node");
             int retry = 0;
             while(!send(msg.set(1)) || retry == 10) {
              wait(100);
              send(msg.set(1));
              retry++;
             }
            } else {
              //If not, send message to controller
             send(msg.set(1));
             Serial.println("Sent message to controller");
            }
          }
    
        } else {
          if (!paired) {
            send(msg.set(0));
          }
          lastButState = butState;
        }
      }
    	firstLoop = 0; //Counter for first loop just to know from where to start timer for pairing button hold
    }
    
    //Pairing function
    void pair()
    {
      Serial.println("Entering pairing mode");
      pairing = 1;
      MyMessage pairMsg(244, V_VAR1); //I'm using specific CHILD_ID to be able to filter out pairing requests
      send(pairMsg.set("Pair me."), true); //Send any message to gateway
      Serial.println("Pair request sent");
      //Then we wait some time to recieve paired node id (in my case 10 seconds)
      timer2 = millis();
      while (!isTime(&timer2, pairWaitTime)) {
        wait(1);
        if (paired) {
          Serial.println("Successfully paired");
          break;
        }
      }
      pairing = 0;
    }
    
    void receive(const MyMessage &message)
    {
      //While in pairing mode we'll only process pairing messages
      if (pairing) {
        if (!message.sender) {
          if (message.type == V_VAR2) {
            node_pair = atoi(strtok(message.getString(), ";")); //Deconstructing string from gateway, wich must contain id of paired node
            Serial.println(node_pair);
            sensor_pair = atoi(strtok(NULL, ";")); //...and id of specific sensor on that node, in case there are more than one
            Serial.print("Paired with: ");
            Serial.println(node_pair);
            Serial.println(sensor_pair);
            paired=1;
            saveState(255, 1);
          }
        }
      }
    }
    

    Relay actuator code:

    // Enable debug prints to serial monitor
    #define MY_DEBUG
    
    // Enable and select radio type attached
    #define MY_RADIO_NRF24
    //#define MY_RADIO_RFM69
    
    // Enable repeater functionality for this node
    //#define MY_REPEATER_FEATURE
    
    #include <MySensors.h>
    
    
    #define CHILD_ID 1
    #define RELAY_PIN  5  // Arduino Digital I/O pin number for relay
    #define RELAY_ON 1  // GPIO value to write to turn on attached relay
    #define RELAY_OFF 0 // GPIO value to write to turn off attached relay
    #define SET_BUTTON_PIN 3
    
    bool relayState;
    bool firstLoop = 1;
    bool pairing = 0;
    int node_pair=-1;
    int sensor_pair=-1;
    bool paired=0;
    bool lastButState=0;
    unsigned long timer1 = 0;
    int debounceTime = 100;
    unsigned long timer2 = 0;
    int pairWaitTime = 10000;
    unsigned long timer3;
    int holdTime = 3000;
    unsigned long timer4;
    int resendTime = 1500;
    
    MyMessage msg(CHILD_ID,V_LIGHT);
    
    
    //Time counter function instead delay
    boolean isTime(unsigned long *timeMark, unsigned long timeInterval) {
        if (millis() - *timeMark >= timeInterval) {
            *timeMark = millis();
            return true;
        }
        return false;
    }
    
    void before ()
    {
      Serial.begin(115200);
      Serial.println("Starting...");
      pinMode(SET_BUTTON_PIN, INPUT_PULLUP);
      bool clr = digitalRead(SET_BUTTON_PIN);
      if (!clr) {
        Serial.println("Clearing EEPROM");
        for (int i=0; i<EEPROM_LOCAL_CONFIG_ADDRESS; i++) {
        hwWriteConfig(i,0xFF);
        }
        //Clearing paired nodes address and paired state
        for (int i=245; i<=255; i++) {
        hwWriteConfig(i,0xFF);
        }
        Serial.println("EEPROM is clean");
      }
      //Reading pairing state from EEPROM and then reading paired nodes id's if paired
      paired = loadState(255);
      Serial.print("Paired state: ");
      Serial.println(paired);
      if (paired) {
        node_pair = loadState(245);
        sensor_pair = loadState(246);
        Serial.print("Paired node: ");
        Serial.print(node_pair);
        Serial.print("-");
        Serial.println(sensor_pair);
      }
      pinMode(RELAY_PIN, OUTPUT);
      digitalWrite(RELAY_PIN, 1);
      delay(1000);
      digitalWrite(RELAY_PIN, 0);
      // Set relay to last known state (using eeprom storage)
      relayState = loadState(CHILD_ID);
      digitalWrite(RELAY_PIN, relayState ? RELAY_ON : RELAY_OFF);
    }
    void setup()
    {
    
    }
    
    void presentation()
    {
      // Send the sketch version information to the gateway and Controller
      sendSketchInfo("Relay", "1.0");
    
      present(CHILD_ID, S_LIGHT, "Test light", true);
    
      // Send saved state to gateway (using eeprom storage)
      send(msg.set(relayState),true);
    }
    
    void loop()
    {
      if (!paired) {
        if (firstLoop) {
          timer3 = millis(); //Starting delay for pairing button on first loop
        }
        //If pairing button hold for required amount of seconds initiate pairing process
        if (!digitalRead(SET_BUTTON_PIN)) {
          if(isTime(&timer3, holdTime)){
            Serial.println("Pair button pressed");
            pair();
          }
        } else {
          timer3 = millis();
        }
      }
      firstLoop = 0; //Counter for first loop just to know from where to start timer for pairing button hold
    }
    
    void pair()
    {
    Serial.println("Entering pairing mode");
      pairing = 1;
      MyMessage pairMsg(244, V_VAR1); //I'm using specific CHILD_ID to be able to filter out pairing requests
      send(pairMsg.set("Pair me."), true); //Send any message to gateway
      Serial.println("Pair request sent");
      //Then we wait some time to recieve paired node id (in my case 10 seconds)
      timer2 = millis();
      while (!isTime(&timer2, pairWaitTime)) {
        wait(1);
        if (paired) {
          Serial.println("Successfully paired");
          break;
        }
      }
      pairing = 0;
      Serial.println("Pairing timeout");
    }
    
    void receive(const MyMessage &message) {
      //While in pairing mode we'll only process pairing messages
      if (pairing) {
        if (!message.sender) {
          if (message.type == V_VAR2) {
            node_pair = atoi(strtok(message.getString(), ";")); //Deconstructing string from gateway, wich must contain id of paired node
            Serial.println(node_pair);
            sensor_pair = atoi(strtok(NULL, ";")); //...and id of specific sensor on that node, in case there are more than one
            Serial.print("Paired with: ");
            Serial.println(node_pair);
            Serial.println(sensor_pair);
            paired=1;
            saveState(255, 1);
          }
        }
      } else { //Process mesage from gateway
        if (message.type == V_LIGHT && !message.sender) {
          // Change relay state
          relayState = message.getBool();
          digitalWrite(RELAY_PIN, relayState ? RELAY_ON : RELAY_OFF);
          // Store state in eeprom
          saveState(CHILD_ID, relayState);
          // Write some debug info
          Serial.print("Incoming change. New status:");
          Serial.println(relayState);
        } else if (message.type == V_TRIPPED && message.sender == node_pair) { //Process message sent directly from paired node
          if(isTime(&timer4, resendTime)) {
            digitalWrite(RELAY_PIN, relayState ? RELAY_OFF : RELAY_ON);
            relayState = relayState ? 0 : 1;
            saveState(CHILD_ID, relayState);
            send(msg.set(relayState)); //Send changed state to controller, because paired button won't do it
          }
        }
      }
    }
    

    Gateway code:

    // Enable debug prints to serial monitor
    #define MY_DEBUG
    
    
    // Enable and select radio type attached
    #define MY_RADIO_NRF24
    //#define MY_RADIO_RFM69
    
    // Set LOW transmit power level as default, if you have an amplified NRF-module and
    // power your radio separately with a good regulator you can turn up PA level.
    #define MY_RF24_PA_LEVEL RF24_PA_MAX
    
    // Enable serial gateway
    #define MY_GATEWAY_SERIAL
    
    // Define a lower baud rate for Arduino's running on 8 MHz (Arduino Pro Mini 3.3V & SenseBender)
    #if F_CPU == 8000000L
    #define MY_BAUD_RATE 38400
    #endif
    
    // Set blinking period
    #define MY_DEFAULT_LED_BLINK_PERIOD 300
    
    #include <MySensors.h>
    
    unsigned long currentTime = 0;
    int waitTime = 10000;
    int node1_addr = 0;
    bool node1_addr_present = 0;
    int sensor1_addr = 0;
    char str1[8];
    char str2[8];
    bool pairing = 0;
    
    //Messages for answering pairing requests
    MyMessage msg(254,V_VAR2);
    MyMessage msg2(254,V_VAR2);
    
    //Time counter function instead delay
    boolean isTime(unsigned long *timeMark, unsigned long timeInterval) {
        if (millis() - *timeMark >= timeInterval) {
            *timeMark = millis();
            return true;
        }
        return false;
    }
    
    void setup()
    {
    	// Setup locally attached sensors
    }
    
    void loop()
    {
      //We are keeping ids of pairing nodes only for 10 seconds while pairing
     if(isTime(&currentTime, waitTime)) {
      node1_addr = 0;
      node1_addr_present = 0;
     }
    }
    void receive(const MyMessage &message) {
      //I used specific message type for filtering out pairing request
      if (message.type == V_VAR1) {
        Serial.print("Incoming message. Node - ");
        Serial.print(message.sender);
        Serial.print(message.sensor);
        Serial.println(message.getString());
        //Check if there was any pairing requests for last 10 seconds, if no begin pairing process
        if (!node1_addr_present) {
          currentTime = millis();
          node1_addr = message.sender;
          sensor1_addr = message.sensor;
          node1_addr_present = 1;
        }
        //If there is request from another node send back pairing node ids to each other
        else if (message.sender != node1_addr && message.sensor != sensor1_addr) {
          snprintf(str2, 7, "%d;%d", message.sender, message.sensor); //Construct message string with node and sensor ids of second node
          snprintf(str1, 7, "%d;%d", node1_addr, sensor1_addr); //...and the first one
          //print some debug info
          Serial.print("First address: ");
          Serial.print(str1);
          Serial.print("Second address: ");
          Serial.print(str2);
          //Send answer to nodes
          msg.setDestination(message.sender);
          send(msg.set(str1), true);
          wait(500);
          Serial.println("Sent message to second address");
          msg2.setDestination(node1_addr);
          send(msg2.set(str2), true);
          wait(500);
          Serial.println("Sent message to first address");
          node1_addr = 0;
          sensor1_addr = 0;
          node1_addr_present = 0;
          Serial.println("Pairing finished");
        }
      }
    }
    


  • Finally got it working, and starting to understand it, had to change a few things, perhaps because its on latest version of mysensors, or possible because of old values in eproms.

    Thanks for sharing, want to make a few changes or additions to suit my needs will share more as I have something working.



  • @rfm69 It was more a proof of concept. I didn't really use it since I wrote it. But then it worked for my testing quiet well. I'd like to know, what you had to change to make it work on your setup. And I am happy that someone made use of my little effort ๐Ÿ™‚



  • @monte ๐Ÿ™‚ I was wondering if you'd used it or what your experience of it was. I'm also just enjoying learning by doing... but wanted to see the node to node communication working and more easily configurable. I'd like to configure this from the controller also perhaps.

    I've moved much of the functionality to its own class so that it can be more easily added to nodes. Heres what I've got so far.

    I used avdweb_Switch.h to simplify and abstract a little the button press/etc.

    I'd still like to clear up a little and add a few more things, like having multiply nodes paired together etc.

    Its still pretty much your origional code.

    There was a small error that both nodeid & sensorid had to be different from the master and slave paired node... that was in gateway.ico

    Gate Way.ico

    /**
    * The MySensors Arduino library handles the wireless radio link and protocol
    * between your home built sensors/actuators and HA controller of choice.
    * The sensors forms a self healing radio network with optional repeaters. Each
    * repeater and gateway builds a routing tables in EEPROM which keeps track of the
    * network topology allowing messages to be routed to nodes.
    *
    * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
    * Copyright (C) 2013-2015 Sensnology AB
    * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
    *
    * Documentation: http://www.mysensors.org
    * Support Forum: http://forum.mysensors.org
    *
    * This program is free software; you can redistribute it and/or
    * modify it under the terms of the GNU General Public License
    * version 2 as published by the Free Software Foundation.
    *
    *******************************
    *
    * DESCRIPTION
    * The ArduinoGateway prints data received from sensors on the serial link.
    * The gateway accepts input on seral which will be sent out on radio network.
    *
    * The GW code is designed for Arduino Nano 328p / 16MHz
    *
    * Wire connections (OPTIONAL):
    * - Inclusion button should be connected between digital pin 3 and GND
    * - RX/TX/ERR leds need to be connected between +5V (anode) and digital pin 6/5/4 with resistor 270-330R in a series
    *
    * LEDs (OPTIONAL):
    * - To use the feature, uncomment any of the MY_DEFAULT_xx_LED_PINs
    * - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved
    * - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly
    * - ERR (red) - fast blink on error during transmission error or recieve crc error
    *
    */
    
    // Enable debug prints to serial monitor
    #define MY_DEBUG
    
    
    // Enable and select radio type attached
    //#define MY_RADIO_NRF24
    //#define MY_RADIO_NRF5_ESB
    #define MY_RADIO_RFM69
    #define MY_RFM69_FREQUENCY RFM69_433MHZ
    //#define MY_RADIO_RFM95
    
    // Set LOW transmit power level as default, if you have an amplified NRF-module and
    // power your radio separately with a good regulator you can turn up PA level.
    #define MY_RF24_PA_LEVEL RF24_PA_LOW
    
    // Enable serial gateway
    #define MY_GATEWAY_SERIAL
    
    // Define a lower baud rate for Arduino's running on 8 MHz (Arduino Pro Mini 3.3V & SenseBender)
    #if F_CPU == 8000000L
    #define MY_BAUD_RATE 38400
    #endif
    
    // Enable inclusion mode
    #define MY_INCLUSION_MODE_FEATURE
    // Enable Inclusion mode button on gateway
    //#define MY_INCLUSION_BUTTON_FEATURE
    
    // Inverses behavior of inclusion button (if using external pullup)
    //#define MY_INCLUSION_BUTTON_EXTERNAL_PULLUP
    
    // Set inclusion mode duration (in seconds)
    #define MY_INCLUSION_MODE_DURATION 60
    // Digital pin used for inclusion mode button
    //#define MY_INCLUSION_MODE_BUTTON_PIN  3
    
    // Set blinking period
    #define MY_DEFAULT_LED_BLINK_PERIOD 300
    
    // Inverses the behavior of leds
    //#define MY_WITH_LEDS_BLINKING_INVERSE
    
    // Flash leds on rx/tx/err
    // Uncomment to override default HW configurations
    //#define MY_DEFAULT_ERR_LED_PIN 4  // Error led pin
    //#define MY_DEFAULT_RX_LED_PIN  6  // Receive led pin
    //#define MY_DEFAULT_TX_LED_PIN  5  // the PCB, on board LED
    
    #include <MySensors.h>
    
    unsigned long currentTime = 0;
    int waitTime = 10000;
    int masterNodeAddr = 0;
    bool masterNodeAddrPresent = 0;
    int masterSensorAddr = 0;
    char str1[8];
    char str2[8];
    bool pairing = 0;
    
    //Messages for answering pairing requests
    MyMessage msg(254,V_VAR2);
    MyMessage msg2(254,V_VAR2);
    
    //Time counter function instead delay
    boolean isTimeUp(unsigned long *timeMark, unsigned long timeInterval) {
        if (millis() - *timeMark >= timeInterval) {
            *timeMark = millis();
            return true;
        }
        return false;
    }
    
    void setup()
    {
    	// Setup locally attached sensors
    }
    
    void loop()
    {
      //We are keeping ids of pairing nodes only for 10 seconds while pairing
     if(isTimeUp(&currentTime, waitTime)) {
      masterNodeAddr = 0;
      masterNodeAddrPresent = 0;
     }
    }
    
    void receive(const MyMessage &message) {
      //I used specific message type for filtering out pairing request
      if (message.type == V_VAR1) {
        Serial.print("Incoming message. Node - ");
        Serial.print(message.sender); Serial.print("-");
        Serial.print(message.sensor);
        Serial.println(message.getString());
        // If we had already a pairing requests within the last 10 seconds ? Then lets setup ready to pair
        if (!masterNodeAddrPresent) {
          currentTime = millis();
          masterNodeAddr = message.sender;
          masterSensorAddr = message.sensor;
          masterNodeAddrPresent = 1;
        }
        // Listening for the second node slave to request pairing.
        else if (message.sender != masterNodeAddr ) { //&& message.sensor != masterSensorAddr) {
          //Construct message string with node and sensor ids 
          snprintf(str2, 7, "%d;%d", message.sender, message.sensor);
          snprintf(str1, 7, "%d;%d", masterNodeAddr, masterSensorAddr); 
          Serial.print("First address: ");  Serial.print(str1); Serial.print("Second address: "); Serial.println(str2);
          // Send answer to nodes
          msg.setDestination(message.sender);
          send(msg.set(str1), true);
          wait(500);
          Serial.println("Sent message to second address");
          msg2.setDestination(masterNodeAddr);
          send(msg2.set(str2), true);
          wait(500);
          Serial.println("Sent message to first address");
          masterNodeAddr = 0;
          masterSensorAddr = 0;
          masterNodeAddrPresent = 0;
          Serial.println("Pairing finished");
        }
      }
    }
    

    Button.ico

    /*
     * Description on node
     */
    
    // Enable debug prints to serial monitor
    #define MY_DEBUG
    
    // Enable and select radio type attached
    #define MY_RADIO_RFM69 
    #define MY_RFM69_FREQUENCY RFM69_433MHZ
    
    #include <MySensors.h>
    
    #define CHILD_ID 3
    
    #include <avdweb_Switch.h>
    #include "pair.h"
    
    #define SET_BUTTON_PIN 5 // Arduino Digital I/O pin for button/reed switch
    #define BUTTON_PIN 4  // Normal button PIN
    Switch button = Switch(BUTTON_PIN);
    
    PairLocal pairLocal = PairLocal(SET_BUTTON_PIN);
    
    
    // I think send to controller the button regardless if its paired directly 
    void presentation()
    {
      // Send the sketch version information to the Controller in case node is'nt paired
      //if (!paired) {
        sendSketchInfo("Binary paired button", "1.0");
        present(CHILD_ID, S_MOTION);
      //}
    }
    
    void before()
    {
      pairLocal.before();
    
      //optionally pass function in, This button node won't recieve messages to do something from a slave
      uint16_t ptr = &arryChange;
      pairLocal.setParedMessageRecievedFunction(ptr);
    }
    
    // Function called when a paired master node sends a message
    void arryChange()
    {
    
    }
    
    void setup()
    {
      pairLocal.setup();
    }
    
    void loop()
    {
      pairLocal.loop();
    
      // Process our own sensors additional button 
      button.poll();
      // button was pushed
      if (button.pushed()) {   
        pairLocal.sendPairedMesage();
        } else {
       // if (!paired) {
          //MyMessage msg(CHILD_ID, V_TRIPPED);
          //send(msg.set(0)); // NOT SURE IF WE NEED THIS ????
    //    }
      } 
    }
    
    
    void receive(const MyMessage &message)
    {
      pairLocal.receive(message);
    
      // Do any additional processing here.
    }
    

    Relay.ico

    /*
     * Description on node
     */
    
    // Enable debug prints to serial monitor
    #define MY_DEBUG
    
    // Enable and select radio type attached
    #define MY_RADIO_RFM69 
    #define MY_RFM69_FREQUENCY RFM69_433MHZ
    
    #include <MySensors.h>
    
    #define CHILD_ID 1
    #define RELAY_PIN  5  // Arduino Digital I/O pin number for relay
    #define RELAY_ON 1  // GPIO value to write to turn on attached relay
    #define RELAY_OFF 0 // GPIO value to write to turn off attached relay
    #define SET_BUTTON_PIN 4
    
    bool relayState;
    
    MyMessage msg(CHILD_ID,V_LIGHT);
    
    #include <avdweb_Switch.h>
    #include "pair.h"
    
    PairLocal pairLocal = PairLocal(SET_BUTTON_PIN);
    
    // I think send to controller the button regardless if its paired directly 
    void presentation()
    {
      // Send the sketch version information to the gateway and Controller
      sendSketchInfo("Relay", "1.0");
    
      present(CHILD_ID, S_LIGHT, "Test light", true);
    
      // Send saved state to gateway (using eeprom storage)
      send(msg.set(relayState),true);
    }
    
    void before()
    {
      pairLocal.before();
    
      // Setup the relay
      pinMode(RELAY_PIN, OUTPUT);
      digitalWrite(RELAY_PIN, 1);
      delay(1000);
      digitalWrite(RELAY_PIN, 0);
    
      // Set relay to last known state (using eeprom storage)
      relayState = loadState(CHILD_ID);
      digitalWrite(RELAY_PIN, relayState ? RELAY_ON : RELAY_OFF);
    }
    
    void setup()
    {
      pairLocal.setup();
    
      //optionally pass function in, Relay change state
      uint16_t ptr = &processPairMessageFromMaster;
      pairLocal.setParedMessageRecievedFunction(ptr);
    }
    
    void loop()
    {
      pairLocal.loop();
    }
    
    void receive(const MyMessage &message)
    {
      pairLocal.receive(message);
    
      // Additional process message from Gateway
      if (message.type == V_LIGHT && !message.sender) {
          // Change relay state
          relayState = message.getBool();
          digitalWrite(RELAY_PIN, relayState ? RELAY_ON : RELAY_OFF);
          // Store state in eeprom
          saveState(CHILD_ID, relayState);
          // Write some debug info
          Serial.print("Incoming change. New status:");
          Serial.println(relayState);
        } 
    }
    
    // Function called when a paired master node sends a message
    void processPairMessageFromMaster()
    {
    	Serial.println("Relay changed state by master node");
    	digitalWrite(RELAY_PIN, relayState ? RELAY_OFF : RELAY_ON);
        relayState = relayState ? 0 : 1;
    }
    


  • @rfm69 Thank you for the tip about an error, it was really a wrong condition to check.

    As for the button sending message directly to paired node but not to controller I made this intentionally. In my use scenario you have simple binary button that sends a message when it pressed. This message doesn't describe "on" or "off" state, it's receiving part who manages the logic of flipping binary state. So if you chose to send message both to paired node and to controller it will arrive to destination node 2 times. At least thats how my controller (domoticz) works. It definitely will mess up your switching logic on destination node, or you will need to write the logic on both node and controller, but message will still be send second time without any purpose. So I chose that button will communicate with controller only if it's not paired, and the paired node will send it's state to controller itself (if message received form paired node).

    If you don't mind, could you publish your "avdweb_Switch.h" when you finish your work? So the community could benefit from it ๐Ÿ™‚



  • @monte I didn't think, or worry to much yet about the exact logic of buttons or what would happen with confused logic between controller yet. I just commented some things out for testing so I could get it working again, after I had refactored it into the separate class. I think I agree with you and what you said, but have to get my head around it.

    The avdweb_switch.h code, it isn't mine, but I took it from link text. I'll document and finish up the code a little more, and of course happy to share everything.

    I've been trying the NodeManager code as well, which made me want to modualize your code a little, because well I get confused easily and need things to look simple.



  • I updated a few things, perhaps not all working properly yet, but have put a git page up at https://github.com/dudman8/MysensorsPairNodeLocal

    Added registering multiply pairings, flashing led to indicate if nodes are in pairing mode etc. Still needs some work though, any feed back ๐Ÿ™‚ welcome.

    Id like to add some messaging so controller could query the nodes and how they are connected, and configure them also from the controller, but don't know yet how to to this with templates and custom buttons etc in mycontroller.


Log in to reply
 

Suggested Topics

66
Online

11.4k
Users

11.1k
Topics

112.7k
Posts