Help with creating a dynamic list of tripped sensors

I'm attempting to create a list of contact sensors which are in the open state.

For example I have a node which returns the state of sensor XYZ. So if the payload is "open", the text "XYZ" is added to the string/list which I can do (each addition is delineated with a new line).

Conversely, if the state of XYZ changes to closed I want to be able to search for and delete "XYZ" from the string, and this part I'm not sure how to to achieve.

Any help/pointers gratefully received! String manipulation unfortunately is not one of my coding strengths.

It would be easier to give some advice if you tell us how the data structure looks like. I assume the list is an array but if you decided to store data in an object then the code to achieve what you want would be different.

I see, thanks. To be honest I haven't given thought to the structure of the list. The intention is to be able to export a list of what sensors are "open" at any one time in the simplest possible way. The number of devices that would likely be populating the array/list at any time would be small (10 at most).

I'll give it some more thought to flesh it out further.

That is not the ideal way to achieve what you want.

Ideally you would store the state of the item and then build a string based on the state.

e.g. you could store the sensors values an array like this...

[
  { "name": "sensor 1", "state": false },
  { "name": "sensor 2", "state": true },
  { "name": "sensor 3", "state": true }, 
]

or an object like this...

{
 "Sensor 1": false,
 "Sensor 2": true,
 "Sensor 3": true
}

With an array, you could build a status string like this...

var offSensors = sensors.filter(e => e.state == false).map(e=>e.name).join(",");
//returns  'sensor 1'

var onSensors = sensors.filter(e => e.state == true).map(e=>e.name).join(",");
//returns  'sensor 2,sensor 3'

However, to update a value in the array is a bit harder (much easier with an object) so that is what i will demo...


Store sensors states in an object...

Premise...

Store a single value for each sensor named by msg.topic in an object named sensors in a flow context variable.

  • When updating a state in flow context, msg.topic must hold the sensor name and msg.payload must have the sensor value
  • Demo assumes msg.payload will be boolean (true or false)

Example data...

{
 "Sensor 1": false,
 "Sensor 2": true,
 "Sensor 3": true
}

//adding / updating a sensors value

var sensors = flow.get("sensors") || {};   //get the sensors state from flow context
var sensorName = msg.topic;                //get sensor name from incoming msg
sensors[sensorName] = msg.payload;         //store value under a key in the sensors object 
flow.set("sensors", sensors);              //update the flow context

getting a string of on or off sensors...

var sensors = flow.get("sensors") || {}; //get the sensors state from flow context

msg.payload = {}; //prepare the payload as an object, ready for the off and on strings

msg.payload.offSensors = Object.entries(sensors).filter(e => e[1] == false).map(e=>e[0]).join(",");
//return example  'sensor 1'

msg.payload.onSensors = Object.entries(sensors).filter(e => e[1] == true).map(e=>e[0]).join(",");
//return example 'sensor 2,sensor 3'

return msg;
2 Likes

Wow - thanks for that, it will keep me occupied for a fair few days working through it!

What is it being exported to and what use will then be made of it? The answer to that will influence which way is best.

Thanks Steve - that code works great!

@Colin, @Andrei FYI the output is being sent to my hubitat hub as a list of open contact sensors for display on a tablet dashboard. As display space is at a premium I wanted to just show a list of open sensors rather than create a whole bunch of device tiles to show status (most of them will be closed at any one time anyway)