I will have to mess with this when I get home I was hoping I could do this remotely.
Aww so will need 12 different flows for each plug in this case !
Any chance that will change in the future to avoid this ?
This isnât going to be possible the way it stands now because the node is a two-part system.
- On deploy registers the sensor with HA
- On input updates the sensor in HA
Not sure your understanding of javascript so I wouldnât do much explaining of the code below. Ask any questions that you have about it.
Doing it this way you wonât be able to remove the sensors in HA from NR, youâd have to do it from the entity registry.
[{"id":"d5c4ef79.0c564","type":"ha-api","z":"9ce184b.0f5bb78","name":"Register Sensor","protocol":"websocket","method":"get","path":"","data":"{\t \"type\":\"nodered/discovery\",\t \"component\": \"sensor\",\t \"server_id\": serverId,\t \"node_id\": nodeId,\t \"config\": {\t \"name\": name,\t \"unit_of_measurement\": uom\t }\t}","dataType":"jsonata","location":"payload","locationType":"msg","responseType":"json","x":768,"y":1216,"wires":[["58a160e0.16fe8"]]},{"id":"a6e1d000.16b7a","type":"function","z":"9ce184b.0f5bb78","name":"Device Ids go here","func":"// List of all device ids, name of switch\nconst deviceIds = [\n [\"10470280dc4f22ed6311\", \"switch1\"],\n [\"2\", \"switch2\"],\n // [\"10470280dc4f22ed6311\", \"switch3\"],\n];\n\ndeviceIds.forEach(d => {\n [\"power\", \"current\", \"voltage\"].forEach(type => {\n let unit; \n switch(type) {\n case \"power\":\n unit = \"W\"\n break;\n case \"current\": \n unit = \"mA\"\n break;\n case \"voltage\": \n unit = \"V\"\n break;\n }\n\n node.send({\n serverId: d[0],\n nodeId: type,\n name: `${d[1]} ${type}`,\n uom: unit\n })\n })\n});\n","outputs":1,"noerr":0,"x":570,"y":1216,"wires":[["d5c4ef79.0c564"]]},{"id":"d872791e.7e3db8","type":"server-events","z":"9ce184b.0f5bb78","name":"","event_type":"home_assistant_client","exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"x":184,"y":1216,"wires":[["cab5b48c.7d4408"]]},{"id":"865bb27b.23aaf","type":"inject","z":"9ce184b.0f5bb78","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":140,"y":1312,"wires":[["58a160e0.16fe8"]]},{"id":"d7ba1479.a00048","type":"function","z":"9ce184b.0f5bb78","name":"fake tuya switch1","func":"msg.data = {\n name: \"switch_1\",\n ip: \"192.168.0.112\",\n id: \"10470280dc4f22ed6311\",\n available: true\n};\nmsg.payload = {\n devId: \"10470280dc4f22ed6311\",\n dps: {\n 1: true,\n 9: 0,\n 18: 5,\n 19: 6,\n 20: 2346,\n 21: 1,\n 22: 591,\n 23: 28555,\n 24: 16349,\n 25: 1275\n }\n};\nreturn msg;","outputs":1,"noerr":0,"x":506,"y":1312,"wires":[["66028769.695528"]]},{"id":"e7005805.eb98e8","type":"function","z":"9ce184b.0f5bb78","name":"fake tuya switch2","func":"msg.data = {\n name: \"switch_2\",\n ip: \"192.168.0.112\",\n id: \"2\",\n available: true\n};\nmsg.payload = {\n devId: \"2\",\n dps: {\n 1: true,\n 9: 0,\n 18: 1,\n 19: 2,\n 20: 2346,\n 21: 1,\n 22: 591,\n 23: 28555,\n 24: 16349,\n 25: 1275\n }\n};\nreturn msg;","outputs":1,"noerr":0,"x":508,"y":1360,"wires":[["66028769.695528"]]},{"id":"66028769.695528","type":"function","z":"9ce184b.0f5bb78","name":"parse data","func":"const types = {\n \"power\": \"18\",\n \"current\": \"19\",\n \"voltage\": \"20\"\n}\nfor (const [type, id] of Object.entries(types)) {\n node.send({\n serverId: msg.payload.devId,\n nodeId: type,\n payload: msg.payload.dps[id] || 0,\n });\n}","outputs":1,"noerr":0,"x":696,"y":1312,"wires":[["9ddb7a33.f8dad8"]]},{"id":"9ddb7a33.f8dad8","type":"ha-api","z":"9ce184b.0f5bb78","name":"Update Sensor","protocol":"websocket","method":"get","path":"","data":"{\t \"type\":\"nodered/entity\",\t \"server_id\": serverId,\t \"node_id\": nodeId,\t \"state\": payload \t}","dataType":"jsonata","location":"payload","locationType":"msg","responseType":"json","x":880,"y":1312,"wires":[[]]},{"id":"3066ba37.c8ef16","type":"comment","z":"9ce184b.0f5bb78","name":"Register Sensors","info":"","x":144,"y":1168,"wires":[]},{"id":"9df1457d.2665c8","type":"comment","z":"9ce184b.0f5bb78","name":"Update Sensors","info":"","x":144,"y":1264,"wires":[]},{"id":"cab5b48c.7d4408","type":"switch","z":"9ce184b.0f5bb78","name":"connected","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"connected","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":390,"y":1216,"wires":[["a6e1d000.16b7a"]]},{"id":"58a160e0.16fe8","type":"switch","z":"9ce184b.0f5bb78","name":"hub","property":"true","propertyType":"jsonata","rules":[{"t":"true"}],"checkall":"true","repair":false,"outputs":1,"x":322,"y":1312,"wires":[["d7ba1479.a00048","e7005805.eb98e8"]]},{"id":"fe75725c.0db45","type":"comment","z":"9ce184b.0f5bb78","name":"Update Sensors after registering them","info":"","x":534,"y":1264,"wires":[]}]
You will only have 12 nodes for each sensor. But you should be able to have one horizontal line flow if you route them and template properly. You can also consolidate all sensor nodes in one subflow of space is what bothers you. Otherwise have template sensors based on input text, and one call service node
I would like to dynamically create sensors for the brightness of each of my lights so I can then better monitor changes in brightness with NR (I donât think there is currently a way in NR to monitor attribute changes with the same flexibility as state changes i.e. you canât have an attribute change trigger a flow only if it has changed for x amount of time). So my solution is to dynamically create a sensor for the brightness of each of my lights so that anytime I add another light to my home, NR will create a sensor for it automatically (via the method in the post Iâm replying to) and then NR will also monitor that sensorâs state (which would be the brightness of the light). My question: is this a practical approach? Will the sensors that are dynamically created through this method be updated constantly like a template sensor would?
isnât attribute a state âmemberâ?
Iâm asking myself from time to time.
Anyway try to react on state change then compare attribute value with one stored in flow variable.
At this moment Iâm not sure NR can create sensors with names generated dynamically in runtime. I guess it cannot.
I donât think the state node will trigger if an entityâs attribute changes. I want it to trigger only when a lightâs brightness or color temperature changes but only once itâs changed for a few seconds. The reason for this is that I can use a trigger-state node to trigger a flow when an attribute changes but it triggers a ridiculous amount of messages for any change to my Hue lights (it also triggers for several entity attribute changes that I donât care to be listening to). So if I change the brightness and color of a light it triggers my flow several times on the way to its destination brightness/color. The problem is much worse when I change the brightness/color of more than 1 light, which I do way more often
Either option is doable.
I personally would go with the approach of monitoring the attributes and then continuing if x time has elapsed.
I can mock either way up if you want an example.
That would be great if you could do that. Just to be clear though, creating sensors dynamically through node red would not be the same as creating a template sensor in the config file, right? As in the sensor wouldnât automatically update any time the entity whose attribute the sensor is referencing is updated?
You can make the sensor created in NR update just like a template sensor would. You would just need to listen for the change and update the sensor.
Not really tested all that much but example 1 shows creating real entities in HA and the second shows creating temp ones that will disappear after a HA reset and will only appear again after their state changes.
[{"id":"d5c4ef79.0c564","type":"ha-api","z":"b28195ad.c495e8","name":"Register Sensor","debugenabled":false,"protocol":"websocket","method":"get","path":"","data":"","dataType":"json","location":"here","locationType":"msg","responseType":"json","x":912,"y":112,"wires":[["6cba3632.d10ad8"]]},{"id":"d872791e.7e3db8","type":"server-events","z":"b28195ad.c495e8","name":"","event_type":"home_assistant_client","exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"waitForRunning":true,"x":168,"y":112,"wires":[["cab5b48c.7d4408"]]},{"id":"9ddb7a33.f8dad8","type":"ha-api","z":"b28195ad.c495e8","name":"Update Sensor","debugenabled":true,"protocol":"websocket","method":"get","path":"","data":"","dataType":"json","location":"payload","locationType":"msg","responseType":"json","x":912,"y":208,"wires":[[]]},{"id":"3066ba37.c8ef16","type":"comment","z":"b28195ad.c495e8","name":"Register Sensors","info":"","x":128,"y":64,"wires":[]},{"id":"9df1457d.2665c8","type":"comment","z":"b28195ad.c495e8","name":"Update Sensors","info":"","x":128,"y":160,"wires":[]},{"id":"cab5b48c.7d4408","type":"switch","z":"b28195ad.c495e8","name":"running?","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"running","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":364,"y":112,"wires":[["28c3215c.c54dce"]]},{"id":"fe75725c.0db45","type":"comment","z":"b28195ad.c495e8","name":"Update Sensors after registering them","info":"","x":518,"y":160,"wires":[]},{"id":"a158770b.9ec218","type":"ha-get-entities","z":"b28195ad.c495e8","name":"get all lights","rules":[{"property":"entity_id","logic":"starts_with","value":"light.","valueType":"str"}],"output_type":"split","output_empty_results":false,"output_location_type":"msg","output_location":"payload","output_results_count":1,"x":582,"y":112,"wires":[["cb2f3f76.c36ce"]]},{"id":"cb2f3f76.c36ce","type":"function","z":"b28195ad.c495e8","name":"","func":"const id = msg.payload.entity_id.split(\".\")[1];\nconst node_id = `${id}_brightness`;\nconst name = msg.payload.attributes.friendly_name ? `${msg.payload.attributes.friendly_name} Brightness` : `${id.replace(\"_\", \" \")} brightness`;\n\nmsg.data = msg.payload;\nmsg.payload = {\n data: {\n type:\"nodered/discovery\",\n component: \"sensor\",\n server_id: \"home\",\n node_id,\n config: {\n name\n }\n }\n};\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":748,"y":112,"wires":[["d5c4ef79.0c564"]]},{"id":"28c3215c.c54dce","type":"change","z":"b28195ad.c495e8","name":"","rules":[{"t":"delete","p":"createdEntities","pt":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":463,"y":112,"wires":[["a158770b.9ec218"]],"l":false},{"id":"6cba3632.d10ad8","type":"function","z":"b28195ad.c495e8","name":"","func":"const id = msg.data.entity_id.split(\".\")[1];\nconst node_id = `${id}_brightness`;\nconst name = msg.data.attributes.friendly_name ? `${msg.data.attributes.friendly_name} Brightness` : `${id.replace(\"_\", \" \")} brightness`;\nconst brightness = msg.data.state !== \"on\" ? 0 : (msg.data.attributes.brightness || 0);\n\nmsg.payload = {\n data: {\n type:\"nodered/entity\",\n server_id: \"home\",\t \n node_id,\n state: brightness\n }\n};\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":748,"y":208,"wires":[["9ddb7a33.f8dad8"]]},{"id":"1c0038cc.619de7","type":"server-state-changed","z":"b28195ad.c495e8","name":"","version":1,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"^light\\.(?!.*\\_brightness$).*","entityidfiltertype":"regex","outputinitially":false,"state_type":"str","haltifstate":"","halt_if_type":"str","halt_if_compare":"is","outputs":1,"output_only_on_state_change":false,"for":0,"forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"x":208,"y":208,"wires":[["8c2a719c.02828"]]},{"id":"8c2a719c.02828","type":"change","z":"b28195ad.c495e8","name":"","rules":[{"t":"set","p":"data","pt":"msg","to":"msg.data.new_state","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":463,"y":208,"wires":[["6cba3632.d10ad8"]],"l":false}]
[{"id":"a0279b06.8882a8","type":"function","z":"b28195ad.c495e8","name":"","func":"const e = msg.data.new_state;\nconst state = e.state !== \"on\" ? 0 : (e.attributes.brightness || 0);\n\nmsg.payload = {\n path: `states/${e.entity_id.replace(\"light.\", \"sensor.\")}_brightness`,\n data: {\n state\n }\n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":460,"y":416,"wires":[["49dc0d09.cd7074"]]},{"id":"47f2fcc.51cc604","type":"server-state-changed","z":"b28195ad.c495e8","name":"","version":1,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"^light\\.(?!.*\\_brightness$).*","entityidfiltertype":"regex","outputinitially":false,"state_type":"str","haltifstate":"","halt_if_type":"str","halt_if_compare":"is","outputs":1,"output_only_on_state_change":false,"for":0,"forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"x":208,"y":416,"wires":[["a0279b06.8882a8"]]},{"id":"49dc0d09.cd7074","type":"ha-api","z":"b28195ad.c495e8","name":"create temp sensor","debugenabled":true,"protocol":"http","method":"post","path":"","data":"","dataType":"json","location":"payload","locationType":"msg","responseType":"json","x":666,"y":416,"wires":[[]]}]
Thank you again for the great examples!!
I saw that in the first flow, you are using websocket and HTTP on the second. Any reason why? I thought websocket is preferableâŚ
the second one is using POST /api/states/<entity_id>
https://developers.home-assistant.io/docs/api/rest/ because it doesnât require you to create an HA entity first. Itâs just a quick and dirty way to make temporary entities.
Updates or creates a state. You can create any state that you want, it does not have to be backed by an entity in Home Assistant.
Thanks. I am always using the quick and dirty way.
I couldnât find the documentation to create entities the âniceâ way using websocket. That part (AFAIK) is not documented on the websocket api pageâŚ
Is there a doc to explain why:
msg.payload = {
data: {
type:"nodered/discovery",
component: "sensor",
server_id: "home",
node_id,
config: {
name
}
}
};
Should be like that?
I have tried to mimic @kermit example and it doesnât work.
[{"id":"5614f8b6.1a8d08","type":"debug","z":"c07c0ac5.ca6f98","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":990,"y":2640,"wires":[]},{"id":"49c6d3eb.60806c","type":"inject","z":"c07c0ac5.ca6f98","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":500,"y":2640,"wires":[["f81c7076.aca23"]]},{"id":"a08a12f1.8668a","type":"ha-api","z":"c07c0ac5.ca6f98","name":"","debugenabled":false,"protocol":"websocket","method":"get","path":"","data":"","dataType":"json","location":"payload","locationType":"msg","responseType":"json","x":820,"y":2640,"wires":[["5614f8b6.1a8d08"]]},{"id":"f81c7076.aca23","type":"function","z":"c07c0ac5.ca6f98","name":"","func":"const node_id = 'conso_gaz';\nconst name = 'conso'\nmsg.data = msg.payload;\nmsg.payload = {\n data: {\n type:\"nodered/discovery\",\n component: \"sensor\",\n server_id: \"home\",\n node_id,\n config: {\n name\n }\n }\n};\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":660,"y":2640,"wires":[["a08a12f1.8668a"]]},{"id":"6b0a6ba0.949944","type":"ha-api","z":"c07c0ac5.ca6f98","name":"Update Sensor","debugenabled":true,"protocol":"websocket","method":"get","path":"","data":"","dataType":"json","location":"payload","locationType":"msg","responseType":"json","x":960,"y":2700,"wires":[["5614f8b6.1a8d08"]]},{"id":"664bf095.348d1","type":"function","z":"c07c0ac5.ca6f98","name":"","func":"const node_id = 'conso_gaz';\nconst name = 'conso;'\n\nmsg.payload = {\n data: {\n type:\"nodered/entity\",\n server_id: \"home\",\t \n node_id,\n state: 234\n }\n};\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":796,"y":2700,"wires":[["6b0a6ba0.949944"]]},{"id":"d26c8c4d.65c8e","type":"inject","z":"c07c0ac5.ca6f98","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":620,"y":2700,"wires":[["664bf095.348d1"]]}]
The api node replies âsuccessâ⌠but, I canât see the supposedly created sensor in HA.
There are no endpoints in HA core that allow you to create entities via a WebSocket. Thatâs why I created the NR custom integration the creates several endpoints that allows this. There is really no documentation as it was only meant to be used with NR as such everything is driven via the UI.
The closest thing youâll find to documentation other than just looking through the code is this thread.
Your export works for me.
Thanks for your answer.
- After having restarted HA, I can now see the entity being created in HA. All good (almost)!
- I have just upgraded to 0.28.0. The flow that was giving me success yesterday, is now complaining with:
"TypeError: Cannot read property 'value' of undefined"
coming out of the API callâŚ
Was there a change between 0.27.9 and 0.28.0 in this respect?
what node is throwing that error?
The âAPIâ Node. Using the same flow copied 2 posts above.
Only difference being the upgrade to 0.28.0.
definitely broke it. accidentally committed a file