Help needed with JS in function node / JSONata in switch node

Hi. I’m a total noob at everything related, tried researching but it came down to basics problem… felt like a dog who’s human is trying to explain the basics of electrolysis to him when the poor guy is still struggling with “sit”, “lay down” and “come” commands in human language. In any case, if someone’s got the patience and good will, I’m thanking them in advance for taking a look.

So, what I’m trying to do is simplify and future-proof my “location refresh” automation in NR /HA and learn a bit about JS and JSONata at the same time. I have 4 mobile phones (4 person household) I want to refresh the location every 30 minutes - 1 hour when inside on of four defined zones and every 5 - 10 minutes when not in any of those four zones by sending a

{"message":"request_location_update"}

message to/through the homeassistant app on the phones. (Basically, I’m having trouble with a couple of phones not refreshing their location with frequency I’d like them to)

I’ve tried “attacking” the problem from two sides. By using a switch node (and JSONata) and by using a function node (and JS) and came to what boils down to the same problem in both cases. I don’t know how to include a “variable” in $globalContext / global.get “call” (The things in quotes… well, I don’t know if they’re called that way, I hope you understand the meaning I gave them in my mind)

So, here are the ways I’ve tried to get it to work. I placed a “function node” that sends out 4 messages consecutively that only have a payload of “mob1”, “mob2”, “mob3”, “mob4”,

var msg1 = { payload:"mob1" };
var msg2 = { payload:"mob2" };
var msg3 = { payload:"mob3" };
var msg4 = { payload:"mob4" };
return [ [ msg1, msg2, msg3, msg4 ] ];

after that I’ve set up a “delay node” that serves as rate control, letting a message through every 2 seconds just to give HA / NR time to process things. Following that one I’ve tried setting up a “switch node” that would, using the payload of the message it received, check if that phone is in one of four zones ATM; and send the payload down the output 1 or output 2 depending on the result; something like this:

$globalContext("homeassistant.homeAssistant.states['sensor.msg.payload_geocoded_location'].attributes.Zones[0]") = "zone1"

or

$globalContext("homeassistant.homeAssistant.states['sensor.msg.payload_geocoded_location'].attributes.Zones[0]") = "zone2"

etc. I don’t know how to “include” the “msg.payload” into the $globalContext call. I’ve tried replacing a placeholder (like msg.payload) with $replace() inside $globalContext, like this:

$globalContext('$replace("homeassistant.homeAssistant.states['sensor.msg.payload_geocoded_location'].attributes.Zones[0]", "msg.payload", "$msg.payload")') = "zone1"

but (I think I) ran out of quotes and / or parenthesis and never managed to make it work. Came to the same problem when trying to use any of the string manipulation functions in JSONata I’ve found and thought would suit my needs (splitting and joining etc).

I’ve then tried setting up a function node but essentially came to the same problem - how to compose a "global.get" partly from predefined parts and partly from the payload of the message received. I’ve tried something like:

var mob = msg.payload;
var zone1 = "zone1";
var zone2 = "zone2";
var zone3 = "zone3";
var zone4 = "zone4";
var lok = global.get('homeassistant.homeAssistant.states["sensor.[mob]_geocoded_location"].attributes.Zones[0]')

where I’d insert the mob variable into global.get (at the right position) and compare the “lok” to the “zone1”, “zone2”, “zone3” and “zone4” and send “mob” to the first output if lok == one of the zones and the second output if not.

I would then put in a rate control or delay (haven’t gotten that far yet) of 5-10 minutes on output 1 and 30min-1h on output 2 and send a message to the “call service node” that does the message sending to the phone defined in msg.payload it receives. Something like:

notify.mobile_app_{{payload}}

full flow would look something like this:

How do I insert a variable into a JSONata and/or JS to do what I need it to do? Is it even possible? Is it a good way of approaching the problem?

Thanks for any help in advance. And please tell me if I need to include anything else in my explanation of the problem I’m trying to solve.

Not tested, but might give you an idea of how it could be done.

[{"id":"ccd2011358c30ea0","type":"inject","z":"894a6b3077af9604","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":172,"y":1968,"wires":[["3f91cb10701668d9"]]},{"id":"3f91cb10701668d9","type":"ha-get-entities","z":"894a6b3077af9604","name":"get geocoded location entities","server":"","version":0,"rules":[{"property":"entity_id","logic":"is","value":"sensor\\.[a-z]+_geocoded_location","valueType":"re"}],"output_type":"split","output_empty_results":false,"output_location_type":"msg","output_location":"payload","output_results_count":1,"x":402,"y":1968,"wires":[["eb9fe9f19ac8cb85"]]},{"id":"a3b709c843f4aea3","type":"switch","z":"894a6b3077af9604","name":"","property":"payload.attributes.Zone[0]","propertyType":"msg","rules":[{"t":"eq","v":"zone1","vt":"str"},{"t":"eq","v":"zone2","vt":"str"},{"t":"eq","v":"zone3","vt":"str"}],"checkall":"true","repair":false,"outputs":3,"x":850,"y":1968,"wires":[["7211598551173d36"],["91a9c179acdee726"],["11399226fd76774a"]]},{"id":"6cbb5ce27f3b7587","type":"api-call-service","z":"894a6b3077af9604","name":"","server":"","version":3,"debugenabled":false,"service_domain":"notify","service":"mobile_app_{{user}}","entityId":"","data":"{\"message\":\"request_location_update\"}","dataType":"jsonata","mergecontext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1330,"y":1920,"wires":[[]]},{"id":"eb9fe9f19ac8cb85","type":"change","z":"894a6b3077af9604","name":"parse user and set topic","rules":[{"t":"set","p":"user","pt":"msg","to":"$match(payload.entity_id, /sensor\\.([a-z0-9]+)_geocoded_location/).groups[0]\t","tot":"jsonata"},{"t":"set","p":"topic","pt":"msg","to":"payload.entity_id","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":670,"y":1968,"wires":[["a3b709c843f4aea3"]]},{"id":"7211598551173d36","type":"delay","z":"894a6b3077af9604","name":"","pauseType":"queue","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"30","rateUnits":"minute","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"allowrate":false,"outputs":1,"x":1040,"y":1920,"wires":[["6cbb5ce27f3b7587"]]},{"id":"91a9c179acdee726","type":"delay","z":"894a6b3077af9604","name":"","pauseType":"queue","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"5","rateUnits":"minute","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"allowrate":false,"outputs":1,"x":1030,"y":1968,"wires":[["6cbb5ce27f3b7587"]]},{"id":"11399226fd76774a","type":"delay","z":"894a6b3077af9604","name":"","pauseType":"queue","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"60","rateUnits":"minute","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"allowrate":false,"outputs":1,"x":1044,"y":2016,"wires":[["6cbb5ce27f3b7587"]]}]
1 Like

The term you’re looking for is string concatenation.

https://docs.jsonata.org/other-operators#-concatenation
https://www.samanthaming.com/tidbits/15-4-ways-to-combine-strings/

This would have actually worked if you had quotes correct.

$globalContext($replace("homeassistant.homeAssistant.states['sensor.msg.payload_geocoded_location'].attributes.Zones[0]", "msg.payload", payload)) = "zone1"

With string concatenation

$globalContext("homeassistant.homeAssistant.states['sensor." & payload & "_geocoded_location'].attributes.Zones[0]") = "zone1"
var mob = msg.payload;
var zone1 = "zone1";
var zone2 = "zone2";
var zone3 = "zone3";
var zone4 = "zone4";
var lok = global.get(`homeassistant.homeAssistant.states["sensor.${mob}_geocoded_location"].attributes.Zones[0]`);
2 Likes

Thank you! Will test it out as soon as I get home. Can’t wait. Thanks a whole lot for taking the time and spreading the knowledge!