Context variable that (partly) references other context variables dynamically

I run node red in conjunction with home assistant.

I would like to have a context variable (like flow.mydatacollection) that contains a json that has normal key-value pairs (that are "manually" updated) and references to other context variables (in my case some global.homeassistant.state/attributes).

Is there a possibility that these references to other context variables are really just references and therefore updated automatically, so i can use them in a sequence.

Or do I need to update them manually (with a function node that runs flow.get or similar)

1 Like

You cannot maintain aliases/links in a context variable as far as I know. And unfortunately, the current standard context variables do not have update events associated with them so you can't fully automate updates via events. (Something I've wanted for years).

So some lateral thinking is required so that your flows update all the related data variables together.

1 Like

If you assign the value of an object to an object in context, they WILL be references.

e.g. change (set flow.mydatacollection to the value of global.homeassistant.state.x)
if any value inside the object x changes, the reference in flow.mydatacollection will be updated by reference (actually, nothing is updated, it is a kinda pointer/reference!)

This is very easy to text and check for your self.

chrome_KtjIddwErn

This can be done using the change node (better/easier) or a function node (harder/more control)

1 Like

They can be reactive if you want them to be.

chrome_3qzuDFxwfj

^ a subflow I wrote that simplifies the registration of a variable as a proxy object.

1 Like

Only for certain context stores. They certainly won't be for most of them. But possibly for memory vars. Even then, does that work when using get/set? I've never tried it.

Interesting, is there an example flow somewhere?

Hi Steve,

thank you very much for the demo.

Unfortunately I am not able to reproduce the functionality so far. If use a change node to set the flow.variable to a value derived from global context it is static? This happens regardless if I choose "Deep Copy" (to clone?) or leave it unticked.

This is my test flow:


[{"id":"ac8c8e6801235d2f","type":"inject","z":"7d8b869bb3b425a1","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"0","payloadType":"num","x":2790,"y":160,"wires":[["cf136a090b2661da"]]},{"id":"0560db25393fde38","type":"inject","z":"7d8b869bb3b425a1","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"5","payloadType":"num","x":2790,"y":280,"wires":[["57dde256ef83d74e"]]},{"id":"3926bddff27c2a32","type":"inject","z":"7d8b869bb3b425a1","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"2","payloadType":"num","x":2790,"y":240,"wires":[["cb7178c2a1a28587"]]},{"id":"c434ebc8fa094b2f","type":"inject","z":"7d8b869bb3b425a1","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1","payloadType":"num","x":2790,"y":200,"wires":[["0da33b58896a17dc"]]},{"id":"cf136a090b2661da","type":"change","z":"7d8b869bb3b425a1","name":"","rules":[{"t":"set","p":"mydatacollection.warm5","pt":"flow","to":"homeassistant.homeAssistant.states[\"input_boolean.thermo_5_warm_abends\"].state","tot":"global"}],"action":"","property":"","from":"","to":"","reg":false,"x":2990,"y":160,"wires":[["c9ed27dde498d0bf"]]},{"id":"0da33b58896a17dc","type":"change","z":"7d8b869bb3b425a1","name":"read flow.variable","rules":[{"t":"set","p":"payload","pt":"msg","to":"mydatacollection.warm5","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":2950,"y":200,"wires":[["9feb2500762209ba"]]},{"id":"9feb2500762209ba","type":"debug","z":"7d8b869bb3b425a1","name":"debug 66","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":3120,"y":200,"wires":[]},{"id":"c9ed27dde498d0bf","type":"debug","z":"7d8b869bb3b425a1","name":"debug 68","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":3240,"y":160,"wires":[]},{"id":"cb7178c2a1a28587","type":"api-current-state","z":"7d8b869bb3b425a1","name":"","server":"304064ba.5ac44c","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"input_boolean.thermo_5_warm_abends","state_type":"str","blockInputOverrides":true,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":3060,"y":240,"wires":[["d954038c91bbc542"]]},{"id":"d954038c91bbc542","type":"debug","z":"7d8b869bb3b425a1","name":"debug 71","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":3340,"y":240,"wires":[]},{"id":"57dde256ef83d74e","type":"api-call-service","z":"7d8b869bb3b425a1","name":"toggle","server":"304064ba.5ac44c","version":7,"debugenabled":false,"action":"input_boolean.toggle","floorId":[],"areaId":[],"deviceId":[],"entityId":["input_boolean.thermo_5_warm_abends"],"labelId":[],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","blockInputOverrides":true,"domain":"input_boolean","service":"toggle","x":2910,"y":280,"wires":[[]]},{"id":"304064ba.5ac44c","type":"server","name":"Home Assistant","addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"","connectionDelay":false,"cacheJson":false,"heartbeat":false,"heartbeatInterval":"","statusSeparator":"","enableGlobalContextStore":false}]

Any ideas why this behaviour differs? Maybe you could share your demo for comparision?

If you clone, you will lose the reference.

Make sure you set an object into the flow var not a number/string/immutable type.

E.g. don't include .state

I just cant make it happen.

Since I don't use home assistant, I cannot test this.

It may be that HA replaces the object instead of updating it (in which case it won't work).

You will need another means of watching the HA variable change and update your own flow context variables (isn't there a state node that emits on change?)

Would love to see that as well !

I'll post the subflow tomorrow after I tidy it up.

1 Like

This portion of the flow is not working?

image

Do you have global context enabled? Open any HA node, where the server select is, click the pencil to edit.

image

Check the box for "Enable global context store" click update at the top, then done, then deploy and restart the node red addon.

Interesting question! I’ve run into a similar situation before where I needed to reference part of a context variable dynamically, and yeah — it’s a bit tricky to get working cleanly.

From what I’ve found, you can kind of work around it by building the variable name as a string and then using flow.get() or global.get() with that dynamic key. Something like:

javascript..

let base = flow.get("baseKey"); // e.g., "user123"
let dynamicKey = base + "_settings";
let value = flow.get(dynamicKey);

It’s not super elegant, but it’s worked for me in a few flows. Would love to know if there’s a cleaner “native” way to reference nested/dynamic keys directly in the templates or function nodes though.

I'm following this thread.. curious to see what others suggest!

I´ll try to find the reason but if this is not working I will probably go for that route and just use some regex patterns for the relevant entities and a full flow.get of all stored values then...

So the flow is working, i can set the flow.variables and read them. But if the state of the entity changes (that is stored in the global context and changes too) the flow variable does not update, unless i execute the change node manually.

I did not but tried it. No change/avail.
I am not sure what this setting really does as I had the home assistant state available in global storage although it was deactivated?

I'm still unclear of how it's being updated and used in your flow. If by chance you are trying to use context inside a HA node as shown below

That is not dynamic. It will read the flow/global on deploy only. If that is not it could you post an example where you encounter the static value.

Looking over what you wrote, just because you set a flow value to that of a global value does not link them together. Every time the global updates you need to update the flow variable either manually or through an automation.

It’s exactly the question if this is possible in any way :grinning_face:

As Steve demonstrated with the demo clip it seems to be working for him/under certain circumstances/prerequisites

As I said before

chrome_VaHkd2ibIZ

[{"id":"2d6df78b1e471cf2","type":"inject","z":"0df4284c28cd9b46","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"0","payloadType":"num","x":890,"y":220,"wires":[["abaa36d76563ec7e"]]},{"id":"abaa36d76563ec7e","type":"change","z":"0df4284c28cd9b46","name":"","rules":[{"t":"set","p":"homeassistant.homeAssistant.states.input_boolean.thermo_5_warm_abends.state","pt":"global","to":"0","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":1360,"y":220,"wires":[["25a4461983d8c59c"]]},{"id":"25a4461983d8c59c","type":"change","z":"0df4284c28cd9b46","name":"set flow.mydatacollection.warm5 to the reference of thermo_5_warm_abends","rules":[{"t":"set","p":"mydatacollection.warm5","pt":"flow","to":"homeassistant.homeAssistant.states.input_boolean.thermo_5_warm_abends","tot":"global"}],"action":"","property":"","from":"","to":"","reg":false,"x":1310,"y":280,"wires":[[]]},{"id":"69f47bb945d8cc61","type":"inject","z":"0df4284c28cd9b46","name":"random int","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"(\t    $minimum := 1;\t    $maximum := 10;\t    $round(($random() * ($maximum-$minimum)) + $minimum, 0)\t)","payloadType":"jsonata","x":900,"y":400,"wires":[["45b1494dc5faf42b"]]},{"id":"45b1494dc5faf42b","type":"change","z":"0df4284c28cd9b46","name":"","rules":[{"t":"set","p":"homeassistant.homeAssistant.states.input_boolean.thermo_5_warm_abends.state","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1320,"y":400,"wires":[[]]},{"id":"1e1ee443d6fa634f","type":"inject","z":"0df4284c28cd9b46","name":"","props":[],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":890,"y":340,"wires":[["9da17416b34ce628"]]},{"id":"9da17416b34ce628","type":"change","z":"0df4284c28cd9b46","name":"get flow.mydatacollection.warm5.state","rules":[{"t":"set","p":"payload","pt":"msg","to":"mydatacollection.warm5.state","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":1150,"y":340,"wires":[["433d9a321795f0c3"]]},{"id":"433d9a321795f0c3","type":"debug","z":"0df4284c28cd9b46","name":"","active":true,"tosidebar":false,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":1410,"y":340,"wires":[]}]

however

as I said before:

Home Assistant globals are read only in a sense. They are there for reference only. They can not change the state of an entity inside HA. They can be temporarily changed in NR but will revert back when the entity is updated. To change the state of entities in HA, you should use the action node.

Thats not the point of discussion or the focus of my demo.

The OPs demo clearly does not directly set the value in the global context:

The point was to store a reference to the (as you call it "read only") value

In my demo above, I manually set the value of homeassistant.homeAssistant.states.input_boolean.thermo_5_warm_abends.state ONLY to simulate what HA does (because I dont use HA).