Companion app, does it allow function node updates to its created entities?

I have an HVAC system I am controlling from Node Red.

I am trying to design it for a variable number of zones. That seems hard to do with separate nodes, but easy to do in a function node, just loop.

Right now I have a fixed-size and rather kludgy set of nodes that interaction with context storage and basically copy it into HA input_numbers.

I discovered the companion app, which gives a more efficient thing than input_numbers, buttons etc.

But I still appear to be stuck updating these with individual flows (for example, if I had z1_high and z1_low, z2_high and z2_low, etc. and want to update them from a function node. So I donā€™t have to hard code how many there are (i.e. a node(s) for each update)?

Is there a way to do so? Does the companion somehow allow it?

Linwood

PS. I realize I can output AN entity name and update it in a node, and so not have to have a specific one. But I donā€™t see a way to update X entities in a single output from the function node, e.g. loop through a message structure of arbitrary length updating entities?

It sounds like you want to reuse 1 call service node for multiple entities? You can leave it blank and send the config to it in the following format

{
    "domain": "homeassistant",
    "service": "turn_on",
    "target": {
        "area_id": ["kitchen"],
        "device_id": ["8932894082930482903"],
        "entity_id": ["light.kitchen", "switch.garage_light"]
    }
    "data": {
        "brightness_pct": 50
    }
}

https://zachowj.github.io/node-red-contrib-home-assistant-websocket/node/call-service.html#input

No, I think I asked it badly.

Let me back up. I have a bunch of context flow variables, e.g. z1_high, z1_low, z2_high, z2_low, etc as examples (there are others).

I donā€™t want to build the flows so the number of them is fixed. I want it to be a variable, e.g. ā€œzonesā€.

All the decisions are made in a function node. It can loop through an arbitrary number of zones, and calculate how each zoneā€™s thermostat should be set, and it also needs to set a slide in HA to show any changes it made in the z1_low, z1_high, etc. variables (which are at the moment input_numbers in HA, and separate flow variables in NR).

Right now when the function node completes it sets all the context variables, then after it exits I have a current-state-node that compares the flow variable with the entity in HA and if different calls a single service node to set the HA node. That (the service node) is fine, itā€™s singular, but I need a separate and explicit number of current-state-nodes to check each context variable. This means Iā€™m hard coding how many zones.

One thing that solves this is if, inside the function node, I can just do some kind of an API call to a service to set an HA entityā€™s value or attribute. Then I can do something like for (i=1, i<zones, i++) call-mystery-service(ā€œzā€ + i + ā€œhighā€,value[i]).

If I have to fall out of the function node I donā€™t see how to loop over a bunch of context variables and HA entities to check them and update.

Does that make sense?

I know how to output one entity name and value and pass to a subsequent node to update it. I just donā€™t see how to do an arbitrary number of them.

Linwood

Iā€™m still a little fuzzy on what you are trying to accomplish. I have this in a function to push an array of js objects 1 at a time to a call service. If this doesnā€™t help post the function that you want to use.

var delay = 0;
let i = 0;
msg = {};

function calanderPush() {
    setTimeout(function () {
        if (i < pokemonCalander.length) {
            msg.heading = pokemonCalander[i].heading;
            msg.summary = pokemonCalander[i].name;

            let start = pokemonCalander[i].start;
            let endDate = pokemonCalander[i].end;

            let image = pokemonCalander[i].image;
            let link = pokemonCalander[i].link;

            msg.location = `${image},${link}`;

            node.send(msg);
            node.status({ fill: "green", shape: "ring", text: "entry " + (i + 1) + " of " + totalCount });
            delay = 2000;
            i++;
            calanderPush();
        }
        else {
            node.status({ fill: "green", shape: "dot", text: "done" })
            node.done
        }
    }, delay)
}

calanderPush();

Edit: I pulled out some irrelevant code.

Edit 2 I donā€™t think the above is what you are after but I will leave it jic.

There is a global store of all home assistant states in nodered available to the function node. The check could be done in a function rather than the current state. You would just need a variable in the global store path to get the right value to make the comparison.

In your home assistant server config node there is a check box to enable global storage, you need to enable that if it is not already.

I use the following to pull states into a function, the entity would be replaced with a variable.

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

The list piece of code Mikefilla post is a reference to the state values HA publish into Node Red.

When you have enabled the Globale storage option.
Then click the down arrow in the upper right corner and choose Context Data then click the refresh icon for the Global section.
This should bring up the HA global context object you can expand and see what is available.

There is little value in running your own state engine in Node Red, when you sync all values to HA anyway.
Just use the HA state engine directly.

So Iā€™m completely confused now, or maybe a glimmer of hope.

@Mikefila I have been under the impression that you could exit a node and emit a message only once. This shows you can do them asynchronously and wait, but I also saw inside the documentation where you can emit an array and it says it emits them one by one. That may get me what I need. Thank you.

@WallyR yes, I am using that global.get with HA to pull in staets. What I really want is to be able to use that API to call a service like set_value. But that doesnā€™t seem to exist, right? You can only call a HA service like set_value by emitting a message to a call-service-node?

2 ways to send messages through an output from a function node return msg and node.send(msg). The latter will async send when it is reached and then carry on. When using node.send after the last message you need to run node.done to tell it is finished.

set timeout will let you add a delay. It works by loading the block into memory and then waiting the delay period before executing. The way I have it setup in a function, because I recall the function at the end of the block, it has to wait 2 seconds before starting again. The result is a send every 2 seconds.

If you were to use that in a for loop, it would run through the loop almost instantly and load every block with a 2 second delay into memory. The result would be every message would be sent together 2 seconds later. In that case every iteration you would need to add 2 seconds to the delay.

So almost instantly it would load all blocks in the loop, the first being sent after 2000, the next at 4000, then next 6000. The result being each one is sent 2 seconds apart.

In the function I set the delay at zero, so the first run through there is no delay. After that each block is delayed 2 seconds. I hope that makes sense. For reference I usually start at w3 JS and if Iā€™m not really clear and run testing I head over to mdn.

mdn is more in depth than w3 but it could be confusing at times when using it as a starting point. The nice thing about mdn, it has an in page editor as opposed to w3ā€™s is on a separate page. This way when testing you have the reference on the same page.

Well, Mikefilla posted before I could finish, so here is the link to his text. :slight_smile:

https://nodered.org/docs/user-guide/writing-functions

1 Like

I found that, but it is about what, not so much why, or when. For example it says:

" To help it do so, the Function node should call node.done() at the appropriate time."

Soā€¦ what is the appropriate time? Not trying to be snarky, but while very familiar with the concept of async vs sync calls, I have no idea what it is I am waiting on. I was wondering if there was something that was a bit more basic, that didnā€™t assume someone already knew when ā€˜appropriateā€™ was?

Or how node.send interactions with return [msg], do I return the last one at the return, or return a null there?

And does node.send always send to the flow on the 1st output?

        else {
            node.status({ fill: "green", shape: "dot", text: "done" })
            node.done
        }

from the example above node.done should be node.done()

1 Like

This was a massive revelation and simplification, that I could have one function node emit an arbitrary number of flows (not sure if that is the right term) and then act on them. So instead of this large grid of partially hard coded call service nodes and comparisons to flow context I just output the entity to change and value(s). A multi-page messy flow is now trivial.

Itā€™s all in the documentation, but somehow never before did it get through that one node could output multiple flows (except for multiple outputs). I just assumed it was one-for-one, and never quite understood the node.send concept.

All better now. Thank you.