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. Development
  3. Node to Node communication

Node to Node communication

Scheduled Pinned Locked Moved Development
22 Posts 3 Posters 220 Views 3 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.
  • BearWithBeardB BearWithBeard

    Hey, APL2017. In this example, pcMsg is the arbitrarily choosen name of a MyMessage class instance (apidocs), like

    #define CHILD_ID 0
    #define CHILD_ID_TEMP 42
    MyMessage pcMsg(CHILD_ID, V_VAR1);
    MyMessage temperatureMessage(CHILD_ID_TEMP, V_TEMP);
    

    setDestination(destinationId) (apidocs) defines with which node you want to communicate. destinationId is the ID of the target node.

    Accordingly, setSensor(sensorId) (apidocs) defines to which sensor ID on the target node this message should be mapped to.

    set(floatValue, decimals) (apidocs) defines which float value should be sent with the given number of decimal places. Note that the set() function has a bunch of overloads for different value types - only floats accept the decimals parameter, for obvious reasons.

    Summarized, send(pcMsg.setDestination(1).setSensor(101).set(temperature,1)) attempts to send a MyMessage of type V_VAR1 with the value of the temperature variable, trimmed to one decimal place, to sensor ID 101 on node ID 1.

    The conditions in the receive() function on the destination node then checks, that the incoming message is of type V_VAR1 and its sensor ID is 101 before it prints the received variable.

    Here's a compact list of all the relevant getters and setters to manipulate a MyMessage object. For a more detailed overview, refer to the apidocs page for the MyMessage class.

    A Offline
    A Offline
    APL2017
    wrote on last edited by
    #3

    @BearWithBeard Thank you! Will go through information you provided and try to implement shortly

    1 Reply Last reply
    0
    • A Offline
      A Offline
      APL2017
      wrote on last edited by
      #4
      This post is deleted!
      1 Reply Last reply
      0
      • A Offline
        A Offline
        APL2017
        wrote on last edited by
        #5
        This post is deleted!
        1 Reply Last reply
        0
        • BearWithBeardB BearWithBeard

          Hey, APL2017. In this example, pcMsg is the arbitrarily choosen name of a MyMessage class instance (apidocs), like

          #define CHILD_ID 0
          #define CHILD_ID_TEMP 42
          MyMessage pcMsg(CHILD_ID, V_VAR1);
          MyMessage temperatureMessage(CHILD_ID_TEMP, V_TEMP);
          

          setDestination(destinationId) (apidocs) defines with which node you want to communicate. destinationId is the ID of the target node.

          Accordingly, setSensor(sensorId) (apidocs) defines to which sensor ID on the target node this message should be mapped to.

          set(floatValue, decimals) (apidocs) defines which float value should be sent with the given number of decimal places. Note that the set() function has a bunch of overloads for different value types - only floats accept the decimals parameter, for obvious reasons.

          Summarized, send(pcMsg.setDestination(1).setSensor(101).set(temperature,1)) attempts to send a MyMessage of type V_VAR1 with the value of the temperature variable, trimmed to one decimal place, to sensor ID 101 on node ID 1.

          The conditions in the receive() function on the destination node then checks, that the incoming message is of type V_VAR1 and its sensor ID is 101 before it prints the received variable.

          Here's a compact list of all the relevant getters and setters to manipulate a MyMessage object. For a more detailed overview, refer to the apidocs page for the MyMessage class.

          A Offline
          A Offline
          APL2017
          wrote on last edited by
          #6

          @BearWithBeard I took my typical water leak detection node, which sends leak flag to controller and added request to also send leak flag to node 15, sensor 10 (the last set below) , but immediately this node stopped reporting leak to controller. What am I doing wrong? Do I need to define dedicated MyMessage statement for sharing data with node?

          #define MY_DEBUG 
          #define MY_RADIO_RF24
          #include <MySensors.h>
          
          #define LEAK_1_CHILD_ID 1
          #define LEAK_1_PIN  5
          
          bool LEAK_1;
          bool last_LEAK_1;
          
          MyMessage msg_LEAK_1(LEAK_1_CHILD_ID,V_TRIPPED);
          
          void setup()  
          {  
            pinMode(LEAK_1_PIN,INPUT_PULLUP);
          }
          void presentation() {
            sendSketchInfo("Water Leak", "1.0");
            present(LEAK_1_CHILD_ID, S_DOOR); 
          }
          
          void loop() 
          {
           LEAK_1 =digitalRead(LEAK_1_PIN);
           if (LEAK_1 != last_LEAK_1) 
           {
           send(msg_LEAK_1.set(LEAK_1));
           send(msg_LEAK_1.setDestination(15).setSensor(10).set(LEAK_1));
           last_LEAK_1 = LEAK_1;
           }
          }
          
          1 Reply Last reply
          0
          • boumB Offline
            boumB Offline
            boum
            wrote on last edited by
            #7

            The destination is a state inside the MyMessage object. You need to reset it every time you change destination, from controller to the other node and back:

             send(msg_LEAK_1.setDestination(0).setSensor(LEAK_1_CHILD_ID).set(LEAK_1));
             send(msg_LEAK_1.setDestination(15).setSensor(10).set(LEAK_1));
            
            

            Or you could create a second message object for the node to node communication:

            MyMessage msg_LEAK_1(LEAK_1_CHILD_ID,V_TRIPPED);
            MyMessage msg_LEAK_to_15(10,V_TRIPPED);
            
            void setup()  
            {  
              pinMode(LEAK_1_PIN,INPUT_PULLUP);
            
              // Set destination only once, sensor is set on constructor above
              msg_LEAK_to_15.setDestination(15);
            }
            //[...]
             if (LEAK_1 != last_LEAK_1) 
             {
               send(msg_LEAK_1.set(LEAK_1));
               send(msg_LEAK_to_15.set(LEAK_1));
               last_LEAK_1 = LEAK_1;
             }
            
            A 1 Reply Last reply
            1
            • boumB boum

              The destination is a state inside the MyMessage object. You need to reset it every time you change destination, from controller to the other node and back:

               send(msg_LEAK_1.setDestination(0).setSensor(LEAK_1_CHILD_ID).set(LEAK_1));
               send(msg_LEAK_1.setDestination(15).setSensor(10).set(LEAK_1));
              
              

              Or you could create a second message object for the node to node communication:

              MyMessage msg_LEAK_1(LEAK_1_CHILD_ID,V_TRIPPED);
              MyMessage msg_LEAK_to_15(10,V_TRIPPED);
              
              void setup()  
              {  
                pinMode(LEAK_1_PIN,INPUT_PULLUP);
              
                // Set destination only once, sensor is set on constructor above
                msg_LEAK_to_15.setDestination(15);
              }
              //[...]
               if (LEAK_1 != last_LEAK_1) 
               {
                 send(msg_LEAK_1.set(LEAK_1));
                 send(msg_LEAK_to_15.set(LEAK_1));
                 last_LEAK_1 = LEAK_1;
               }
              
              A Offline
              A Offline
              APL2017
              wrote on last edited by APL2017
              #8

              @boum said in Node to Node communication:

              MyMessage msg_LEAK_to_15(10,V_TRIPPED);

              Thank you, here is what I have on receiving node (simplified). I am not getting the leak flag on receiving node. Is this correct? Elimination of sleeping did not help. I've noticed that there is no receiving commands within the LOOP, but it was advised as not required in previously referenced discussion.

              #define MY_DEBUG 
              #define MY_RADIO_RF24
              #include <MySensors.h>
              #define LEAK_RECEIVED_CHILD_ID 10
              bool LEAK_RECEIVED;
              uint32_t SLEEP_TIME = 1000; // Sleep time between reads (in milliseconds)
              MyMessage msg_LEAK_RECEIVED(LEAK_RECEIVED_CHILD_ID,V_TRIPPED);
              
              void setup()  
              {  
               }
              void presentation() {
                sendSketchInfo("Basement Water", "1.0");
                present(LEAK_RECEIVED_CHILD_ID, S_DOOR);
              }
              void receive(const MyMessage &message)
               {if (message.type==V_TRIPPED)
                {if (message.sensor==15)
                  { Serial.print(message.sensor);
                    Serial.print("\n");
                    Serial.print(", New status: ");
                    Serial.print(message.getBool());
                    LEAK_RECEIVED=message.getBool();
                  }
                  }
               }
              void loop() 
              {
                  sleep(SLEEP_TIME);
               }
              
              1 Reply Last reply
              0
              • boumB Offline
                boumB Offline
                boum
                wrote on last edited by
                #9

                Yes, you should replace the sleep with a wait. If you module is sleeping, it won't receive any message.
                While prototyping/debugging, you should put more Serial.print around your blocks, not only in the innermost block.

                I guess you are mixing different things in the message object. In the receive() function, you should test message.sensor against 10, the sensor value you put in the sent message, 15 is the node ID destination, that is the current node.

                A 1 Reply Last reply
                0
                • boumB boum

                  Yes, you should replace the sleep with a wait. If you module is sleeping, it won't receive any message.
                  While prototyping/debugging, you should put more Serial.print around your blocks, not only in the innermost block.

                  I guess you are mixing different things in the message object. In the receive() function, you should test message.sensor against 10, the sensor value you put in the sent message, 15 is the node ID destination, that is the current node.

                  A Offline
                  A Offline
                  APL2017
                  wrote on last edited by APL2017
                  #10

                  @boum Thank you! So, in my receiving function i should have the following, where 10 is sending node?

                  void receive(const MyMessage &message)
                   {if (message.type==V_TRIPPED)
                    {if (message.sensor==10)
                      { Serial.print(message.sensor);
                        Serial.print("\n");
                        Serial.print(", New status: ");
                        Serial.print(message.getBool());
                        LEAK_RECEIVED=message.getBool();
                      }
                      }
                   }
                  
                  1 Reply Last reply
                  0
                  • BearWithBeardB Offline
                    BearWithBeardB Offline
                    BearWithBeard
                    wrote on last edited by BearWithBeard
                    #11

                    sensor or sensor ID is synonymous for child ID, one of the many sensors a single node can have. sender is the ID of the node which sent the message.

                    On the sending node:

                    #define MY_NODE_ID 7
                    //                 ^ sender / node ID
                    [...]
                    MyMessage msg_LEAK_to_15( 10, V_TRIPPED );
                    //                        ^^ sensor / child ID
                    [...]
                    msg_LEAK_to_15.setDestination(15);
                    //                            ^^ ID of the destination / receiving node
                    

                    On the receiving node:

                    // returns sender / node ID (7)
                    msg.getSender();
                    
                    // returns sensor / child ID (10)
                    msg.getSensor();
                    

                    So yes, with the changes in your latest code snipped, you should start seeing some serial output.

                    On a different note: Not that it would change anything here, but l'd like to advise to use the availabe getter and setter functions, whenever possible.

                    message.sensor==10 works perfectly fine if you want to compare the current value of the variable against 10. But if you accidently omit one of the equal signs, you assign 10 to the variable instead. Bugs like these can be hard to spot - the if-condition would always evaluate true in this case. Using message.getSensor() prevents such mistakes.

                    A 1 Reply Last reply
                    1
                    • BearWithBeardB BearWithBeard

                      sensor or sensor ID is synonymous for child ID, one of the many sensors a single node can have. sender is the ID of the node which sent the message.

                      On the sending node:

                      #define MY_NODE_ID 7
                      //                 ^ sender / node ID
                      [...]
                      MyMessage msg_LEAK_to_15( 10, V_TRIPPED );
                      //                        ^^ sensor / child ID
                      [...]
                      msg_LEAK_to_15.setDestination(15);
                      //                            ^^ ID of the destination / receiving node
                      

                      On the receiving node:

                      // returns sender / node ID (7)
                      msg.getSender();
                      
                      // returns sensor / child ID (10)
                      msg.getSensor();
                      

                      So yes, with the changes in your latest code snipped, you should start seeing some serial output.

                      On a different note: Not that it would change anything here, but l'd like to advise to use the availabe getter and setter functions, whenever possible.

                      message.sensor==10 works perfectly fine if you want to compare the current value of the variable against 10. But if you accidently omit one of the equal signs, you assign 10 to the variable instead. Bugs like these can be hard to spot - the if-condition would always evaluate true in this case. Using message.getSensor() prevents such mistakes.

                      A Offline
                      A Offline
                      APL2017
                      wrote on last edited by
                      #12

                      @BearWithBeard Thank you. I do not define my nodes ID, they are being assigned automatically (by controller? gateway?), but I do see nodes ID in my controller configuration. Is this a problem?

                      1 Reply Last reply
                      0
                      • BearWithBeardB Offline
                        BearWithBeardB Offline
                        BearWithBeard
                        wrote on last edited by
                        #13

                        I'm not sure if a node's automatically assigned ID can change in special circumstances (apart from clearing the EEPROM), but as long as you don't care about which specific node sent a message in a node-to-node relationship, this shouldn't be a problem. So it's best to avoid using msg.getSender() on the receiving node.

                        I just added a static node ID in the example above to better illustrate what each variable means, since you seem to mix up sender and sensor.

                        A 1 Reply Last reply
                        1
                        • BearWithBeardB BearWithBeard

                          I'm not sure if a node's automatically assigned ID can change in special circumstances (apart from clearing the EEPROM), but as long as you don't care about which specific node sent a message in a node-to-node relationship, this shouldn't be a problem. So it's best to avoid using msg.getSender() on the receiving node.

                          I just added a static node ID in the example above to better illustrate what each variable means, since you seem to mix up sender and sensor.

                          A Offline
                          A Offline
                          APL2017
                          wrote on last edited by
                          #14

                          @BearWithBeard Sorry, I am still confused. Is it possible to publish a complete example of sending Boolean from one node to another to be used in control logic? Thank you.

                          1 Reply Last reply
                          0
                          • BearWithBeardB Offline
                            BearWithBeardB Offline
                            BearWithBeard
                            wrote on last edited by BearWithBeard
                            #15

                            Unfortunately, I don't have a test setup running right now, otherwise I would quickly whip up and test two minimal example sketches.

                            But here are some snippets that should include everything related to node-to-node communication you need. My best advice at this point, if it still confuses you, is to get rid of all the magic numbers in the code and define macros / constants.

                            On the leak detector node, you need the following bits:

                            bool leakState = false;
                            bool previousLeakState = false;
                            
                            #define LEAK_CHILD_ID 0 // 0 to 254
                            #define LEAK_CHILD_ID_TO_NODE 100 // 0 to 254
                            #define LEAK_TARGET_NODE_ID 15 // The ID of the node you want to report to
                            
                            // Setup two separate messages. One reports to the GW, the other to the target node
                            MyMessage msgToGw(LEAK_CHILD_ID, V_TRIPPED);
                            MyMessage msgToNode(LEAK_CHILD_ID_TO_NODE, V_TRIPPED);
                            
                            void presentation() 
                            {
                            	// Register and present sketch and sensors
                            	sendSketchInfo("Leak Detector", "1.0");
                            	present(LEAK_CHILD_ID, S_WATER_LEAK);
                            }
                            
                            void setup()  
                            {
                            	// Set the destination for msgToNode permanently to the target node's ID 
                            	// msgToGw doesn't need that; it defaults to 0 (=GW)
                            	msgToNode.setDestination(LEAK_TARGET_NODE_ID);
                            }
                            
                            void loop() 
                            {
                            	// Check if things have changed
                            	if (leakState != previousLeakState)
                            	{
                            		// Report new state to GW and target node
                            		send(msgToGw.set(leakState));
                            		wait(100); // Optional, but a short pause inbetween can't hurt
                            		send(msgToNode.set(leakState));
                            		
                            		// Update state
                            		previousLeakState = leakState;
                            	}
                            }
                            

                            This will inform the GW via msgToGw as well as the the node with the ID 15 (LEAK_TARGET_NODE_ID) via msgToNode about the updated leakState.

                            The GW will receive this message with the child ID 0 (LEAK_CHILD_ID), node 15 will receive it with the child ID 100 (LEAK_CHILD_ID_TO_NODE). You do not need to change the child ID you send to the destination node - you can keep using the same as for the GW. Just note that you can change it.

                            On the target node, you need this:

                            bool leakState = false;
                            bool previousLeakState = false;
                            #define LEAK_CHILD_ID_INCOMING 100 
                            
                            void loop() 
                            {
                            	// Check if leakState has changed
                            	if (leakState != previousLeakState)
                            	{
                            		// Do something
                            		
                            		// Update state
                            		previousLeakState = leakState;
                            	}
                            }
                            
                            void receive(const MyMessage & msg) 
                            {
                            	Serial.print("Incoming message... ");
                            
                            	// Filter out our message
                            	if (msg.getType() == V_TRIPPED && 
                            		msg.getSensor() == LEAK_CHILD_ID_INCOMING)
                            	{
                            		// Update the local leakState variable
                            		leakState = msg.getBool();
                            
                            		// Print some infos
                            		Serial.println("is a new leak state!");
                            		Serial.print("From (Node ID):");
                            		Serial.println(msg.getSender());
                            		Serial.print("Child ID: ");
                            		Serial.println(msg.getSensor());
                            		Serial.print("State: ");
                            		Serial.println(leakState);
                            	} else 
                            	{
                            		Serial.println("is something else. :(");
                            	}
                            }
                            

                            Hope I didn't miss anything.

                            Once you got it working, it's best to remove most if not all serial prints from the receive function, as it's generally bad practice and can cause various problems.

                            A 1 Reply Last reply
                            1
                            • BearWithBeardB BearWithBeard

                              Unfortunately, I don't have a test setup running right now, otherwise I would quickly whip up and test two minimal example sketches.

                              But here are some snippets that should include everything related to node-to-node communication you need. My best advice at this point, if it still confuses you, is to get rid of all the magic numbers in the code and define macros / constants.

                              On the leak detector node, you need the following bits:

                              bool leakState = false;
                              bool previousLeakState = false;
                              
                              #define LEAK_CHILD_ID 0 // 0 to 254
                              #define LEAK_CHILD_ID_TO_NODE 100 // 0 to 254
                              #define LEAK_TARGET_NODE_ID 15 // The ID of the node you want to report to
                              
                              // Setup two separate messages. One reports to the GW, the other to the target node
                              MyMessage msgToGw(LEAK_CHILD_ID, V_TRIPPED);
                              MyMessage msgToNode(LEAK_CHILD_ID_TO_NODE, V_TRIPPED);
                              
                              void presentation() 
                              {
                              	// Register and present sketch and sensors
                              	sendSketchInfo("Leak Detector", "1.0");
                              	present(LEAK_CHILD_ID, S_WATER_LEAK);
                              }
                              
                              void setup()  
                              {
                              	// Set the destination for msgToNode permanently to the target node's ID 
                              	// msgToGw doesn't need that; it defaults to 0 (=GW)
                              	msgToNode.setDestination(LEAK_TARGET_NODE_ID);
                              }
                              
                              void loop() 
                              {
                              	// Check if things have changed
                              	if (leakState != previousLeakState)
                              	{
                              		// Report new state to GW and target node
                              		send(msgToGw.set(leakState));
                              		wait(100); // Optional, but a short pause inbetween can't hurt
                              		send(msgToNode.set(leakState));
                              		
                              		// Update state
                              		previousLeakState = leakState;
                              	}
                              }
                              

                              This will inform the GW via msgToGw as well as the the node with the ID 15 (LEAK_TARGET_NODE_ID) via msgToNode about the updated leakState.

                              The GW will receive this message with the child ID 0 (LEAK_CHILD_ID), node 15 will receive it with the child ID 100 (LEAK_CHILD_ID_TO_NODE). You do not need to change the child ID you send to the destination node - you can keep using the same as for the GW. Just note that you can change it.

                              On the target node, you need this:

                              bool leakState = false;
                              bool previousLeakState = false;
                              #define LEAK_CHILD_ID_INCOMING 100 
                              
                              void loop() 
                              {
                              	// Check if leakState has changed
                              	if (leakState != previousLeakState)
                              	{
                              		// Do something
                              		
                              		// Update state
                              		previousLeakState = leakState;
                              	}
                              }
                              
                              void receive(const MyMessage & msg) 
                              {
                              	Serial.print("Incoming message... ");
                              
                              	// Filter out our message
                              	if (msg.getType() == V_TRIPPED && 
                              		msg.getSensor() == LEAK_CHILD_ID_INCOMING)
                              	{
                              		// Update the local leakState variable
                              		leakState = msg.getBool();
                              
                              		// Print some infos
                              		Serial.println("is a new leak state!");
                              		Serial.print("From (Node ID):");
                              		Serial.println(msg.getSender());
                              		Serial.print("Child ID: ");
                              		Serial.println(msg.getSensor());
                              		Serial.print("State: ");
                              		Serial.println(leakState);
                              	} else 
                              	{
                              		Serial.println("is something else. :(");
                              	}
                              }
                              

                              Hope I didn't miss anything.

                              Once you got it working, it's best to remove most if not all serial prints from the receive function, as it's generally bad practice and can cause various problems.

                              A Offline
                              A Offline
                              APL2017
                              wrote on last edited by APL2017
                              #16

                              @BearWithBeard THANK YOU! It works fine. The only change I had to make is to replace msg with message in all commands. Couple of questions, if you don't mind:

                              1. Is it critical to have void receive after void loop?
                              2. How receiving node distinguishes between same sensor ID coming from different nodes? Or, I need to assign unique sensor ID throughout complete sensors pool?

                              It will be useful to include working example into mySensors library.

                              1 Reply Last reply
                              0
                              • BearWithBeardB Offline
                                BearWithBeardB Offline
                                BearWithBeard
                                wrote on last edited by
                                #17

                                Glad you got it working!

                                1. The order of the functions in the sketch doesn't determine their execution order, which is managed behind the scenes by the framework. You could place receive() right below the mysensors.h inclusion if you wish.

                                2. They don't. That's why I showed you how to assign a different child ID. You could assing a unique ID per node-to-node-message to make them identifiable.
                                  If multiple node-to-node-message end up having the same child ID, you would have to factor in other variables, like getSender() to tell them apart. Let's say you have three nodes (IDs 1, 2, 3) sending a boolean to a fourth target node and all messages have the same child ID of 0, you could tell them apart like this:

                                  #define LEAK_CHILD_ID_INCOMING 0
                                  // [...]
                                  void receive(const MyMessage & msg) 
                                  {
                                  	// Message is what we're looking for
                                  	if (msg.getType() == V_TRIPPED && 
                                  		msg.getSensor() == LEAK_CHILD_ID_INCOMING)
                                  	{
                                  		// Find out where it's from
                                  		switch (msg.getSender())
                                  		{
                                  			case 1: // From node ID 1
                                  				leakStateNode1 = msg.getBool();
                                  				break;
                                  			case 2: // From node ID 2
                                  				leakStateNode2 = msg.getBool();
                                  				break;
                                  			case 3: // From node ID 3
                                  				leakStateNode3 = msg.getBool();
                                  				break;
                                  			default: // From GW or 4 - 254
                                  				break;
                                  		}
                                  	}
                                  }
                                  

                                  But again, since you're using automatic ID assignment - I'm not sure if node IDs can change under specific circumstances. So If you make use of getSender() you may want to consider assigning static node IDs.

                                A 2 Replies Last reply
                                1
                                • BearWithBeardB BearWithBeard

                                  Glad you got it working!

                                  1. The order of the functions in the sketch doesn't determine their execution order, which is managed behind the scenes by the framework. You could place receive() right below the mysensors.h inclusion if you wish.

                                  2. They don't. That's why I showed you how to assign a different child ID. You could assing a unique ID per node-to-node-message to make them identifiable.
                                    If multiple node-to-node-message end up having the same child ID, you would have to factor in other variables, like getSender() to tell them apart. Let's say you have three nodes (IDs 1, 2, 3) sending a boolean to a fourth target node and all messages have the same child ID of 0, you could tell them apart like this:

                                    #define LEAK_CHILD_ID_INCOMING 0
                                    // [...]
                                    void receive(const MyMessage & msg) 
                                    {
                                    	// Message is what we're looking for
                                    	if (msg.getType() == V_TRIPPED && 
                                    		msg.getSensor() == LEAK_CHILD_ID_INCOMING)
                                    	{
                                    		// Find out where it's from
                                    		switch (msg.getSender())
                                    		{
                                    			case 1: // From node ID 1
                                    				leakStateNode1 = msg.getBool();
                                    				break;
                                    			case 2: // From node ID 2
                                    				leakStateNode2 = msg.getBool();
                                    				break;
                                    			case 3: // From node ID 3
                                    				leakStateNode3 = msg.getBool();
                                    				break;
                                    			default: // From GW or 4 - 254
                                    				break;
                                    		}
                                    	}
                                    }
                                    

                                    But again, since you're using automatic ID assignment - I'm not sure if node IDs can change under specific circumstances. So If you make use of getSender() you may want to consider assigning static node IDs.

                                  A Offline
                                  A Offline
                                  APL2017
                                  wrote on last edited by
                                  #18

                                  @BearWithBeard Thank you!!!

                                  1 Reply Last reply
                                  0
                                  • BearWithBeardB BearWithBeard

                                    Glad you got it working!

                                    1. The order of the functions in the sketch doesn't determine their execution order, which is managed behind the scenes by the framework. You could place receive() right below the mysensors.h inclusion if you wish.

                                    2. They don't. That's why I showed you how to assign a different child ID. You could assing a unique ID per node-to-node-message to make them identifiable.
                                      If multiple node-to-node-message end up having the same child ID, you would have to factor in other variables, like getSender() to tell them apart. Let's say you have three nodes (IDs 1, 2, 3) sending a boolean to a fourth target node and all messages have the same child ID of 0, you could tell them apart like this:

                                      #define LEAK_CHILD_ID_INCOMING 0
                                      // [...]
                                      void receive(const MyMessage & msg) 
                                      {
                                      	// Message is what we're looking for
                                      	if (msg.getType() == V_TRIPPED && 
                                      		msg.getSensor() == LEAK_CHILD_ID_INCOMING)
                                      	{
                                      		// Find out where it's from
                                      		switch (msg.getSender())
                                      		{
                                      			case 1: // From node ID 1
                                      				leakStateNode1 = msg.getBool();
                                      				break;
                                      			case 2: // From node ID 2
                                      				leakStateNode2 = msg.getBool();
                                      				break;
                                      			case 3: // From node ID 3
                                      				leakStateNode3 = msg.getBool();
                                      				break;
                                      			default: // From GW or 4 - 254
                                      				break;
                                      		}
                                      	}
                                      }
                                      

                                      But again, since you're using automatic ID assignment - I'm not sure if node IDs can change under specific circumstances. So If you make use of getSender() you may want to consider assigning static node IDs.

                                    A Offline
                                    A Offline
                                    APL2017
                                    wrote on last edited by APL2017
                                    #19

                                    @BearWithBeard Thanks to you my water leak detection system works fine. My next challenge is to let node receive Boolean (RESET_SOFT) from GW - directly from controller logic. I am looking at example RelayActuator and trying to make sense of it, see below simplified version of it. The idea is to get message from GW (node 0) and received it as sensor ID 20 on the receiving node. Is this close to what is should be?

                                    #define MY_DEBUG 
                                    #define MY_RADIO_RF24
                                    #include <MySensors.h>
                                    
                                    bool RESET_SOFT;
                                    
                                    void setup()  
                                    {  
                                     
                                    }
                                    void presentation() {
                                      sendSketchInfo("Basement Water", "1.0");
                                      present(20, S_BINARY);
                                    }
                                    
                                    void loop() 
                                    {
                                      
                                    }
                                     void receive(const MyMessage &message)
                                     {
                                        if (message.getType()==S_BINARY &&
                                          message.getSensor()==0)
                                         {RESET_SOFT=message.getBool(); }
                                         
                                     } 
                                    
                                    1 Reply Last reply
                                    0
                                    • BearWithBeardB Offline
                                      BearWithBeardB Offline
                                      BearWithBeard
                                      wrote on last edited by BearWithBeard
                                      #20

                                      Well, it looks like you are still mixing up the meaning of sensor and sender in the code. If the controller sends a message to the sensor you have set up in the sketch above (20), while you are comparing against 0 in receive(), you will never detect that message. Compare against 20.

                                      Remember how I advised to get rid of magic numbers and use constants instead? If you would add something like #define SENSOR_ID 20 and use that variable instead of 0 and 20, you might be able to avoid such confusions, because you give those arguments a meaningful name.

                                      Let's try to explain it another way, so that you can adapt it to any situation in the future.

                                      Sensor: In the context of a MySensors sketch, stop thinking of a sensor being a (physical) device. It is just a unique identifier for one of many different data points a device (MySensors calls this device a node) wants to share with others. Think of a sensor (or also often called child) as one of up to 255 wires going from one node to any other, whereby each wire represents a single type of data, like a temperature, a string, voltage level, a boolean value.

                                      Sender: When a node sends a message, it includes a reference to itself - the node ID - as the sender, as well as a reference to the target node as the destination. Both sender and destination enable MySensors to route messages through the network, no matter if it is a direct A-to-B connection or if the message needs to be forwarded by multiple repeaters.

                                      The MyMessage class is used to manage those messages. It stores all kinds of information neccessary to share data between nodes, send and request commands independently from the selected transport method (RF24, Sub-GHz, wired) and controller connection (Serial, MQTT, WiFi, Ethernet).

                                      Imagine a simplified MyMessage instance as a collection of variables and a bunch of helper functions to make your life easier. When the controller (via the GW) sends the message to the node, as you described above, the message would look like this on the receiving node:

                                      MyMessage msg 
                                      {
                                      	sender = 0;       // Node ID of the message's origin (the GW)
                                      	destination = 7;  // Node ID of this device (I assumed this number!)
                                      	sensor = 20;      // Child ID / data point that this message wants to update
                                      	type = 3;         // S_BINARY == 3
                                      	[...]
                                      	getBool();        // Returns the payload as a boolean
                                      	getSensor();      // Returns the value of sensor
                                      	setSensor(n);     // Changes the value of sensor
                                      	getDestination(); // Returns the value of destination
                                      	[...]
                                      }
                                      

                                      So what do you have to do if you want to update the local variable RESET_SOFT on that node whenever it receives a new value? You have to test that the incoming message is of the expected type and that it concerns the right sensor. If you also want to make sure that only the controller or GW can cause an update of RESET_SOFT, you must validate that sender - in other words, the origin of this message - is valid as well.

                                      I really hope this makes sense to you, as I'm running out of ideas how to explain what is going on behind the scenes.

                                      Maybe a look at the Serial API introduction can also help you further.

                                      A 2 Replies Last reply
                                      2
                                      • BearWithBeardB BearWithBeard

                                        Well, it looks like you are still mixing up the meaning of sensor and sender in the code. If the controller sends a message to the sensor you have set up in the sketch above (20), while you are comparing against 0 in receive(), you will never detect that message. Compare against 20.

                                        Remember how I advised to get rid of magic numbers and use constants instead? If you would add something like #define SENSOR_ID 20 and use that variable instead of 0 and 20, you might be able to avoid such confusions, because you give those arguments a meaningful name.

                                        Let's try to explain it another way, so that you can adapt it to any situation in the future.

                                        Sensor: In the context of a MySensors sketch, stop thinking of a sensor being a (physical) device. It is just a unique identifier for one of many different data points a device (MySensors calls this device a node) wants to share with others. Think of a sensor (or also often called child) as one of up to 255 wires going from one node to any other, whereby each wire represents a single type of data, like a temperature, a string, voltage level, a boolean value.

                                        Sender: When a node sends a message, it includes a reference to itself - the node ID - as the sender, as well as a reference to the target node as the destination. Both sender and destination enable MySensors to route messages through the network, no matter if it is a direct A-to-B connection or if the message needs to be forwarded by multiple repeaters.

                                        The MyMessage class is used to manage those messages. It stores all kinds of information neccessary to share data between nodes, send and request commands independently from the selected transport method (RF24, Sub-GHz, wired) and controller connection (Serial, MQTT, WiFi, Ethernet).

                                        Imagine a simplified MyMessage instance as a collection of variables and a bunch of helper functions to make your life easier. When the controller (via the GW) sends the message to the node, as you described above, the message would look like this on the receiving node:

                                        MyMessage msg 
                                        {
                                        	sender = 0;       // Node ID of the message's origin (the GW)
                                        	destination = 7;  // Node ID of this device (I assumed this number!)
                                        	sensor = 20;      // Child ID / data point that this message wants to update
                                        	type = 3;         // S_BINARY == 3
                                        	[...]
                                        	getBool();        // Returns the payload as a boolean
                                        	getSensor();      // Returns the value of sensor
                                        	setSensor(n);     // Changes the value of sensor
                                        	getDestination(); // Returns the value of destination
                                        	[...]
                                        }
                                        

                                        So what do you have to do if you want to update the local variable RESET_SOFT on that node whenever it receives a new value? You have to test that the incoming message is of the expected type and that it concerns the right sensor. If you also want to make sure that only the controller or GW can cause an update of RESET_SOFT, you must validate that sender - in other words, the origin of this message - is valid as well.

                                        I really hope this makes sense to you, as I'm running out of ideas how to explain what is going on behind the scenes.

                                        Maybe a look at the Serial API introduction can also help you further.

                                        A Offline
                                        A Offline
                                        APL2017
                                        wrote on last edited by APL2017
                                        #21

                                        @BearWithBeard Thank you! I am really embarrassed with my, let's say, luck of understanding. But you made it clear again. Everything works as required!

                                        1 Reply Last reply
                                        0
                                        • BearWithBeardB BearWithBeard

                                          Well, it looks like you are still mixing up the meaning of sensor and sender in the code. If the controller sends a message to the sensor you have set up in the sketch above (20), while you are comparing against 0 in receive(), you will never detect that message. Compare against 20.

                                          Remember how I advised to get rid of magic numbers and use constants instead? If you would add something like #define SENSOR_ID 20 and use that variable instead of 0 and 20, you might be able to avoid such confusions, because you give those arguments a meaningful name.

                                          Let's try to explain it another way, so that you can adapt it to any situation in the future.

                                          Sensor: In the context of a MySensors sketch, stop thinking of a sensor being a (physical) device. It is just a unique identifier for one of many different data points a device (MySensors calls this device a node) wants to share with others. Think of a sensor (or also often called child) as one of up to 255 wires going from one node to any other, whereby each wire represents a single type of data, like a temperature, a string, voltage level, a boolean value.

                                          Sender: When a node sends a message, it includes a reference to itself - the node ID - as the sender, as well as a reference to the target node as the destination. Both sender and destination enable MySensors to route messages through the network, no matter if it is a direct A-to-B connection or if the message needs to be forwarded by multiple repeaters.

                                          The MyMessage class is used to manage those messages. It stores all kinds of information neccessary to share data between nodes, send and request commands independently from the selected transport method (RF24, Sub-GHz, wired) and controller connection (Serial, MQTT, WiFi, Ethernet).

                                          Imagine a simplified MyMessage instance as a collection of variables and a bunch of helper functions to make your life easier. When the controller (via the GW) sends the message to the node, as you described above, the message would look like this on the receiving node:

                                          MyMessage msg 
                                          {
                                          	sender = 0;       // Node ID of the message's origin (the GW)
                                          	destination = 7;  // Node ID of this device (I assumed this number!)
                                          	sensor = 20;      // Child ID / data point that this message wants to update
                                          	type = 3;         // S_BINARY == 3
                                          	[...]
                                          	getBool();        // Returns the payload as a boolean
                                          	getSensor();      // Returns the value of sensor
                                          	setSensor(n);     // Changes the value of sensor
                                          	getDestination(); // Returns the value of destination
                                          	[...]
                                          }
                                          

                                          So what do you have to do if you want to update the local variable RESET_SOFT on that node whenever it receives a new value? You have to test that the incoming message is of the expected type and that it concerns the right sensor. If you also want to make sure that only the controller or GW can cause an update of RESET_SOFT, you must validate that sender - in other words, the origin of this message - is valid as well.

                                          I really hope this makes sense to you, as I'm running out of ideas how to explain what is going on behind the scenes.

                                          Maybe a look at the Serial API introduction can also help you further.

                                          A Offline
                                          A Offline
                                          APL2017
                                          wrote on last edited by APL2017
                                          #22
                                          This post is deleted!
                                          1 Reply Last reply
                                          0
                                          Reply
                                          • Reply as topic
                                          Log in to reply
                                          • Oldest to Newest
                                          • Newest to Oldest
                                          • Most Votes


                                          7

                                          Online

                                          11.7k

                                          Users

                                          11.2k

                                          Topics

                                          113.0k

                                          Posts


                                          Copyright 2019 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