Node-red-contrib-azure-iot-device & Direct Methods

Hello, I'm very new to Node Red and JSON so bear with me. I'm using the "Device" node from the subject palette and found the Direct Method feature perfect for my IoT application. What I want to do is use a cloud hosted SCADA application to command up to 12 or so points on an end device via Modbus. The cloud hosted SCADA application will use the Azure IoTHub Direct Method to invoke the method named "AHU01_Commands" on the "Device" node. I've already proven that I can successfully invoke the direct method but I'm having trouble interpreting the resulting message object. The payload that will be sent by SCADA will simply contain the point name and the associated value as shown below:

{
"RADamperPos" : 57.5
}

or

{
"SetUnitEnabled" : 0,
}

or

{
"HtgSP" : 85.5
}

Do you have ideas of how I can interpret the msg.payload.payload point name which would allow me to route the resulting value to a multiple output function node? So if the payload contains "RADamperPos" then the associated value goes to output 1, if the payload contains "SetUnitEnabled" then the associated value goes to output 2, etc.

When the direct method is invoked the resulting message object looks like this:
DirectMethodCommand

Hi,

Does this help ?

I have created a sample flow that will route based on keys. This works if you have a finite and known set of keys

[{"id":"258292c7.9d602e","type":"debug","z":"bce50b9f.7a7508","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":655,"y":360,"wires":[]},{"id":"2d4f016d.bca636","type":"change","z":"bce50b9f.7a7508","name":"RADamperPos","rules":[{"t":"set","p":"payload","pt":"msg","to":"{     \"RADamperPos\" : msg.payload.payload.RADamperPos}        ","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":440,"y":300,"wires":[["258292c7.9d602e"]]},{"id":"6f3e2ac5.7c17cc","type":"change","z":"bce50b9f.7a7508","name":"SetUnitEnabled","rules":[{"t":"set","p":"payload","pt":"msg","to":"{     \"SetUnitEnabled\" : msg.payload.payload.SetUnitEnabled}        ","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":440,"y":345,"wires":[["258292c7.9d602e"]]},{"id":"81bc7de3.81054","type":"change","z":"bce50b9f.7a7508","name":"HtgSP","rules":[{"t":"set","p":"payload","pt":"msg","to":"{     \"HtgSP\" : msg.payload.payload.HtgSP}        ","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":410,"y":390,"wires":[["258292c7.9d602e"]]},{"id":"3bfb9bc3.49da3c","type":"switch","z":"bce50b9f.7a7508","name":"Which point","property":"payload.payload","propertyType":"msg","rules":[{"t":"hask","v":"RADamperPos","vt":"str"},{"t":"hask","v":"SetUnitEnabled","vt":"str"},{"t":"hask","v":"HtgSP","vt":"str"}],"checkall":"false","repair":false,"outputs":3,"x":250,"y":345,"wires":[["2d4f016d.bca636"],["6f3e2ac5.7c17cc"],["81bc7de3.81054"]],"outputLabels":["RADamperPos","SetUnitEnabled","HtgSP"]},{"id":"11ea05c4.9a26b2","type":"inject","z":"bce50b9f.7a7508","name":"Inject value","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"requestId\":\"1\",\"methodName\":\"AHU01_Commands\",\"payload\":{\"RADamperPos\":57.5},\"topic\":\"command\",\"deviceId\":\"MyNodeDevice\"}","payloadType":"json","x":90,"y":345,"wires":[["3bfb9bc3.49da3c"]]}]

The switch node will determine the point name and then each of the change node will set up the msg.payload.

Will you be doing anything unique with the points or will they judt be passed on. If it is the latter then you could just extract the msg.payload.payload and set it to msg.payloadf like

[{"id":"ba262e2.e2707d","type":"inject","z":"bce50b9f.7a7508","name":"Inject value","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"requestId\":\"1\",\"methodName\":\"AHU01_Commands\",\"payload\":{\"RADamperPos\":57.5},\"topic\":\"command\",\"deviceId\":\"MyNodeDevice\"}","payloadType":"json","x":120,"y":570,"wires":[["2932ce05.dc5bf2"]]},{"id":"2932ce05.dc5bf2","type":"change","z":"bce50b9f.7a7508","name":"Extract just payload","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":315,"y":570,"wires":[["68449f71.a0708"]]},{"id":"68449f71.a0708","type":"debug","z":"bce50b9f.7a7508","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":530,"y":570,"wires":[]}]

Chrisn,

Thank you very much for taking the time to guide me. I was missing the concept of "key" in the message object. I am testing with your first flow, but noticed that nothing seems to pass the Switch node when I manually inject (I don't get any msg.payload posting to the Debug panel). Is there a chance that the Switch node property needs to be something other than "msg.payload.payload"?

Hi,

Strange because I get what i expect in debug.

I made the switch msg.payload.payload based on your data. Are you running the flow unchanged ?.

{
    "requestId": "1",
    "methodName": "AHU01_Commands",
    "payload": {
        "RADamperPos": 57.5
    },
    "topic": "command",
    "deviceId": "MyNodeDevice"
}

Let me know, if anyone else wants to try this flow it is appreciated but it works on my pc :slight_smile:

Chrisn,
Sorry this is my mistake. When I ran your flow by itself unaltered it works as expected. When I introduce the output from my "Device" node into your "Which point" node it seems to break your flow functionality, but I'm not sure why. When I invoked a direct method from Azure IoT Explorer you can see from my screen print below nothing passes the "Which" point. In addition this flow seems to break the "Inject Value" node. Does this make sense?

Chrisn,
One thing I just noticed...When I disconnect your "Inject value" node and have "Which point" node just tied to the "Device" node, after deploying, I get a msg:error in the debugger "TypeError: Cannot read property 'hasOwnProperty' of undefined". See screen print below. Hopefully this leads to the solution.

Hi,

I assume the payload the switch is receiving does not have a msg.payload.payload

I have extended my flow a bit to help capture some diagnostics

[{"id":"e093da07.64977","type":"inject","z":"bce50b9f.7a7508","name":"Inject value","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"requestId\":\"1\",\"methodName\":\"AHU01_Commands\",\"payload\":{\"RADamperPos\":57.5},\"topic\":\"command\",\"deviceId\":\"MyNodeDevice\"}","payloadType":"json","x":75,"y":870,"wires":[["72e6ba21.57ca0c"]]},{"id":"72e6ba21.57ca0c","type":"change","z":"bce50b9f.7a7508","name":"Does nothing","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":175,"y":810,"wires":[["d74ca36c.e128","d7138483.be2ee8"]]},{"id":"d74ca36c.e128","type":"switch","z":"bce50b9f.7a7508","name":"Which point","property":"payload.payload","propertyType":"msg","rules":[{"t":"null"},{"t":"hask","v":"RADamperPos","vt":"str"},{"t":"hask","v":"SetUnitEnabled","vt":"str"},{"t":"hask","v":"HtgSP","vt":"str"},{"t":"else"}],"checkall":"false","repair":false,"outputs":5,"x":370,"y":810,"wires":[["dba5a131.fcfb98"],["d444d24b.a096f"],["21c33452.ae55ac"],["a780e14a.a0e168"],["a259aaca.e376f"]],"outputLabels":["","RADamperPos","SetUnitEnabled","HtgSP",null]},{"id":"1cd52508.d853f3","type":"inject","z":"bce50b9f.7a7508","name":"No payload.payload","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":115,"y":735,"wires":[["72e6ba21.57ca0c"]]},{"id":"d7138483.be2ee8","type":"debug","z":"bce50b9f.7a7508","name":"What goes in ","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":355,"y":660,"wires":[]},{"id":"d444d24b.a096f","type":"change","z":"bce50b9f.7a7508","name":"RADamperPos","rules":[{"t":"set","p":"payload","pt":"msg","to":"{     \"RADamperPos\" : msg.payload.payload.RADamperPos}        ","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":560,"y":765,"wires":[["a1dd6de1.c1d79"]]},{"id":"21c33452.ae55ac","type":"change","z":"bce50b9f.7a7508","name":"SetUnitEnabled","rules":[{"t":"set","p":"payload","pt":"msg","to":"{     \"SetUnitEnabled\" : msg.payload.payload.SetUnitEnabled}        ","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":560,"y":810,"wires":[["a1dd6de1.c1d79"]]},{"id":"a780e14a.a0e168","type":"change","z":"bce50b9f.7a7508","name":"HtgSP","rules":[{"t":"set","p":"payload","pt":"msg","to":"{     \"HtgSP\" : msg.payload.payload.HtgSP}        ","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":530,"y":855,"wires":[["a1dd6de1.c1d79"]]},{"id":"dba5a131.fcfb98","type":"debug","z":"bce50b9f.7a7508","name":"No payload.payload","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":580,"y":690,"wires":[]},{"id":"a259aaca.e376f","type":"debug","z":"bce50b9f.7a7508","name":"No match","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":565,"y":930,"wires":[]},{"id":"a1dd6de1.c1d79","type":"debug","z":"bce50b9f.7a7508","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":775,"y":825,"wires":[]}]

If you connect the Device node to the does nothing node and expand the debugs we should be able to find out what is going in

Okay Chrisn, here's what I get:

The screen print above is after invoking the direct method via Azure IoT Explorer. The screen print below is manually injecting via your two inject nodes:

So it looks like it is working ?

It looks like you are getting the value out

Yes Chrisn, it looks like it is working with your new flow, but I don't understand why this works and the previous flow does not. Thank you very much for your help!

1 Like

I'm trying to expand above topic to respond to the Azure IoTHub with "objective" feedback to the IoTHub that the direct method properly set the Modbus address on the end system. In the function node below I'm having trouble formatting the "msg.payload.payload" with the syntax {name:value}. I have the components (CmdPointName and CmdPointValue) to build the msg.payload.payload but can't figure out how to structure this into this syntax: {CmdPointName:CmdPointVaulue}.

The function node:

The debug response to the above function node:
Function Node Response

Any guidance would be greatly appreciated.

var cmdFdbk = {}:
cmdFdbk[CmdPointName] = CmdPointVaulue;

The concept you are looking for is property assessor bracket notation

2 Likes

Thank you Steve! I appreciate your help on this.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.