Maths with multiple HA entities

Noob question.

I managed to work out how to perform a simple math operation with a single HA entity value. I used a Function node and did some simple maths like this (the msg.payload input is a number from a HA Current State node):

msg.payload = (100 - msg.payload)
return msg;

But I want to perform some maths with more than one HA entity value. e.g. multiply the Current State from two different HA entity values together.

This eludes me.

What sort of node should I use / how to do this?

Thanks

In the upper right corner click the down arrow and select context data, then click the refresh of the global section.
You can now see all the HA values.

In a function node you can use them as this:

msg.states = global.get('homeassistant').homeAssistant.states["binary_sensor.node_red_update_available"].state;
return msg;

Thanks. I don’t quite understand that. I can see the drop down you mention and have refreshed the global section but I don’t understand what this is:

msg.states = global.get('homeassistant').homeAssistant.states["binary_sensor.node_red_update_available"].state;
return msg;

It may be I have not phrased my question well, not sure.

Let’s say I have two HA entities:

sensor.battery_state_of_charge
and
sensor.solcast_forecast_remaining_today

Say I want to perform some maths using the values of those two entities (I actually want to use more inputs but let’s keep it simple for the sake of the exercise).

I can use a Home Assistant Current State node to see the value for each individually but I don’t understand how to combine the two values in the one node to perform some maths on them.

[{"id":"e6680e5ea2e27b8c","type":"inject","z":"1813665b6a60a2aa","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":108,"y":368,"wires":[["102510e999a5b578"]]},{"id":"102510e999a5b578","type":"api-current-state","z":"1813665b6a60a2aa","name":"","server":"","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"sensor.battery_state_of_charge","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"battery","propertyType":"msg","value":"","valueType":"entityState"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":388,"y":368,"wires":[["421a9a137532cec7"]]},{"id":"421a9a137532cec7","type":"api-current-state","z":"1813665b6a60a2aa","name":"","server":"","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"sensor.solcast_forecast_remaining_today","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"solcast","propertyType":"msg","value":"","valueType":"entityState"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":798,"y":368,"wires":[["f4ef580e088673d1"]]},{"id":"4c0f64888cb25e62","type":"debug","z":"1813665b6a60a2aa","name":"debug 23","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1260,"y":368,"wires":[]},{"id":"f4ef580e088673d1","type":"function","z":"1813665b6a60a2aa","name":"maths","func":"msg.payload = 100 - (msg.battery * msg.solcast);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1090,"y":368,"wires":[["4c0f64888cb25e62"]]},{"id":"cfe848151789b1b2","type":"inject","z":"1813665b6a60a2aa","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":100,"y":416,"wires":[["49a2fb506c3f0e2b"]]},{"id":"49a2fb506c3f0e2b","type":"api-current-state","z":"1813665b6a60a2aa","name":"","server":"","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"sensor.battery_state_of_charge","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"100 - (\t   $number($entity().state) * $number(\t       $entities(\t           \"sensor.solcast_forecast_remaining_today\"\t       ).state\t   )\t)","valueType":"jsonata"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":380,"y":416,"wires":[["a348b6203bbca0c5"]]},{"id":"a348b6203bbca0c5","type":"debug","z":"1813665b6a60a2aa","name":"debug 24","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":652,"y":416,"wires":[]}]
1 Like

The global.gwt function was just an example to extract a value.
Had it been a numeric value, them you could a like + 100 I’m the end or you could add - and then a global.get more.

Thanks Kermit.

I learned a lot from those examples. The first one with the Function node makes a bit more intuitive sense to me.

I didn’t realise you could put status nodes like that in series, nor that you can define the output msg to a custom name such as:
msg.battery

The second example uses a Json expression, which I know bugger all about, so thanks for the example.

Much to learn.

Thanks WallyR.

One day it’ll tweak for me what this means and/or how or when I might use it. For now I don’t understand what that code does. All it does for me is show an error in the debug window.

Oh, maybe you do not have node red installed as an addon.
I just picked that value as an example because I thought you had it.

Try this instead:

global.get('homeassistant').homeAssistant.states["sensor.battery_state_of_charge"].state

I ended up with this as a test. It calculates whether or not supplemental charging would be required to complete a full charge of my off-grid battery.

Basic logic is to estimate out how much PV output is expected from the off-grid PV array for the remainder of the day (a bit convoluted due to the available entities I have to work with, plus some allowances for error/inefficiencies), and compare that with how much energy is currently required to charge the battery to 100%.

[{"id":"4e91b577f9dc2162","type":"api-current-state","z":"eafe579046581a4e","name":"PV Forecast - Today's Combined Array Total","server":"58a17342.ac5f9c","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"sensor.solcast_forecast_today","state_type":"num","blockInputOverrides":false,"outputProperties":[{"property":"forecasttoday","propertyType":"msg","value":"","valueType":"entityState"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":380,"y":820,"wires":[["cd43495a2e709e6a"]]},{"id":"845e2d4da2a88c34","type":"inject","z":"eafe579046581a4e","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":100,"y":820,"wires":[["4e91b577f9dc2162"]]},{"id":"cd43495a2e709e6a","type":"api-current-state","z":"eafe579046581a4e","name":"PV Forecast - Remaining Today","server":"58a17342.ac5f9c","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"sensor.solcast_forecast_remaining_today","state_type":"num","blockInputOverrides":false,"outputProperties":[{"property":"forecastremaining","propertyType":"msg","value":"","valueType":"entityState"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":340,"y":880,"wires":[["12182a3aba5abe7b"]]},{"id":"12182a3aba5abe7b","type":"api-current-state","z":"eafe579046581a4e","name":"PV Forecast - OffGrid Array","server":"58a17342.ac5f9c","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"sensor.solcast_wattmatters_garage","state_type":"num","blockInputOverrides":false,"outputProperties":[{"property":"forecastgarage","propertyType":"msg","value":"","valueType":"entityState"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":320,"y":940,"wires":[["59e291b3ef1668c1"]]},{"id":"59e291b3ef1668c1","type":"api-current-state","z":"eafe579046581a4e","name":"Battery SOC","server":"58a17342.ac5f9c","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"sensor.battery_state_of_charge","state_type":"num","blockInputOverrides":false,"outputProperties":[{"property":"batterySOC","propertyType":"msg","value":"","valueType":"entityState"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":270,"y":1000,"wires":[["a611421366c0e28a"]]},{"id":"a611421366c0e28a","type":"function","z":"eafe579046581a4e","name":"Calculate PV Surplus/Deficit","func":"msg.payload = 0.8 * ((msg.forecastremaining / msg.forecasttoday) * msg.forecastgarage) - ((100 - msg.batterySOC) / 10);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":330,"y":1060,"wires":[["284967eb18418534","2bb7a68b48da92b4"]]},{"id":"284967eb18418534","type":"debug","z":"eafe579046581a4e","name":"Expected PV Surplus/Deficit","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":690,"y":1060,"wires":[]},{"id":"2bb7a68b48da92b4","type":"switch","z":"eafe579046581a4e","name":"Supplemental Charging Required?","property":"payload","propertyType":"msg","rules":[{"t":"lt","v":"0","vt":"str"},{"t":"gte","v":"0","vt":"str"}],"checkall":"false","repair":false,"outputs":2,"x":350,"y":1140,"wires":[["95a6279f5440517c"],["4a1c403cf26b20b9"]]},{"id":"95a6279f5440517c","type":"change","z":"eafe579046581a4e","name":"Supplemental charge IS required","rules":[{"t":"set","p":"payload","pt":"msg","to":"Yes","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":700,"y":1120,"wires":[["e7cda27faa7a98fb"]]},{"id":"4a1c403cf26b20b9","type":"change","z":"eafe579046581a4e","name":"Supplemental charge IS NOT required","rules":[{"t":"set","p":"payload","pt":"msg","to":"No","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":720,"y":1160,"wires":[["e7cda27faa7a98fb"]]},{"id":"e7cda27faa7a98fb","type":"debug","z":"eafe579046581a4e","name":"Is Supplemental Charging Required?","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1070,"y":1120,"wires":[]},{"id":"58a17342.ac5f9c","type":"server","name":"Home Assistant","version":4,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":30,"areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":"at: ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"h23","statusTimeFormat":"h:m"}]

No doubt there are far more efficient ways of doing it but it’s a start.

With this I can choose whether to set my system to turn on/off supplemental charging from the grid-tied PV array.

That will be determined by whether the grid-tied PV array has sufficient excess energy available, i.e. is exporting enough power to the grid to supply supplemental charging. This avoid grid imports but also unnecessary use of supplemental charging which otherwise could earn export credits.

Thanks, I do have the Home Assistant Node Red add on. That’s what I’m using.

That suggested sequence returns a time stamp value, not the value of the entity state.

If I use your earlier suggested option:

msg.states = global.get('homeassistant').homeAssistant.states["binary_sensor.node_red_update_available"].state;
return msg;

I get this:

TypeError: Cannot read properties of undefined (reading 'state')

try to compare the line with the global variables in the context data.

oh and remember to set the debug node to the complete message.
I have put the data into msg.states and not msg.payload.

I don’t know what that means.

How? I see no option for changing what the debug window shows. I can clear the messages and filter which flows populate the debug window but that’s about it. I looked at the NR documentation and it doesn’t mention anything else.
https://nodered.org/docs/user-guide/editor/sidebar/debug

This is what I see:

In your second screenshot you have refresh the globals variables.
You then just need to expand them to see it.
Click the > to the right of the { to expand the values.
Now the line should make more sense.

Doubleclick your debug node and click the output field and set it to complete message

Ah, thanks.

I don’t see the entity you referred to but I don’t know if I’m looking in the right area: