How to properly handle variable requests



  • Hello,

    I've seen this ask several times, dating back to 2015 or so, but no really appropriate answer. Hence I try to find a definitive answer to this question.

    How to properly handle requests of variables in the nodes?

    According to documentation the request(...) function could be used to request variables from the controller or any other node.

    What it does is sending a message with command C_REQ. But how should an answer properly be sent?

    Example (shortened to what is really important here):
    Node 1 has a variable V_STATUS, Node 2 has a variable V_STATUS.
    Node 1 now septs C_REQ for V_STATUS to Node 2.
    What should Node 2 answer?
    If it would answer with C_REQ, this could be read by Node 1 as request for its V_STATUS. If it would send C_SET it would be a set of V_STATUS in Node 1.

    Only reasonable way I see with available tools would be:
    Node 1 sends C_REQ for V_STATUS to Node 2, with EchoRequest (because it is for sure requesting for something back), payload is empty.
    Node 2 replies C_REQ for V_STATUS, puts V_STATUS value in payload and sets isEcho.

    Problem with this approach: The echo request is not seen in the receive function as it is handled in transportProcessMessage() inside library. Plus: This would stretch the definition of echo, because the answer is not an echo, as it has payload the request did not have. But that would probably be acceptable, because an empty payload would still be an echo in case Node 2 does not have variable V_STATUS.

    Did I miss anything?


  • Hero Member

    @tante-ju

    If you are making a request to the controller it will return the required data for you to use, you will then need to have code on the requesting node to handle this return.

    If you are making a node to node request you will need to manually handle both the incoming request on the target node and then use node to node communication to the return of the required data to the node that requested the data. Then on the node that sent the request you will need to have code to separate this return from normal controller commands.

    In MySensors you can use message.sender to determine where the message came from and message.getCommand to see if the message is a request or command etc.

    Have a look at these three posts to see what these look like in use and also how to format a node to node message.

    https://forum.mysensors.org/topic/6422/display-node-how-to-set-up/20

    https://forum.mysensors.org/topic/6948/synchronising-light-switch

    https://forum.mysensors.org/topic/6542/outdoors-touch-switch-light-controller?_=1596330659286



  • @Boots33

    I don't see any of the posts addressing the core issue.
    You could have different actions regarding variables:

    1. set variable in destination node
    2. request variable from destination node
    3. deliver variable from source node

    3 is a result of 2. In controller/node communication 3 is no issue, as it could just C_SET (as it would be with 1), because I think it is unlikely that a node wants to set a variable in the controller other than its own variable representation.

    But for 3 between nodes: How to differentiate it from 1 and 2? I could not find any standard or best practice approach. All the ones I found are based on assumption of using different variables in the nodes or that a node could not set a variable in another node (and hence could use C_SET as answer) or that the request is always from the controller.


  • Hero Member

    sorry @tante-ju I am not quite getting what you are trying to achieve. Are you trying to request data directly from one node to the other of from a node to the controller.



  • @Boots33

    Node to Node. Between Nodes that have the same set of Variables.



  • I see it this way:
    NodeA sends C_REQ of Var1 to NodeB
    NodeB processes C_REQ message in receive();
    NodeB replies with C_SET of Var1 to NodeA just as controller would
    NodeA processes C_SET message in receive();

    You can use echo/ACK functionality or not, it doesn't matter.

    If you want both nodes to synchronise their variables, then it seems best to:
    a)request values on boot
    b)On variable change send values without prompt

    That way you cut traffic by half compared to request-reply approach.



  • @Sasquatch said in How to properly handle variable requests:

    I see it this way:
    NodeA sends C_REQ of Var1 to NodeB
    NodeB processes C_REQ message in receive();
    NodeB replies with C_SET of Var1 to NodeA just as controller would
    NodeA processes C_SET message in receive();

    You can use echo/ACK functionality or not, it doesn't matter.

    If you want both nodes to synchronise their variables, then it seems best to:
    a)request values on boot
    b)On variable change send values without prompt

    That way you cut traffic by half compared to request-reply approach.

    In case of vars to be synced that could be an approach. But in case, that is not intended, the C_SET looks for NodeA as a request to modify Var1 in NodeA.



  • I think I found a way, maybe an idea to document it somewhere?

    If the C_REQ received has getLength()==0, it is a request for a value. If it has any payload, it is reply to a request.

    Makes sense?


  • Hero Member

    @tante-ju
    Sorry for the late reply, I have been away for a few days with work.

    While I am sure there will be more than one way to achieve your goal I have given a brief outline of the way i did it below.

    If all you want to do is request data from another node it should not need any more steps than @Sasquatch has listed above.
    Lets say we have node A with an id of 1
    we also have node B with an id of 2 and it has a binary sensor with a child id of 3

    Node A wants to know the the status of the binary sensor on node B
    So in your code on node A you will issue the request to query child id 3 on node 2

     request( 3, V_STATUS,  2);
    

    The gateway will rout this directly to node B where you will need to have code to deal with the request in the receive(); function. In it's simplest form you could have something like this below.

    void receive(const MyMessage &message) {
    
         if (message.type == V_STATUS) { 
           if (message.getCommand() == C_REQ){   // message is request
    
             // put code here to be executed when the message is from a request
             // most likely you will call a function that will get the requested 
             // data and return it to node A. If you are expecting requests for more than 1
             // sensor you can use  message.sensor to test which sensor the request is for 
           
    }
           else {                                                             // message is from gateway,process the message as per normal
               
                // put code here to be executed when the message is from gateway   
                }
         }
     }
    

    in the scenario above node B only expects requests from node A or commands from the gateway so it is easy to check what has arrived. If the message is a request we can execute code to get the required data and send it back. if it is a command (C_SET) from the gateway then it will fall through to the else part of the statement and be available as per normal.

    To send back the Data you will need to use a node to node message.
    this can be done on the fly, the format is shown below

     /*   Node to Node message format.                                                                                     *
              *                                                                                                            *
              *                                                                                                            *
              *            : Id of sending  : message  :   Destination     :     Destination      : Payload                *
              *            :    sensor      :  Type    :    sensor Id      :       Node Id        :                        */ 
             send(MyMessage(sendingSensorId, V_STATUS).setSensor(sensorId).setDestination(nodeId).set(true));  //send message to desitination node 
    

    So using our example you would have. (As we are not trying to actually switch any sensors on node A we can leave out the setSensor() part of the message)

    send(MyMessage(3, V_STATUS).setDestination(1).set(true));
    

    Being a binary sensor the payload would be set to either true or false.

    Now we have sent the data all that is left to do is catch it in the recieve part of node A. One way to do this is simply to test for where the message has come from, if it is from the gateway (node 0) or in our case node 2.

    void receive(const MyMessage &message) {
    
     if (message.type == V_STATUS) {
       if (message.sender == 0) {                                        // check if message is from gateway (node 0)
        
        // put code here for normal gateway messages
        
    }
      else {                                                           // message is not from gateway so check to see if it is from node B 
        
        if (message.sender == 2 ){
    
             Put code here to deal with returning request
        }
    
    } 
    }
    }
    

Log in to reply
 

Suggested Topics

11
Online

11.4k
Users

11.1k
Topics

112.7k
Posts