How do I create an entity from node-red and read all updates?

Since I am new in Home Assistant I started to migrate my JS coding from ioBroker to HA / node-red.
So far so good … everything is working. Now I want to create entities from my API poll of my device.

My question would be: Can I assign all entity attributes to the message flow, so that the entities are created with all assigned attributes? If yes, where do I find a documentation about needed attributes and how does it work? Are examples available?

I don’t think you can create an entity from node red. HA is written in python.

If NR can send to MQTT you can probably leverage that though.

Proof of concept:

[{"id":"25ef1c9c74581477","type":"ha-api","z":"be03f9025a1f137a","name":"sensor","server":"541ade28.b4a62","version":1,"debugenabled":false,"protocol":"http","method":"post","path":"/api/states/{{entity_id}}","data":"","dataType":"json","responseType":"json","outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"results"}],"x":875,"y":750,"wires":[[]]},{"id":"06ac8e03a8a85876","type":"function","z":"be03f9025a1f137a","name":"make final payload","func":"msg.entity_id = `sensor.test_entity`;\n\nmsg.payload = {\n    data: {\n        state: Date.now(),\n        attributes: {\n            'name': 'test_entity',\n            'attribute1': 'attribute_1',\n            'attribute2': 'attribute_2',\n            'attribute3': 'attribute_3',\n            'attribute4': 'attribute_4',\n            friendly_name: 'Test Entity',\n            icon: 'mdi:pulse'\n        }\n    }\n};\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":705,"y":750,"wires":[["25ef1c9c74581477"]]},{"id":"39963ed0628d85b4","type":"inject","z":"be03f9025a1f137a","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":525,"y":750,"wires":[["06ac8e03a8a85876"]]},{"id":"541ade28.b4a62","type":"server","name":"Home Assistant","version":2,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"","connectionDelay":false,"cacheJson":false,"heartbeat":false,"heartbeatInterval":""}]

And a real application of the concept in form of a ping flow.

[{"id":"5e79dbe6f1ff6193","type":"ping","z":"742cc87db4d12986","protocol":"IPv4","mode":"triggered","name":"ping","host":"","timer":"20","inputs":1,"x":290,"y":105,"wires":[["60ee1802b4936e33"]]},{"id":"de8cb585e64cbdcd","type":"function","z":"742cc87db4d12986","name":"init payload","func":"msg.payload = [\n    {\n        \"host\":msg.ping_hosts[flow.get('host_count')].host,\n        \"name\":msg.ping_hosts[flow.get('host_count')].name,\n        \"timeout\":1000\n    }\n]\ndelete msg.ping_hosts\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":140,"y":105,"wires":[["5e79dbe6f1ff6193"]]},{"id":"8d89777709693798","type":"ha-api","z":"742cc87db4d12986","name":"sensor","server":"541ade28.b4a62","version":1,"debugenabled":false,"protocol":"http","method":"post","path":"/api/states/{{entity_id}}","data":"","dataType":"json","responseType":"json","outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"results"}],"x":635,"y":240,"wires":[["2b7fbc9f4d5a512c"]]},{"id":"60ee1802b4936e33","type":"function","z":"742cc87db4d12986","name":"rearrange payload","func":"ping = msg.payload\nmsg.payload = [\n    {\n        \"host\":msg.ping.host,\n        \"name\":msg.ping.name,\n        \"timeout\":msg.ping.timeout,\n        \"ping1\":ping\n    }\n]\ndelete msg.ping\ndelete msg.topic\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":465,"y":105,"wires":[["5556ec8bac29e714"]]},{"id":"5556ec8bac29e714","type":"ping","z":"742cc87db4d12986","protocol":"IPv4","mode":"triggered","name":"ping","host":"","timer":"20","inputs":1,"x":290,"y":150,"wires":[["4216857a7920c093"]]},{"id":"4216857a7920c093","type":"function","z":"742cc87db4d12986","name":"rearrange payload","func":"ping = msg.payload\nmsg.payload = [\n    {\n        \"host\":msg.ping.host,\n        \"name\":msg.ping.name,\n        \"timeout\":msg.ping.timeout,\n        \"ping1\":msg.ping.ping1,\n        \"ping2\":ping\n    }\n]\ndelete msg.ping\ndelete msg.topic\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":465,"y":150,"wires":[["5756468d017e28fc"]]},{"id":"3448a970a6c3c28b","type":"function","z":"742cc87db4d12986","name":"rearrange payload","func":"ping = msg.payload\nmsg.payload = [\n    {\n        \"host\":msg.ping.host,\n        \"name\":msg.ping.name,\n        \"timeout\":msg.ping.timeout,\n        \"ping1\":msg.ping.ping1,\n        \"ping2\":msg.ping.ping2,\n        \"ping3\":ping\n    }\n]\ndelete msg.ping\ndelete msg.topic\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":465,"y":195,"wires":[["9039ddb76aeaf573"]]},{"id":"5756468d017e28fc","type":"ping","z":"742cc87db4d12986","protocol":"IPv4","mode":"triggered","name":"ping","host":"","timer":"20","inputs":1,"x":290,"y":195,"wires":[["3448a970a6c3c28b"]]},{"id":"eab00987afff6bab","type":"function","z":"742cc87db4d12986","name":"make final payload","func":"ping = msg.payload\nmsg.entity_id = `sensor.ping_${msg.ping.name.toLowerCase().replace(/ /g, '_' )}`;\npacketloss=0;\naverage = 0;\nif (msg.ping.ping1==false)\n{\n    packetloss=1;\n}\nelse\n{\n    average=msg.ping.ping1;\n}\n\nif (msg.ping.ping2==false)\n{\n    packetloss++;\n}\nelse\n{\n    average=average+msg.ping.ping2;\n}\n\nif (msg.ping.ping3==false)\n{\n    packetloss++;\n}\nelse\n{\n    average=average+msg.ping.ping3;\n}\n\nif (ping==false)\n{\n    packetloss++;\n}\nelse\n{\n    average=average+ping;\n}\n\nif (packetloss!=4)\n{\n    average=average/(4-packetloss);\n}\npacketloss=packetloss*25\n\nmsg.payload = {\n    data: {\n        state: Date.now(),\n        attributes: {\n            'name':msg.ping.name,\n            'host':msg.ping.host,\n            'ping1': msg.ping.ping1,\n            'ping2': msg.ping.ping2,\n            'ping3': msg.ping.ping3,\n            'ping4': ping,\n            'average': Math.floor(average),\n            'packetloss': packetloss,\n            friendly_name: 'Ping '+msg.ping.name,\n            icon: 'mdi:pulse'\n        }\n    }\n};\ndelete msg.ping\ndelete msg.topic\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":465,"y":240,"wires":[["8d89777709693798"]]},{"id":"9039ddb76aeaf573","type":"ping","z":"742cc87db4d12986","protocol":"IPv4","mode":"triggered","name":"ping","host":"","timer":"20","inputs":1,"x":290,"y":240,"wires":[["eab00987afff6bab"]]},{"id":"06433f919f86b67b","type":"function","z":"742cc87db4d12986","name":"set ping list","func":"msg.ping_hosts = [\n        { \"name\":\"Router\",\"host\":\"10.10.12.1\"},\n        { \"name\":\"First Hop\", \"host\":\"100.70.8.1\"},\n        { \"name\":\"Public IP\",\"host\":\"185.107.15.19\"},\n        { \"name\":\"Google\", \"host\":\"8.8.8.8\"},\n        { \"name\":\"Switch 1\", \"host\":\"10.10.14.11\"},\n        { \"name\":\"Switch 2\", \"host\":\"10.10.14.12\"},\n        { \"name\":\"Switch 3\", \"host\":\"10.10.14.13\"},\n        { \"name\":\"Switch 4\", \"host\":\"10.10.14.14\"},\n        { \"name\":\"AP 1\", \"host\":\"10.10.14.21\"},\n        { \"name\":\"Hue Bridge\", \"host\":\"10.10.12.12\"},\n        { \"name\":\"RF Bridge 1\", \"host\":\"10.10.12.14\"},\n        { \"name\":\"RF Bridge 2\", \"host\":\"10.10.12.16\"},\n        { \"name\":\"NAS\", \"host\":\"10.10.12.20\"},\n        { \"name\":\"Radio Bedroom Left\", \"host\":\"10.10.12.50\"},\n        { \"name\":\"Radio Bedroom Right\", \"host\":\"10.10.12.52\"},\n        { \"name\":\"Smartplug Outdoor\", \"host\":\"10.10.12.150\"},\n        { \"name\":\"Smartplug Refrigerator\", \"host\":\"10.10.12.151\"},\n        { \"name\":\"Smartplug Freezer\", \"host\":\"10.10.12.152\"},\n        { \"name\":\"Smartplug Dishwasher\", \"host\":\"10.10.12.153\"},\n        { \"name\":\"Smartplug Washingmachine\", \"host\":\"10.10.12.154\"},\n        { \"name\":\"Sonoff Plug 1\", \"host\":\"10.10.12.155\"},\n        { \"name\":\"Sonoff Plug 2\", \"host\":\"10.10.12.156\"},\n        { \"name\":\"Sonoff Plug 3\", \"host\":\"10.10.12.157\"},\n        { \"name\":\"Sonoff Plug 4\", \"host\":\"10.10.12.158\"},\n        { \"name\":\"Sonoff Plug 5\", \"host\":\"10.10.12.159\"},\n        { \"name\":\"Sonoff Plug 6\", \"host\":\"10.10.12.160\"},\n        { \"name\":\"Sonoff Switch 1\", \"host\":\"10.10.12.161\"},\n        { \"name\":\"Kasa1\", \"host\":\"10.10.12.162\"},\n        { \"name\":\"Kasa2\", \"host\":\"10.10.12.163\"},\n        { \"name\":\"Kasa3\", \"host\":\"10.10.12.164\"},\n        { \"name\":\"Kasa4\", \"host\":\"10.10.12.165\"},\n        { \"name\":\"Kasa5\", \"host\":\"10.10.12.166\"},\n        { \"name\":\"Kasa6\", \"host\":\"10.10.12.167\"}\n    ]\nflow.set('ping_hosts_length',msg.ping_hosts.length)\nreturn msg;\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":775,"y":45,"wires":[["de8cb585e64cbdcd"]]},{"id":"cea4042da4a1a615","type":"inject","z":"742cc87db4d12986","name":"start ping cycle","props":[],"repeat":"120","crontab":"","once":true,"onceDelay":"30","topic":"","x":130,"y":45,"wires":[["c3848bb02d93a9da"]]},{"id":"1a060eab08e27cc9","type":"function","z":"742cc87db4d12986","name":"initiate counter","func":"flow.set('host_count',0)\nflow.set('running',1)\nreturn msg","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":575,"y":45,"wires":[["06433f919f86b67b"]]},{"id":"2b7fbc9f4d5a512c","type":"function","z":"742cc87db4d12986","name":"increase counter","func":"counter=flow.get('host_count')+1\nif (counter==flow.get('ping_hosts_length'))\n{\n    flow.set('running',0)\n}\nflow.set('host_count',counter)\nreturn msg","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":790,"y":240,"wires":[["04d9427be7f1da21","1ebf45b3f585cced"]]},{"id":"c3848bb02d93a9da","type":"switch","z":"742cc87db4d12986","name":"Check for active session","property":"running","propertyType":"flow","rules":[{"t":"neq","v":"1","vt":"num"}],"checkall":"true","repair":false,"outputs":1,"x":350,"y":45,"wires":[["1a060eab08e27cc9"]]},{"id":"04d9427be7f1da21","type":"switch","z":"742cc87db4d12986","name":"Check for active session","property":"running","propertyType":"flow","rules":[{"t":"neq","v":"0","vt":"num"}],"checkall":"true","repair":false,"outputs":1,"x":755,"y":150,"wires":[["06433f919f86b67b"]]},{"id":"e85fb753c38c3214","type":"function","z":"742cc87db4d12986","name":"reset flow ","func":"flow.set('host_count',0)\nflow.set('running',0)\nreturn msg","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":975,"y":285,"wires":[[]]},{"id":"8a20032e6aa7d835","type":"inject","z":"742cc87db4d12986","name":"Reset at startup","props":[{"p":"reset","v":"1","vt":"num"}],"repeat":"","crontab":"","once":true,"onceDelay":"60","topic":"","x":130,"y":285,"wires":[["e85fb753c38c3214"]]},{"id":"1ebf45b3f585cced","type":"merge","z":"742cc87db4d12986","name":"","timeout":"300","x":965,"y":240,"wires":[["e85fb753c38c3214"]]},{"id":"541ade28.b4a62","type":"server","name":"Home Assistant","version":2,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"","connectionDelay":false,"cacheJson":false,"heartbeat":false,"heartbeatInterval":""}]
1 Like

The Node-RED add-on for HA has hooks for the Home Assistant API. You can directly update entities in HA from a Node-RED flow.

I do not think tp1de wants to update existing entities, but instead create new ones.

You can also use the entity node to create an entity in HA from Node red.

[{"id":"deb8fd1153e98ceb","type":"debug","z":"ad594fb84fe6d294","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":650,"y":80,"wires":[]},{"id":"baaeb67025c3b042","type":"function","z":"ad594fb84fe6d294","name":"","func":"var array = {};\nvar time = \"\";\n\ntime = new Date(msg.payload.approvedTime);\nvar offset = time.getTimezoneOffset(); \ntime = new Date(time.getTime() - (offset*60*1000)); \nmsg.state = time.toISOString().replace(\"T\", \" \").substring(0,16)\n\nfor (var index in msg.payload.timeSeries.slice(0,36)) {\n    for (var val in msg.payload.timeSeries[index].parameters) {\n        time = new Date(msg.payload.timeSeries[index].validTime);\n        offset = time.getTimezoneOffset(); \n        time = new Date(time.getTime() - (offset*60*1000)); \n        \n        \n        if (msg.payload.timeSeries[index].parameters[val][\"name\"] == \"ws\"){\n            array[time.toISOString().replace(\"T\", \" \").substring(0,16)] = { \"wind\": msg.payload.timeSeries[index].parameters[val].values[0] };  \n        }else if (msg.payload.timeSeries[index].parameters[val][\"name\"] == \"gust\"){\n            array[time.toISOString().replace(\"T\", \" \").substring(0,16)].gust =  msg.payload.timeSeries[index].parameters[val].values[0];  \n        }\n    }\n}\n\nmsg.arr = array;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":480,"y":120,"wires":[["deb8fd1153e98ceb","aeb70bcf74c928d9"]]},{"id":"aeb70bcf74c928d9","type":"ha-entity","z":"ad594fb84fe6d294","name":"smhi hourly","server":"4bbca37b.1700ec","version":2,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"smhi hourly"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"state","stateType":"msg","attributes":[{"property":"hourly","value":"arr","valueType":"msg"}],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"$entity().state ? \"on\": \"off\"","outputPayloadType":"jsonata","x":670,"y":180,"wires":[[]]},{"id":"994a4699a32ef4ec","type":"inject","z":"ad594fb84fe6d294","name":"","props":[{"p":"payload"}],"repeat":"7200","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"str","x":150,"y":120,"wires":[["8584052db0255346"]]},{"id":"8584052db0255346","type":"http request","z":"ad594fb84fe6d294","name":"","method":"GET","ret":"obj","paytoqs":"ignore","url":"https://opendata-download-metfcst.smhi.se/api/category/pmp3g/version/2/geotype/point/lon/18.194609416231792/lat/62.97106354370433/data.json","tls":"","persist":false,"proxy":"","authType":"","senderr":false,"credentials":{},"x":310,"y":120,"wires":[["baaeb67025c3b042"]]},{"id":"4bbca37b.1700ec","type":"server","name":"Home Assistant","version":2,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":30}]

This is used to get the wind speed from a forecast and warn me if I need to tie the curtains on the balcony.

1 Like

Yes I want to create new ones where entity names and other entity attributes can be send by msg attributes. I tested different versions but I can’t pass the entity names just state info.

Since I want to create approx. 130 entities this approach does not work. Is HA so inflexible?

My first reply does that.
I create 33 sensors with attributes with just a script that sets up the data and a node for HA that does not change.

The Proof of Concept flow is just for one with static values, but it shows the possibilities.

This is what the sequence I posted gives me in Home Assistant:

So state and attributes are set by the message. Name is set in the node settings.

Yes it seems to work this way for sensors . Thanks a lot for your support.
How would it work for switches?

Your values of the attributes are set dynamically, but not the attributes themself, since that is a key/value pair.
You are having a static key in your node.

I have actually no idea.
Try to set the entity name to a switch and see. :slight_smile:

Does this mean I can’t create entities which can be changed in lovelace?

I was a reply to Hellis81.

I made a test with a switch and although HA accepts that it will not change state as a switch.
It is most likely possible, but you might need some more data in the function node.
I do just not know which data is needed.

Thanks so far. I will test and if I find a solution I will post it.

Looking forward to it :slight_smile:

There is nothing limiting it from being dynamic.

[{"id":"99837e99b397cd3d","type":"function","z":"ad594fb84fe6d294","name":"","func":"msg.payload = {\n    \"attributes\":{\n        \"aa\":{\n            \"test\":1,\n            \"test2\":2\n        }\n    }\n};\nmsg.state = \"test\"\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":480,"y":420,"wires":[["3b021b1c81d5e096"]]},{"id":"516f37f70806a164","type":"inject","z":"ad594fb84fe6d294","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":320,"y":420,"wires":[["99837e99b397cd3d"]]},{"id":"3b021b1c81d5e096","type":"ha-entity","z":"ad594fb84fe6d294","name":"test","server":"4bbca37b.1700ec","version":2,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"test"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"state","stateType":"msg","attributes":[],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"$entity().state ? \"on\": \"off\"","outputPayloadType":"jsonata","x":650,"y":380,"wires":[[]]},{"id":"4bbca37b.1700ec","type":"server","name":"Home Assistant","version":2,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":30}]

msg.payload = {
    "attributes":{
        "aa":{
            "test":1,
            "test2":2
        }
    }
};
msg.state = "test"
return msg;

The only parts that can’t be dynamic (sadly) is the “Home Assistant Config” part.

1 Like

hmm, I do not know why it looked different the first time I pasted it in, but I see what you are saying now.
Have you tried setting msg.entity_id or msg.name to see if that changes anything?

In my node I set msg.entity_id = switch.test_entity

If this is possible, then it solves the issue with making switches.

It was different, I just took a sequence I had.
Now I made it as dynamic as it can be.

No you can’t have the entity id as dynamic I have spent a lot of time trying.
And it’s not documented either.

1 Like