Help with nested if-then-else please

Hi again,

I'm slowly learning Node Red and its workings, trying to get a function node working with nested if-then-else statements but despite messing for some hours I just can't grasp it. Could someone kindly have a look at my code below and maybe mould it into a working function.

The idea is that if the msg contains an "on" command and the requested RGB colours are as listed it will set the msg object as shown.

If the "on" command is there and the RGB colours requested do not match the figures shown then set the msg as shown.

If the command is "off" then just do that bit.

Sounds so simple but my coding education stopped at visual basic so I'm way behind and getting on in age now sadly.

Thanks for any guidance

var CT = global.get('homeassistant.homeAssistant.states["input_number.rgb_white_tone"].state');
var BR = global.get('homeassistant.homeAssistant.states["input_number.dr_rgb_default"].state');
CT = parseInt(CT);
BR = parseInt(BR);

if (msg.on === true)
{
    if (msg.rgb[0] == 192 && msg.rgb[1] == 192 && msg.rgb[2] == 192){
        msg.payload =
        "action": "light.turn_on",
        data:
        {"color_temp": CT,
        "brightness": BR}
    } else {
        msg.payload =
        "action": "light.turn_on",
        data:
        {"rgb_color": msg.rgb, "brightness": msg.bri}
    };
};
if (msg.on === false) msg.payload = {
    "action": "light.turn_off"
};
return msg;



The editor should show that you have problems with your brace matching. The statements assigning an object to msg.payload should be

        msg.payload = {
            "action": "light.turn_on",
            data:
            {
                "color_temp": CT,
                "brightness": BR
            }
        }

And similarly for the second one.

You can further simplify it with something like

var CT = global.get('homeassistant.homeAssistant.states["input_number.rgb_white_tone"].state');
var BR = global.get('homeassistant.homeAssistant.states["input_number.dr_rgb_default"].state');
CT = parseInt(CT);
BR = parseInt(BR);

if (msg.on) {
    if (msg.rgb[0] == 192 && msg.rgb[1] == 192 && msg.rgb[2] == 192) {
        msg.payload = {
            "action": "light.turn_on",
            data:
            {
                "color_temp": CT,
                "brightness": BR
            }
        }
    } else {
        msg.payload = {
            "action": "light.turn_on",
            data:
                { "rgb_color": msg.rgb, "brightness": msg.bri }
        }
    };
} else {
    msg.payload = {
        "action": "light.turn_off"
    }
}
return msg;

You can get rid of all the trailing semi-colons too.
I advise against code like

if (msg.on === false) msg.payload = {
    "action": "light.turn_off"
};

Put in the extra braces so that it becomes

if (msg.on === false) {
     msg.payload = {
        "action": "light.turn_off"
    }
};

It makes it clearer.

1 Like

A cup of coffee helped me out, I was over-complicating things it seems, the working version I now have is below. I guess the lesson learnt is to KISS (keep it simple, stupid) :slight_smile:

var CT = global.get('homeassistant.homeAssistant.states["input_number.rgb_white_tone"].state');
var BR = global.get('homeassistant.homeAssistant.states["input_number.dr_rgb_default"].state');
CT = parseInt(CT);
BR = parseInt(BR);

if (msg.on === true && msg.rgb[0] == 192 && msg.rgb[1] == 192 && msg.rgb[2] == 192)
msg.payload =
{
    "action": "light.turn_on",
    data:
    {"color_temp": CT, "brightness": BR}
}
else if (msg.on === true)
msg.payload =
{
    "action": "light.turn_on",
    data:
    {"rgb_color": msg.rgb, "brightness": msg.bri}
};

if (msg.on === false) 
msg.payload = 
{
    "action": "light.turn_off"
};
return msg;

Many thanks, I was typing my update when you replied :slight_smile:

Here's another offering for you...
Note: Untested as I do not use HA.

var CT = global.get('homeassistant.homeAssistant.states["input_number.rgb_white_tone"].state');
var BR = global.get('homeassistant.homeAssistant.states["input_number.dr_rgb_default"].state');

CT = parseInt(CT);
BR = parseInt(BR);

// Default payload
msg.payload = {};

if (msg.on === true) {

    // Check for your "white tone" RGB pattern
    if (msg.rgb && msg.rgb[0] === 192 && msg.rgb[1] === 192 && msg.rgb[2] === 192) {

        msg.payload = {
            action: "light.turn_on",
            data: {
                color_temp: CT,
                brightness: BR
            }
        };

    } else {

        msg.payload = {
            action: "light.turn_on",
            data: {
                rgb_color: msg.rgb,
                brightness: msg.bri
            }
        };

    }

} else if (msg.on === false) {

    msg.payload = {
        action: "light.turn_off"
    };

}

return msg;

Nice, thanks,

I've cleaned it to this point, I think it's a little easier for me to read....

var CT = global.get('homeassistant.homeAssistant.states["input_number.rgb_white_tone"].state')
var BR = global.get('homeassistant.homeAssistant.states["input_number.dr_rgb_default"].state')
CT = parseInt(CT)
BR = parseInt(BR)

if (msg.on === true && msg.rgb[0] == 192 && msg.rgb[1] == 192 && msg.rgb[2] == 192) {
    msg.payload = { "action": "light.turn_on", data: { "color_temp": CT, "brightness": BR }}
}
else if (msg.on === true) {
    msg.payload = { "action": "light.turn_on", data: { "rgb_color": msg.rgb, "brightness": msg.bri }}
}

if (msg.on === false) {
    msg.payload = { "action": "light.turn_off" }
}
return msg

If you want to send the settings into an action node, there is a specific format to use if you want to override the node.

1 Like

IMHO
If you retain the identation in the formatting - then it is much easier to spot a missing { or }.

1 Like

It is best not to use var. Use let or const instead. Google if you don't know why.

In case you did not realise, instead of if (msg.on === true) you can just use if (msg.on). If you know that msg.on is true or false then the two statements are identical. If msg.on is, for example, 1 or "1" or in fact any string or any non-zero number, then the test will fail pass in the first test, but pass fail in the second.

Edit: corrected above. Non zero numbers and all strings (including "false" and "0") are considered truthy in javascript. Number 0 is considered falsey.

1 Like

Thanks, something else learnt and applied.

Another option to simplify nested if/else structures is to break outside, to save annoying bracket counting. For example:

msg.status = 0;

if (condition1)
   return msg.

if (condition2)  {
   if (condition3)  {
      msg.status = 1;
      return msg.
   }

   if (condition4)  {
     msg.status = calcStatus();
     return msg;
   }
   msg.status = 7;
   return msg.
}
msg.status = 99;
return msg;

Personally I would not do that. I have seen, many times, programmers updating code that has early return statements add code not noticing that a return had been made further up, meaning that the added code does not get run.

2 Likes