Extra command message type for local data requests


  • Contest Winner

    Every now and then i'd think about sensors which rely on data from other sensors/nodes.

    The current way of gathering this data, is request the data direct from the other MySensors-node using the message command type "req" (see api: https://www.mysensors.org/download/serial_api_20) This limits the data gathering to MySensors nodes.

    My proposal would be to extend the message API with an additional message command type called "localrequest"
    where the payload of this command holds the unique device id as known by the HA-controller (each HA has such ID's)

    A localrequest message would look like this:

    30;1;5;0;15;215\n
    

    requesting node id (reply-to node);child id (reply-to sensor id);localrequest-command;nack;V_ARMED;HA-unique ID\n

    By having this localrequest command and using the unique HA-ID all devices connected to this HA can provide data to the MySensors nodes. At least for Vera this will work fine. (i can provide the correct code for the Vera plugin)
    This localrequest will also work for data provided by battery powered nodes which are sleeping most of their time.


  • Hero Member

    @BartE I had (and maybe have) a similar need. Domoticz does something like that with S_CUSTOM which can request all kinds of data from the the controller. I have 'solved' it by duplicating the data with a controller script to a sensor specific 'dummy sensor' so that it can be retrieved with a request from the controller.

    Problem with having a controller dependent number would be 'controller dependency' so I'm not sure...
    (and a better name would be 'controllerRequest' 😉)


  • Contest Winner

    @AWI i was actually referring to an additional "command" (third byte) and not a V-type.
    The V-type should represent the type of value which is requested from the controller. HA controller like Vera need the message type to be able to retrieve the data.

    ControlleRequest is indeed a better name than local request.

    Using V_CUSTOM could be an alternative. with the first payload byte the request V-type followed by and HA Controller ID.

    I can make a prototype with this implementation.


  • Contest Winner

    OK i did make a prototype implementation using the V_CUSTOM message type.
    This works for Vera only.

    I had to change only one file: L_Arduino.lua
    The function starting on line 244 has te be extened with this if statement:

    -- Handle Local Request variables	
    if (varType == "CUSTOM") then
    	local bit         = require("bit")
            local varReqIndex = bit.band(tonumber(value), 0xFF);
            local varVeraId   = bit.rshift(tonumber(value), 8);
    	local varReqType  = tVarLookupNumType[varReqIndex]
    	local varReq      = tVarTypes[varReqType]
                            
    	if (varReq[2] ~= nil) then 
    		log("Local request '" .. varReq[3] .. "' from Device ID: ".. varVeraId .. " sensor type '" .. varReqType .. "'")
    		local localValue = luup.variable_get(varReq[2], varReq[3], varVeraId)
    		if (localValue ~= nil) then
    			-- Send variable value to actuator
    			sendRequestResponse(nodeId .. ";" .. childId, varReqType, localValue)
    		end
    	end	
    else
    

    The complete function will then look like this:

    local function setVariable(incomingData, childId, nodeId)
    	if (childId ~= nil) then
    		-- Set variable on child sensor.
    		local index = tonumber(incomingData[5]);
    		local varType = tVarLookupNumType[index]
    		local var = tVarTypes[varType]
    		local value = incomingData[6]
    		local timestamp = os.time()
    
                    -- Handle Local Request variables	
    		if (varType == "CUSTOM") then
    			local bit         = require("bit")
                            local varReqIndex = bit.band(tonumber(value), 0xFF);
                            local varVeraId   = bit.rshift(tonumber(value), 8);
    			local varReqType  = tVarLookupNumType[varReqIndex]
    			local varReq      = tVarTypes[varReqType]
                            
    		        if (varReq[2] ~= nil) then 
    				log("Local request '" .. varReq[3] .. "' from Device ID: ".. varVeraId .. " sensor type '" .. varReqType .. "'")
    				local localValue = luup.variable_get(varReq[2], varReq[3], varVeraId)
    				if (localValue ~= nil) then
    					-- Send variable value to actuator
    					sendRequestResponse(nodeId .. ";" .. childId, varReqType, localValue)
    				end
    			end	
    
    		elseif (var[2] ~= nil) then 
    			log("Setting variable '".. var[3] .. "' to value '".. value.. "'")
    			setVariableIfChanged(var[2], var[3], value, childId)
    		
    			-- Handle special variables battery level and tripped which also
    			-- should update other variables to os.time()
    			if (varType == "TRIPPED" and value == "1") then
    				local variable = tVeraTypes["LAST_TRIP"]
    				setVariableIfChanged(variable[2], variable[3], timestamp, childId)
    			else
    				local variable = tVeraTypes["LAST_UPDATE"]
    				setVariableIfChanged(variable[2], variable[3], timestamp, childId)
    			end
    		end
    
    		-- Always update LAST_UPDATE for node	
    		if (nodeId ~= nil) then
    			local nodeDevice = childIdLookupTable[nodeId .. ";" .. NODE_CHILD_ID] 
    			setLastUpdate(nodeDevice)
    		end
    	end
    end
    

    Now the Vera HA-contoller response on V_CUSTOM messages.

    Use the feature in a MySensors node:

    void requestValue(byte type, unsigned int id)
    {
         MyMessage msgRequest(1, V_CUSTOM);
         unsigned long msgData;
         msgData = type + ((unsigned long)id * 0x100); 
         send(msgRequest.set(msgData));
    }
    
    void loop()
    {
         // Request the status from Vera Device 4
         requestValue(V_STATUS,  4);
     
        // Request the dimn level  from Vera Device 20
        requestValue(V_LEVEL, 20);
       
       // etc..  
    }
    

    Make sure you can handle the incoming messages

    void receive(const MyMessage &message)
    {
    	if (message.type==V_STATUS) {
    		Serial.print(" New value: ");
    		Serial.println(message.getBool());
    	}
           if (message.type==V_LEVEL) {
    		Serial.print(" New value: ");
    		Serial.println(message.getByte());
    	}
           if (message.type==V_TEMP) {
    		 Serial.print(" New value: ");
    		Serial.println(message.getFloat());
    	}
    }
    

    If you need the same value type from different Device a different sensor id can be used, the requestValue will then look like this:

    void requestValue(byte type, unsigned int id, byte sensorid)
    {
         MyMessage msgRequest(sensorid, V_CUSTOM);
         unsigned long msgData;
         msgData = type + ((unsigned long)id * 0x100); 
         send(msgRequest.set(msgData));
    }
    

    In the receive function "message.sensor" can be used to determine for which device a request was made


Log in to reply
 

Suggested Topics

14
Online

11.2k
Users

11.1k
Topics

112.5k
Posts