Sparing lights Node Red challenge

Brainstorming for Node Red experts…
Here is the context, I have four lights (hue or tradfri doesn’t matter) on a candelar, name them Cand1, Cand2, Cand3 and Cand4.
At night, before dark night (nadir) if there is no motion in the room I would like only one of these lights to be lit at 30%.
At real night (during nadir) I want all lights off.
I know how to do that with Cand1 but how can I lit them in turn so that it’s not always the same which is the night light ?
Even if I don’t know how to code it I thought of a function according month day :
LightNumber= mod(Day;4)+1

What I don’t know is how to code this in Node Red to build the light name by concatenation or even if it is possible to make an entity name from a variable.

Thanks to those who take a minute to help

Regards

You can use the function node and then use that to pass into a call service node. This is how I do it for virtually all my lighting nodes:

In the function node, I would do something like this (I’m doing this off the top of my head, so I’m pretty sure there is a better way). Have the function node wired into a blank call service node and it should work.

//Clear the current msg.payload
msg.payload = {};

//If counter hasn't been set in the flow context, set counter to 1.
var counter = flow.get("counter") === null ? 1 : flow.get("counter");
var entity = 'Cand' + counter;

//Increment the counter in the flow context 
flow.set("counter", counter++);

//Create the payload
msg.payload = {
    domain: 'light',
    service: 'turn_on',
    data: {
        entity_id: entity,
        brightness_pct: 30
    }
}

return msg;

Thanks a lot very elegant solution, I ended with a solution where the light number is according to the date of the month. I’ll use the same when time comes to turn off.

var today = new Date();
var today_day = today.getDate();
var lightnum = 0;
lightnum = (today_day % 4) +1;
var lightname = 'light.salleam' + lightnum;

msg.payload = {
    domain: 'light',
    service: 'turn_on',
    data: {
        entity_id: lightname,
        brightness_pct: 30
    }
}

return msg;
1 Like

I perfected a bit my function for a chandelier dealing both with the lights to turn on and the ones to turn off, made it easily adaptable for a bigger chandelier :

// Sparing chandelier lights one per day
// the function finds today’s light which should be on
// and builds an array with on and off lights
// all chandelier lights are supposed to be named in sequence (chand1, chand2,…)
var newmsg = {};
var lgt_basename = ‘light.salleam’; //what is your chandelier lights name without the number
var lgt_many = 4; // how many lights on the chandelier
var today = new Date();
var today_day = today.getDate();
var lightnum = 0;
var m_out = [];
lightnum = (today_day % lgt_many) + 1;
var lighton = lgt_basename + lightnum;

for (var i = 1; i <= lgt_many; i++) {
  if (i != lightnum) {
    newmsg = {};
    newmsg.payload = {
      domain: ‘light’,
      service: ‘turn_off’,
      data: {
        entity_id: lgt_basename + i,
      }
    }
    m_out.push(newmsg);
  } else {
    newmsg = {};
    newmsg.payload = {
      domain: ‘light’,
      service: ‘turn_on’,
      data: {
        entity_id: lighton,
        brightness_pct: 30
      }
    }
    m_out.push(newmsg);

    Copy to clipboard
  }
}
return m_out;

A big thank you to @code-in-progress for pointing me in the right direction.

[{"id":"c010e2e8.d83ef","type":"inject","z":"5e828dc1.ea29c4","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":120,"y":1040,"wires":[["3dbd950c.539a22"]]},{"id":"3dbd950c.539a22","type":"function","z":"5e828dc1.ea29c4","name":"Which bulb on today ?","func":"// Sparing chandelier lights one per day\n// the function finds today's light which should be on\n// and builds an array with on and off lights\nvar newmsg={};\nvar lgt_basename = 'light.salleam'; \nvar lgt_many = 4; // how many lights on the chandelier\nvar today = new Date();\nvar today_day = today.getDate();\nvar lightnum = 0;\nvar m_out=[];\nlightnum = (today_day % lgt_many) +1;\nvar lighton = lgt_basename + lightnum;\n\nfor (var i = 1; i <= lgt_many ; i++) {\n if (i != lightnum) {\n newmsg ={};\n newmsg.payload = {\n domain: 'light',\n service: 'turn_off',\n data: {\n entity_id: lgt_basename + i,\n }\n } \n m_out.push(newmsg);\n } else {\n newmsg ={};\n newmsg.payload = {\n domain: 'light',\n service: 'turn_on',\n data: {\n entity_id: lighton,\n brightness_pct: 30\n }\n }\n m_out.push(newmsg);\n\n }\n}\n\n\nreturn m_out;","outputs":4,"noerr":0,"x":320,"y":1040,"wires":[["c7d70946.b50708"],["c7d70946.b50708"],["c7d70946.b50708"],["c7d70946.b50708"]]},{"id":"c7d70946.b50708","type":"api-call-service","z":"5e828dc1.ea29c4","name":"","server":"b6132cbb.43484","version":1,"debugenabled":false,"service_domain":"homeassistant","service":"","entityId":"","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":600,"y":1040,"wires":[[]]},{"id":"b6132cbb.43484","type":"server","z":"","name":"Home Assistant","legacy":false,"hassio":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true}]

1 Like

This may or may not be more readable to you. It also preserves your original message object and you only need 1 output on the function node.

// Sparing chandelier lights one per day
// the function finds today's light which should be on
// and builds an array with on and off lights
// all chandelier lights are supposed to be named in sequence (chand1, chand2,…)
const lgt_basename = 'light.salleam'; // what is your chandelier lights name without the number
const lgt_many = 4; // how many lights on the chandelier
const today = new Date();
const today_day = today.getDate();
const lightnum = (today_day % lgt_many) + 1;

msg.payload = {
    domain: 'light',
    service: 'turn_off'
};

const messages = Array.from({ length: lgt_many }, () => Object.assign({}, msg));

messages[lightnum].payload = {
    domain: 'light',
    service: 'turn_on',
    data: {
        entity_id: `${lgt_basename}${lightnum}`,
        brightness_pct: 30
    }
};

return [messages];

This one is a bit cryptic for me :slight_smile:

I’ll study it as I’m a beginner on Javascript.

Thanks you very much

It’s just creating an array with the length of lgt_many and then filling it with Object.assign({}, msg) which is just doing a shallow copy of the msg object to get rid of the object reference.

So basically creating a 4 element array with each index equal to the msg object.

OK But how do you fill it with the lights to be off numbers ?

Ho, you use the index as light number, is that it ?

that’s the the second argument of Array.from is doing fill the whole array with the same thing.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from#Using_arrow_functions_and_Array.from