Hi,
In Node-Red, I want to read the value of a global variable that has a dot in the name
As an example, I want to:
global.get("homeassistant.MyHomeAssistant.states.sun.sun.state");
The problem is the name of the variable sun.sun
I tried several ways to escape that dot, but without any luck.
Any tips are welcome,
thanks,
chrisV
Problem solved:
Iām re-posting the answer here in case someone else has the same issue.
I had also posted this to the Node-Red forum and user @knolleary suggested to use an alternate syntax like this:
global.get("homeassistant.MyHomeAssistant.states['sun.sun'].state")
ā¦which solved the issue
Learned 2 things here:
- there is an alternate syntax to address the ānodesā in a JSON object
- single quotes can also be used and they donāt terminate the double quotes
chrisV
I have same issue , want to access state of specific element but I cant do that from the flow.
Tried your code (adjusted to my needs)
var haCtx = global.get(āhomeassistant.Home_Assistant.states[āswitch.control_ac_emillyā].stateā);
but no results like its coming null.
How can I debug/check ? @chrisV
Canāt get your example to work @chrisV
Trying two ways. Function and Switch.
Function
var item = global.get("homeassistant.homeAssistant.states['input_select.livingroom_mode'].state");
node.warn("find it 1 "+ item);
var item1 = global.get("homeassistant").homeAssistant.states['input_select.livingroom_mode'].state;
node.warn("find it 2 "+ item1);
return msg;
This will log find it 1 undefined
and "TypeError: Cannot read property 'state' of undefined"
.
Switch
Here I donāt get any error, nor does the debug node run. Iām trying to check global
and the value
homeassistant.homeAssistant.states['input_select.livingroom_mode'].state
Looking at the vars they should be there. Would be really nice to run a switch to grab existing value instead of having to setup a current state
node everytime.
Figured it out
# get global variable
var g = global.get("homeassistant");
# get states variable
var states = g.homeAssistant.states;
# get the actual entity that we want
var player = states["media_player.livingroom"];
My apologies, @Evgeny_Golubov and @fbacker I must have missed your earlier replies.
@fbacker Glad you got it working
@Evgeny_Golubov to troubleshoot, you can add a function node and send output to a debug node (see also the commented lines in the function node)
[{"id":"3c0ba1d6.c8ad9e","type":"tab","label":"dummy test","disabled":false,"info":""},{"id":"9b57ce79.ae3158","type":"function","z":"3c0ba1d6.c8ad9e","name":"","func":"\n\n// msg=global.get(\"homeassistant.homeAssistant.states['sun.sun'].state\");\n//msg=global.get(\"homeassistant.homeAssistant\");\n\n\nmsg=global.get(\"homeassistant.homeAssistant.states['sun.sun']\");\nreturn msg;","outputs":1,"noerr":0,"x":272,"y":271,"wires":[["6e5e08ee.1fec3"]]},{"id":"6e5e08ee.1fec3","type":"debug","z":"3c0ba1d6.c8ad9e","name":"Debug","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":507,"y":273,"wires":[]},{"id":"7f2e8e7d.82e158","type":"inject","z":"3c0ba1d6.c8ad9e","name":"now","topic":"","payload":"now","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":"","x":124,"y":127,"wires":[["9b57ce79.ae3158"]]}]
hope this helps,
ChrisV
Hi, I copy all. Then no happen. but
I change like this
//msg.payloadmsg=global.get(āhomeassistant.homeAssistant.states[āsun.sunā].stateā);
//msg.payload=global.get(āhomeassistant.homeAssistantā);
msg.payload=global.get(āhomeassistant.homeAssistant.states[āsun.sunā]ā);
return msg;
-> return: āundefinedā
Where am I wrong?
Hi @Kydan
Iām trying to understand what you did.
Were you able to:
- Import the flow (that I posted), in Node-Red?
- Can you share a print-screen of the debug message that you get? Click on the square witch is attached to the left of the Inject Node, to trigger an event. And then open the debug output to display the debug message.
Here is a screenshot of what you should see
hope this helps,
chris
Thanks. I just fix problem. Just rename āserverā to any other name, in Node red. Thatās all.
Hi @Kydan
Iām sorry, but I donāt understand what you mean with āserverā
Anyway, Iām glad that you got it working
chris
yes, that entry has to match with your home assistant deployment
chrisV
hello! Iām trying to set the AC temperature to the value of a helper.
I know how to make it through a node function, but I would like (in order to learn a bit more) to do it directly with a call service node. Something like this:
temperature: global.get(homeassistant.homeAssistant.states[āinput_number.t_ac_max_bnh_0ā].state)
Is it possible? Where is my error? Thanks!
let tv = global.get(āhomeassistant.homeAssistant.states[āmedia_player.sony_kdl_55w800cā].stateā);
This works for me. This is defining tv before all the if statements.
Hello! thanks for your anwer, but it if not working for me. At the beginning I was getting an error with the ā (expecting "), I changed them and tried different combinations but nothing.
Final try has been this one, but nothing:
{ātemperatureā: global.get(āhomeassistant.homeAssistant.states[input_number.t_ac_max_bnh_0"].state)}
I get this error:
msg : error
āHomeAssistantError: must contain at least one of temperature, target_temp_high, target_temp_low.ā
but I dont understand what you mean by " This is defining tv before all the if statements." I am trying to use a ācall service nodeā.
You are missing some quotes. One at the start of the entity and one at the very end.
global.get('homeassistant.homeAssistant.states["input_number.t_ac_max_bnh_0"].state')
That only works in NR nodes like a function node. Inside a HA node use
$entities('input_number.t_ac_max_bnh_0').state
Edit You are using pretty quotes, they donāt work in NR.
Use standard double or single quotes.
if you get an error with that it likely needs to be converted to a number, in that case use
{
"temperature": $number($entities('input_number.t_ac_max_bnh_0'))
}
thank you all for all the replies!
I have been using the āprettyā quotes beacuse they worked when using the following:
{ātemperatureā:22}
PS: The āprettyā quotes are the default ones for my language configuration, Spanish: Shift + 2.
Anyway, I have been trying your suggestions (and variations) but nothing, still doesnāt work.
If use this:
{ātemperatureā: global.get(āhomeassistant.homeAssistant.states[āinput_number.t_ac_max_bnh_0ā].stateā)}
The error shown is āHomeAssistantError: must contain at least one of temperature, target_temp_high, target_temp_low.ā
On the other hand, I have being checking how do I do these kind of calls for other flows with a Function Node:
msg.payload = global.get(āhomeassistantā).homeAssistant.states[āinput_number.t_ac_max_bnh_0ā].state
This way the Function Node works. There are no { } (logically) and the structure is slighly different, but I have no idea yet.
Thank you all again for your time. As I said, I can cover my needs with a Function Node but, in order to learn a bit more and have a tidier and nicer whiteboard, I would like to make it work with a Service Node, thanks!
JSON (JavaScript Object Notation) structures with special characters in the field names require non-standard referencing.
The referencing syntax depends on the language you are using.
For JavaScript, the usual path reference notation is msg.payload.myfield
Where the field name is a Home Assistant entity, HA make the entity name a combination of the domain and the actual name with a . in the middle. Hence input_number.my_value
. This is a bit of a challenge as you canāt use msg.payload.input_number.my_value
as it will not work!
For JavaScript (ie code within a function node) the referencing format is
[āinput_number.my_valueā]
which makes the name (including the errant .
) a string, and references the object field using the [ ]
notation.
In NR the JavaScript function global.get('homeassistant')
returns the value from the global context variable āhomeassistantā, which is an object, and therefore
global.get('homeassistant').homeAssistant.states["input_number.my_value"].state
does the job of both getting the context varaiable and walking down the path to the input entity state value.
Should you wish to do this directly in the HomeAssistant WebSocket nodes, the most useful approach is to use JSONata (that J: expression option). The fun here is that JSONata is another quite different language, and has a different set of requirements for the same job.
First, we need the JSONata function $globalContext() to get the global context variable. This is a special JSONata function that is added to Node-RED, and will work in any JSONata enabled node (such as the change node), therefore
$globalContext("homeassistant").homeAssistant.states
will get the HA states object. Note that the function call string parameter, as a string literal, can be enclosed by "
or by '
as long as you are consistent.
Second, we need to get at that tricky field name. In JSONata this is done directly in the path expression but using back ticks to constrain the JSON path reference field. The full reference path is something like
$globalContext("homeassistant").homeAssistant.states.`input_number.t_ac_max_bnh_0`.state
Third, once we have the state value, this is most likely to be a string, and therefore where the service call is expecting temperature to be a number, we need to convert the state value.
JSONata has a $number() function, and we could enclose the above as a parameter to this function. However, since things are getting long and complex, the use of the JSONata function chaining operator ~>
can help provide visual clarity.
"70" ~> $number()
chains the result of, in this case a string literal, with the following function, passing the output of the left hand side as context and then replacing the optional input parameter to the $number function. It works!
Therefore your Service Node - Data field, using JSONata, would be (if I have typed everything correctly)
{"temperature": $globalContext("homeassistant").homeAssistant.states.`input_number.t_ac_max_bnh_0`.state ~> $number()}
This works nicely, and since it uses functions that are available throughout Node-RED, this JSONata code can be used in change nodes and inject nodes.
All of this works by getting an entity state value using the HA global context variable. As has been said above, within the WebSocket nodes (and only these nodes) there is another special function $entities() that can be used to return any entity. In your case this would be a bit simpler, and would be
{"temperature": $number($entities('input_number.t_ac_max_bnh_0').state)}
where the entity name (including the errant .
) is passed as a string literal.
oh wow! i was literally impressed, thank you for this very comprehensive post!! I do understand way better how this new language (for me) works, thanks a lot!
Sorry by the delay, I canāt dedicate to HA as much time as I would like, but yes! it does work!
Unlickily, the Beko integration is not working since 2024.05 update, so I will have to wait to test the final loop, but the important thing is that I am being able to send the value, thanks a lot to all and, specially, to @Biscuit !
Jose