Node Red: get user name from user_id

I have an NFC tag setup in HA that is firing a NodeRed automation. That part works fine and the payload looks like this:

{"tag_name":"My Tag","user_id":"58b0e1d64d4642e0a1344f08e7fc50f2","tag_id":"8a563d63-0cb2-40d4-9f76-f175b26349c4","name":"My Tag","device_id":"cda48fcb0ad9e05ace8ec41d3d22136f"}

My goal is to send some TTS to a media player that says the name of the person that scanned the NFC tag. I have all of the parts in place save the friendly name of the user that scanned the tag. The payload consists of the “user_id” property so I need some manner to translate that to a person object to get the actual name.

I have played extensively with the “Get Entities” node but cannot seem to get that to work. I have looked at the “API” node but that seems like it is not in the right direction.

Any help would be greatly appreciated!

You can use a change node to change the user ID to a name

[{"id":"e662c75397e6e3bb","type":"inject","z":"40e1f8faee5dae4f","name":"bob","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"tag_name\":\"My Tag\",\"user_id\":\"58b0e1d64d4642e0a1344f08e7fc50f2\",\"tag_id\":\"8a563d63-0cb2-40d4-9f76-f175b26349c4\",\"name\":\"My Tag\",\"device_id\":\"cda48fcb0ad9e05ace8ec41d3d22136f\"}","payloadType":"json","x":350,"y":2740,"wires":[["0d52504c57b03b2b"]]},{"id":"0d52504c57b03b2b","type":"change","z":"40e1f8faee5dae4f","name":"","rules":[{"t":"change","p":"payload.user_id","pt":"msg","from":"58b0e1d64d4642e0a1344f08e7fc50f2","fromt":"str","to":"bob","tot":"str"},{"t":"change","p":"payload.user_id","pt":"msg","from":"58b0e1d64d4642e0a1344f08e7fc50f1","fromt":"str","to":"tom","tot":"str"},{"t":"move","p":"payload.user_id","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":640,"y":2740,"wires":[["b8e58d1b4092233e"]]},{"id":"b8e58d1b4092233e","type":"debug","z":"40e1f8faee5dae4f","name":"debug 20","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":840,"y":2740,"wires":[]},{"id":"e7a2186a8c43c1b8","type":"inject","z":"40e1f8faee5dae4f","name":"tom","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"tag_name\":\"My Tag\",\"user_id\":\"58b0e1d64d4642e0a1344f08e7fc50f1\",\"tag_id\":\"8a563d63-0cb2-40d4-9f76-f175b26349c4\",\"name\":\"My Tag\",\"device_id\":\"cda48fcb0ad9e05ace8ec41d3d22136f\"}","payloadType":"json","x":350,"y":2820,"wires":[["0d52504c57b03b2b"]]}]

Whereas that will work today but I am trying not to hard-code values in my automations. If I were to add a user down the line then I would have to remember to go into every automation that had this lookup and add the new user.

Even if I put that in a subflow to make only one place I had to make the change then I would still have to have all flows that needed this functionality in the same main flow.

I like the creativeness of the response but it is not quite what I am looking for. Much obliged.

Node red does not store a list of user names, although I’m sure it could be built in a function node. It does keep a list of areas.

This would require you to create a new area for each phone with the name of the phone user. Look up your phone under devices, edit, and add a new area. Then you’ll get that name from payload.realname right from the tag scanned node.

[{"id":"10eb0ae030fd8e33","type":"debug","z":"40e1f8faee5dae4f","name":"debug 20","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":920,"y":2700,"wires":[]},{"id":"723d7de8ca183a38","type":"ha-tag","z":"40e1f8faee5dae4f","name":"","server":"6b1110b5.183a4","version":2,"exposeAsEntityConfig":"","tags":["__ALL_TAGS__"],"devices":[],"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"eventData"},{"property":"payload.resolved","propertyType":"msg","value":"$areas(payload.device_id)","valueType":"jsonata"},{"property":"payload.realname","propertyType":"msg","value":"payload.resolved.name","valueType":"jsonata"}],"x":750,"y":2700,"wires":[["10eb0ae030fd8e33"]]},{"id":"6b1110b5.183a4","type":"server","name":"Home Assistant","version":5,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":false,"heartbeat":false,"heartbeatInterval":"30","areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":"at: ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"h23","statusTimeFormat":"h:m","enableGlobalContextStore":true}]

On the assumption that you have entities called person.name, and these entities have attributes with the user_id that is used elsewhere (in your tag) and friendly_name, which is the name you want…

The following Node-RED flow will
get all entities with a non-null user_id (which seems to be just the person.name ones)
pull all of these into an object with user_id as key and friendly_name as value

lookup the given user (user_id) and return the name.

[{"id":"44d4e4b597b0d00b","type":"ha-get-entities","z":"776c027950fc8c3f","name":"All users","server":"","version":1,"rules":[{"property":"attributes.user_id","logic":"is_not","value":"null","valueType":"jsonata"}],"outputType":"array","outputEmptyResults":true,"outputLocationType":"msg","outputLocation":"payload","outputResultsCount":1,"x":720,"y":2700,"wires":[["b970dbbe238b04cb"]]},{"id":"09d668007617d6c4","type":"inject","z":"776c027950fc8c3f","name":"User ID to Friendly Name","props":[{"p":"user","v":"58b0e1d64d4642e0a1344f08e7fc50f2","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":530,"y":2700,"wires":[["44d4e4b597b0d00b"]]},{"id":"20521f7ed1b4aa3e","type":"debug","z":"776c027950fc8c3f","name":"debug 343","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1090,"y":2700,"wires":[]},{"id":"b970dbbe238b04cb","type":"change","z":"776c027950fc8c3f","name":"Lookup user from ID","rules":[{"t":"set","p":"payload","pt":"msg","to":"$merge(payload.{attributes.user_id: attributes.friendly_name})~>$lookup(user)","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":900,"y":2700,"wires":[["20521f7ed1b4aa3e"]]}]

It may do exactly what you want, but it was a lot of fun writing it!

I love the creativeness of this one! This will be a nice fallback. Thanks!

Oh yeah, this one hit the nail on the head! Very nice! It did exactly what I was looking for. Thank you so very much @Biscuit

And yeah, figuring these things out are a bit of fun. Sadly this one eluded me but am glad there are others that did not fail! :slight_smile:

So with the get entities query from @Biscuit That could be used to store the user list in node red. Then have it available to all nodes on the tab. You can replace flow with global to have it available to all node red.

When a user is added home assistant fires an event. When you add a person that can log in, this is done automatically. The first flow will listen for that event and then update the user list in nodered.

Then you can get friendly name from the tag node.

[{"id":"3c4404b7de3ce821","type":"ha-get-entities","z":"40e1f8faee5dae4f","name":"All users","server":"","version":1,"rules":[{"property":"attributes.user_id","logic":"is_not","value":"null","valueType":"jsonata"}],"outputType":"array","outputEmptyResults":true,"outputLocationType":"flow","outputLocation":"users","outputResultsCount":1,"x":1120,"y":3160,"wires":[[]]},{"id":"35d5822e67c6338c","type":"server-events","z":"40e1f8faee5dae4f","name":"","server":"","version":3,"exposeAsEntityConfig":"","eventType":"user_added","eventData":"","waitForRunning":true,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"eventData"}],"x":890,"y":3160,"wires":[["3c4404b7de3ce821"]]},{"id":"10eb0ae030fd8e33","type":"debug","z":"40e1f8faee5dae4f","name":"debug 20","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1100,"y":3240,"wires":[]},{"id":"c958861e8db4ead8","type":"ha-tag","z":"40e1f8faee5dae4f","name":"","server":"","version":2,"exposeAsEntityConfig":"","tags":["__ALL_TAGS__"],"devices":[],"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"eventData"},{"property":"resolved","propertyType":"msg","value":"$merge($flowContext('users').{attributes.user_id: attributes.friendly_name})~>$lookup(payload.user_id)","valueType":"jsonata"}],"x":850,"y":3240,"wires":[["10eb0ae030fd8e33"]]}]

Edit
You’ll need to hit the get entities node with a time stamp to create the list in the first place or add a new user.

With many thanks to @Biscuit , I ended up with the following:

[{"id":"138a2fa36646affe","type":"ha-get-entities","z":"26994888f54b165b","d":true,"name":"Get User","server":"52934302.29ab4c","version":1,"rules":[{"property":"attributes.user_id","logic":"is","value":"payload.user_id","valueType":"msg"}],"outputType":"array","outputEmptyResults":true,"outputLocationType":"msg","outputLocation":"payload","outputResultsCount":1,"x":200,"y":740,"wires":[["b52a0b9cb9934f15"]]},{"id":"b52a0b9cb9934f15","type":"api-call-service","z":"26994888f54b165b","d":true,"name":"Say it!!!","server":"52934302.29ab4c","version":5,"debugenabled":false,"domain":"tts","service":"speak","areaId":[],"deviceId":[],"entityId":["tts.piper"],"data":"{\t    \"message\": \"Welcome home {{payload.0.attributes.friendly_name}}\",\t    \"media_player_entity_id\": \"media_player.office_speaker\"\t}\t","dataType":"json","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":380,"y":740,"wires":[[]]},{"id":"52934302.29ab4c","type":"server","name":"Home Assistant","version":5,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":30,"areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":"at: ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"h23","statusTimeFormat":"h:m","enableGlobalContextStore":true}]

Since this call is assured that the entity will exist, there is no need to check for null then filter from the list. But to be clear, that is my use-case, may not be every ones.

With this, I am able to identify the user early on in the pipeline. In the end flow, I set the user to its own property on the message object that is used a couple different steps further down the line.

So many thanks to the members of this great community for helping out!

1 Like