Help Me Understand How Messages are Passed

I’ve created a sub-flow to identify then group together Sonos speakers that are active on the network. Once they’ve been identified and grouped, a loop is used to set the volume on each using a message passed to the loop from the calling flow. As written, the sub-flow is working.

I’m flummoxed by one thing though! I can’t figure out why when trying to use ‘payload’ in the msg field of the ‘array-loop node’ (Loop Through List) an error occurs (This flow contains some nodes that are not configured properly) and I’m unable to Deploy the sub-flow. To make the node function, a message named ‘msg.loop_through’ (msg.loop_through = msg.payload) is created in the function node named “Set Master and Group Members”. This message is, from what I can see, identical to msg.payload. Here’s the catch! When ‘loop_through’ is used in the msg field of the ‘array-loop node’, the sub-flow continues, exiting back to the calling flow.

I’d like to eliminate the loop_through message and use the payload msg instead. Why am I unable to use that message in the msg field of the ‘array-loop node’ ?

Here’s a couple of screen shots and the sub-flow that’s working.

[{"id":"4ed4def360353223","type":"subflow","name":"Ungroup Sonos Speakers","info":"","category":"","in":[{"x":100,"y":140,"wires":[{"id":"677f323de579408b"}]}],"out":[{"x":680,"y":140,"wires":[{"id":"f03f45a21b75fd46","port":0}]}],"env":[],"meta":{},"color":"#DDAA99"},{"id":"a3c3ed4e88946a44","type":"comment","z":"4ed4def360353223","name":"Ungroup Sonos Speakers","info":"","x":170,"y":80,"wires":[]},{"id":"677f323de579408b","type":"ha-get-entities","z":"4ed4def360353223","name":"ID Sonos Speakers","server":"fcf9b76b.256a88","version":0,"rules":[{"property":"entity_id","logic":"is","value":"(?<=media_player)(.*)(?=_sonos$)","valueType":"re"}],"output_type":"array","output_empty_results":false,"output_location_type":"msg","output_location":"payload","output_results_count":1,"x":250,"y":140,"wires":[["f03f45a21b75fd46"]],"info":"The name of all Sonos speakers installed in the house ends with _sonos. Use a filter to identify and build an array of all active speakes."},{"id":"f03f45a21b75fd46","type":"api-call-service","z":"4ed4def360353223","name":"Unjoin Sonos Speakers","server":"fcf9b76b.256a88","version":5,"debugenabled":false,"domain":"media_player","service":"unjoin","areaId":[],"deviceId":[],"entityId":[],"data":"{\"entity_id\": $join(payload.entity_id,\",\")}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":510,"y":140,"wires":[[]]},{"id":"fcf9b76b.256a88","type":"server","name":"Home Assistant","version":2,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":"30"},{"id":"2daf88a8cb1e7dfd","type":"subflow","name":"Group Sonos Speakers","info":"","category":"","in":[{"x":100,"y":140,"wires":[{"id":"019bb764bb26a988"}]}],"out":[{"x":1540,"y":140,"wires":[{"id":"88d2898f6579fa51","port":0}]}],"env":[],"meta":{},"color":"#DDAA99"},{"id":"c77a899029985c0d","type":"comment","z":"2daf88a8cb1e7dfd","name":"Group Sonos Speakers","info":"","x":160,"y":80,"wires":[]},{"id":"019bb764bb26a988","type":"subflow:4ed4def360353223","z":"2daf88a8cb1e7dfd","name":"","x":290,"y":140,"wires":[["8fa424986cca3c5d"]]},{"id":"fad4e56c0cae913a","type":"function","z":"2daf88a8cb1e7dfd","name":"Set Master and Group Members","func":"msg.loop_through = msg.payload\nmsg.group_members = [];\n\nfor (var i = 0; i < msg.payload.length; i++) {\n    if(i === 0){\n        msg.sonos_master = msg.payload[i].entity_id;\n    }else{\n        msg.group_members[i-1] = '\"' + msg.payload[i].entity_id + '\"';\n    }\n}\n\nmsg.group_members = msg.group_members.join(\",\")\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":810,"y":140,"wires":[["703f711e0835ed75","feb90444894a2eb9"]]},{"id":"703f711e0835ed75","type":"api-call-service","z":"2daf88a8cb1e7dfd","name":"Group Sonos Speakers","server":"fcf9b76b.256a88","version":5,"debugenabled":true,"domain":"media_player","service":"join","areaId":[],"deviceId":[],"entityId":[],"data":"{\"entity_id\":\"{{sonos_master}}\",\"group_members\":[{{{group_members}}}]}","dataType":"json","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1110,"y":140,"wires":[["88d2898f6579fa51","0fae693f4a27e55e"]]},{"id":"b93fc264f3f032ba","type":"function","z":"2daf88a8cb1e7dfd","name":"Next Speaker","func":"return msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1360,"y":200,"wires":[["88d2898f6579fa51"]]},{"id":"24b9feaaaeb5e7a3","type":"api-call-service","z":"2daf88a8cb1e7dfd","name":"Set Volume","server":"fcf9b76b.256a88","version":5,"debugenabled":false,"domain":"media_player","service":"volume_set","areaId":[],"deviceId":[],"entityId":["{{payload.entity_id}}"],"data":"{\"volume_level\":\"{{audio_volume_level}}\"}","dataType":"json","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1590,"y":200,"wires":[["b93fc264f3f032ba"]]},{"id":"88d2898f6579fa51","type":"array-loop","z":"2daf88a8cb1e7dfd","name":"Loop Through List","key":"al88d2898f6579fa51","keyType":"msg","reset":false,"resetValue":"value-null","array":"loop_through","arrayType":"msg","x":1370,"y":140,"wires":[[],["24b9feaaaeb5e7a3"]]},{"id":"feb90444894a2eb9","type":"debug","z":"2daf88a8cb1e7dfd","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1050,"y":220,"wires":[]},{"id":"0fae693f4a27e55e","type":"debug","z":"2daf88a8cb1e7dfd","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1310,"y":300,"wires":[]},{"id":"8fa424986cca3c5d","type":"ha-get-entities","z":"2daf88a8cb1e7dfd","name":"ID Sonos Speakers","server":"fcf9b76b.256a88","version":0,"rules":[{"property":"entity_id","logic":"is","value":"(?<=media_player)(.*)(?=_sonos$)","valueType":"re"}],"output_type":"array","output_empty_results":false,"output_location_type":"msg","output_location":"payload","output_results_count":1,"x":550,"y":140,"wires":[["fad4e56c0cae913a"]],"info":"The name of all Sonos speakers installed in the house ends with _sonos. Use a filter to identify and build an array of all active speakes."}]

Can’t really answer for certain because I’ve never used the “array-loop” node before. But looking at it I guess I’m a bit confused why you need that node? What’s wrong with the OOTB Split and Join nodes?

I use those all the time whenever I need to loop. You pass a message with an array in payload into a split node, put one or more nodes after doing whatever your processing you need to do on each item and then finish with a join node to recreate your array in payload again. From the looks of it that would work fine here? Probably be more performant too since then its processing each message asychronously rather then one after another.

@CentralCommand , thanks for the tip. In reply to your thought regarding use of Split and Join, I wasn’t aware of how to use those nodes until now.

…and I will be for this flow and in the future. Thank you for the insight.

1 Like

Yea it works great!

Only thing that is a little tricky with split join as a true loop replacement is if you want to filter out some messages but still rejoin the rest afterwards. By default the split node includes information about how many messages it made so the join node knows how many to wait for. But if you switch the config of the join node from auto you can use the options to handle that with a timeout, a number of messages or some other end signal.

Or filter out those items before the split if you can, that’s easiest.