Help using payload from previous node - Home assistant nodes

Hi,

I just started trying node red out with home assistant, but I don’t really understand how to create flows.
I’m trying to setup a flow to change the color of a light bulb depending on it’s current color (to cycle through a few favourites easily from a hue light switch). Here is what I have so far :

[{"id":"b6ea14f1.63f2c8","type":"api-current-state","z":"5114ad7.ae7af54","name":"","server":"3624259f.a9b772","version":1,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","override_topic":false,"entity_id":"light.0x0017880103ac8bc9_light","state_type":"str","state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","blockInputOverrides":false,"x":400,"y":560,"wires":[["a5faa7af.e81e4"]]},{"id":"11497e10.12b34a","type":"inject","z":"5114ad7.ae7af54","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":100,"y":560,"wires":[["b6ea14f1.63f2c8"]]},{"id":"a5faa7af.e81e4","type":"function","z":"5114ad7.ae7af54","name":"","func":"if (JSON.stringify(msg.data.attributes.rgb_color) == JSON.stringify([128, 128, 128]))\n{\n    msg.payload = [0, 0, 0];\n}\nelse\n{\n    msg.payload = [128, 128, 128];\n}\n\nnode.warn(msg.payload);\n\nreturn msg;","outputs":1,"noerr":0,"x":710,"y":560,"wires":[["ee38cfed.4987b"]]},{"id":"ee38cfed.4987b","type":"api-call-service","z":"5114ad7.ae7af54","name":"","server":"3624259f.a9b772","version":1,"service_domain":"light","service":"turn_on","entityId":"light.0x0017880103ac8bc9_light","data":"{\"rgb_color\": {{payload}}}","dataType":"json","mergecontext":"","output_location":"payload","output_location_type":"msg","mustacheAltTags":false,"x":970,"y":560,"wires":[["68e19db6.128094"]]},{"id":"68e19db6.128094","type":"debug","z":"5114ad7.ae7af54","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":1220,"y":500,"wires":[]},{"id":"3624259f.a9b772","type":"server","z":"","name":"Home Assistant","legacy":false,"hassio":false,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true}]

This does not work however : “Call-service API error. Error Message: extra keys not allowed @ data[‘0’]”
I know that error usually means you’re trying to define your object wrong, like having data inside of data, but I don’t think that’s what I’m doing here. The {{payload}} syntax was found in other posts here and on the node red forums, maybe that’s just not how to do it.
Any tips would be appreciated !
Thanks

I often find the mustache syntax to be problematic. Sometimes it works and other times it’s just all sorts of nope.

So, here’s how I would change your flow:

In your function node, you can remove the JSON.stringify calls as this is done automatically for you for most messages coming over the wire. You can add as many if/else statements as you need to to capture various colors. You can also use the color_name attribute in the data: property and specify any named color.

msg.payload = {
    domain: "light",
    service: "turn_on",
    data: {
        entity_id: "light.office_desk_light_1", //change this to your light entity_id.
        rgb_color: "[0, 0, 0]"
    }
};

if (msg.data.attributes.rgb_color != [128, 128, 128]) {
    msg.payload.data.rgb_color = [128, 128, 128];
}

return msg;

Then, in your svc:: node to change the light, remove the domain, service, entity_id and data lines. You can pass these in from your function node (that’s what the code above does). It’ll end up looking like this:

mustache templates work fine with strings and number and not so well with arrays and object because it turns everything into a string.

You can switch it to JSONata expression and use

{"rgb_color": payload}
1 Like

I didn’t even realize that was a menu, JSON expression does work !
As for the function building the whole msg object I did see that, and it does work fine but I was trying to avoid it as it makes the function bigger and the svc object a bit useless, but I suppose that’s an easy way to do it.

Now it looks like the Philips hue bulb don’t really set the color that precisely, the color you get back is sometimes a few numbers off the one you set so my conditions rarely match … Might have to compare ranges instead of specific colors to get around that, I suppose, I’ll give that a try.

Thanks for the help !

EDIT: There we go, that works fine, now I’ll just add a bunch of colors :

function isSameColorIsh(array1, array2) 
{ 
    r = Math.abs(array1[0] - array2[0]);
    g = Math.abs(array1[1] - array2[1]);
    b = Math.abs(array1[2] - array2[2]);
    if (r > 20 || g > 20 || b > 20) { return false }
    else { return true }
}

deeppink = [255, 24, 149]
white = [255, 255, 255]

msg.payload = {
    domain: "light",
    service: "turn_on",
    data: {
        entity_id: "light.0x0017880103ac8bc9_light",
        rgb_color: "[0, 0, 0]"
    }
};

if (!isSameColorIsh(msg.data.attributes.rgb_color, deeppink))
{
    msg.payload.data.rgb_color = deeppink;
}
else
{
    msg.payload.data.rgb_color = white;
}

node.warn(msg.data.attributes.rgb_color);
node.warn(msg.payload.data.rgb_color);

return msg;
1 Like

I honestly prefer it as I have a bunch of lights that I only turn on and off during various modes (time of day binary sensors) and having a single function to control a single call service node works well for my way of thinking. :smiley:

This is my dining room lights function (turns on/off with motion). I have two global variables that get set when the tod sensors change. From there, I don’t have to query a bunch of things like time or anything like that. Just if the night lights should turn on/off and then what the actual mode is. If one of the tod sensors is on (evening, night, overnight or early morning), then the message object gets returned. If not, no message gets sent. It helps with things like turning lights on during the day (if it’s overcast outside or something like that).

msg.payload = {};

var status  = global.get("night_lights_active");
var mode    = global.get("mode");

node.status({fill:status ? "green": "red", shape: "ring", text: mode });

mode = mode.toLowerCase().replace(" ", "_");

if(status) {
    msg.payload = {
        domain: "scene",
        service: "turn_on",
        data: {
            entity_id: "scene.dining_room_lights_" + mode
        }
    };
    return msg;
}