Other functions

Several additional JSONata functions are provided for use within the WebSocket nodes. JSONata expressions are first 'prepared' then 'executed', and the preparation first stage is used to bind the expression to extra Node-RED or other functions. This means that these WebSocket functions can only be used within a WebSocket node.

screenshot

This example demonstrates the basic use of some of these functions.

[{"id":"c3f7b442994c1a29","type":"group","z":"776c027950fc8c3f","name":"Using WebSocket functions to return entity, device, and area details","style":{"label":true,"color":"#000000"},"nodes":["578b1fe6b17d9053","9e2cc6208465cb53","24a0721c11a9dabf","0e27f1810d1f2726","25aa9320ec1b341f","87097a630683a0f3","2b079469d339ee68","6d7320ce7cf2d71b","4cf613030bdac458","4bba7af21fb76af8","80af7504e9450dd4"],"x":34,"y":2699,"w":732,"h":322},{"id":"578b1fe6b17d9053","type":"inject","z":"776c027950fc8c3f","g":"c3f7b442994c1a29","name":"Manual trigger","props":[],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":150,"y":2820,"wires":[["9e2cc6208465cb53"]]},{"id":"9e2cc6208465cb53","type":"ha-get-entities","z":"776c027950fc8c3f","g":"c3f7b442994c1a29","name":"Entities with an attribute called \"array\"","server":"","version":1,"rules":[{"property":"","logic":"jsonata","value":"$entity().attributes.array!=[]","valueType":"jsonata"}],"outputType":"array","outputEmptyResults":true,"outputLocationType":"msg","outputLocation":"payload","outputResultsCount":1,"x":410,"y":2820,"wires":[["6d7320ce7cf2d71b"]]},{"id":"24a0721c11a9dabf","type":"api-current-state","z":"776c027950fc8c3f","g":"c3f7b442994c1a29","name":"Entity attributes called \"array\"","server":"","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"sensor.date_time","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"$entities().*.attributes[$exists(array)]","valueType":"jsonata"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":380,"y":2900,"wires":[["4cf613030bdac458"]]},{"id":"0e27f1810d1f2726","type":"api-current-state","z":"776c027950fc8c3f","g":"c3f7b442994c1a29","name":"Get Areas with Device and Entity Counts","server":"","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"sensor.time","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"$areas()^(name).{name: \" Devices: \" & $count($areaDevices(area_id)) & \" Entities: \" & $count($areaEntities(area_id))}~>$merge()","valueType":"jsonata"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":420,"y":2980,"wires":[["87097a630683a0f3"]]},{"id":"25aa9320ec1b341f","type":"inject","z":"776c027950fc8c3f","g":"c3f7b442994c1a29","name":"Manual trigger","props":[],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":150,"y":2980,"wires":[["0e27f1810d1f2726"]]},{"id":"87097a630683a0f3","type":"debug","z":"776c027950fc8c3f","g":"c3f7b442994c1a29","name":"Output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":670,"y":2980,"wires":[]},{"id":"2b079469d339ee68","type":"inject","z":"776c027950fc8c3f","g":"c3f7b442994c1a29","name":"Manual trigger","props":[],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":150,"y":2900,"wires":[["24a0721c11a9dabf"]]},{"id":"6d7320ce7cf2d71b","type":"debug","z":"776c027950fc8c3f","g":"c3f7b442994c1a29","name":"Output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":670,"y":2820,"wires":[]},{"id":"4cf613030bdac458","type":"debug","z":"776c027950fc8c3f","g":"c3f7b442994c1a29","name":"Output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":670,"y":2900,"wires":[]},{"id":"4bba7af21fb76af8","type":"server-state-changed","z":"776c027950fc8c3f","g":"c3f7b442994c1a29","name":"Using $entity() and $prevEntity()","server":"","version":5,"outputs":1,"exposeAsEntityConfig":"","entityId":"sensor.time","entityIdType":"exact","outputInitially":false,"stateType":"str","ifState":"","ifStateType":"str","ifStateOperator":"is","outputOnlyOnStateChange":true,"for":"0","forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"{\"old\": $prevEntity(), \"new\": $entity()}","valueType":"jsonata"}],"x":390,"y":2740,"wires":[["80af7504e9450dd4"]]},{"id":"80af7504e9450dd4","type":"debug","z":"776c027950fc8c3f","g":"c3f7b442994c1a29","name":"Output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":670,"y":2740,"wires":[]}]

Reading entity state and entity attributes with $entity() and $prevEntity()

In nodes with output properties, a number of properties are typically set by default, or can be optionally set as:

  • msg.payload = 'entity state'
  • msg.data = 'entity'
  • msg.event = 'event data'
  • msg.topic = 'entity id'

This provides useful message values in the flow following the node, however these values can be obtained within the node itself using the appropriate functions.

The function $entity() returns an object containing the entity details, relating to the entity that is the subject of the node. This means that the output property selection options are equivalent to JSONata expressions:

  • 'entity' ~ $entity()
  • 'entity state' ~ $entity().state
  • 'entity id' ~ $entity().entity_id

For the Events: nodes (Events: all and Events: state) the node triggers from an entity-change event, with $entity() returning the current (new) entity details, and the function $prevEntity() returning the previous (old) entity details.

{"old": $prevEntity(), "new": $entity()}

The first example uses an Events: state node, with a basic sensor.time entity to facilitate triggering the node every minute. The Time & Date Integrationopen in new window should be added to the configuration file, and then the given time sensor will return the current local time. The entity state (as time) is "hh:mm" and therefore changes every 60 seconds.

The output msg.payload is set to a new JSONata expression, which creates a new object with the old and new entity details, just as the output property 'event data' would do, but permitting a more detailed JSONata expression to be executed if required.

Using $entities() to return one or all entities

The next two examples explore ways to obtain specific entities, and this code looks for all Home Assistant entities that have an attribute field called 'array'.

$entity().attributes.array!=[]

In the first flow, a Get Entities node is used, with a JSONata expression used to filter the result, based on each entity having an attribute field called 'array' that is a non-empty JSON array. This will return the entire entity, and therefore the output will be an array of entities that have an 'attribute.array' field.

$entities().*.attributes[$exists(array)]

In the second flow, a Current State node is used, with a valid subject entity. The return from the given entity itself is not required - the node is just being used as a vehicle in which to execute the $entities() function. When specifying a named entity such as $entities('sun.next_dawn') only that entity will be returned, otherwise an array of all entities in Home Assistant will be returned. This JSONata expression then matches all entities in the array, filtering out attributes fields where the object key 'array' exists.

In contrast to the preceding flow, this will return just an array of the entity attributes. The JSONata code in this case can also be executed as and when required.

Note: Where a number of entity state values or attributes are required at one point in a flow for collective processing, using JSONata in a Current State node can be highly effective. The alternatives are:

  • Several Current State nodes chained in sequence, with each writing the state or entity data to a different msg.field.
  • One Current State node executing a JSONata expression, collating various $entity() or $entities('sensor.name') functions to either place values into one object, or to perform the necessary computation at that point. Output from JSONata can be either a simple primitive, or an object with several fields.

Using $areas(), $areaDevices and $areaEntities()

Finally, a more complex JSONata expression that returns details about areas, devices, and entities.

$areas()^(name).{
    name: " Devices: " & $count($areaDevices(area_id)) & " Entities: " & $count($areaEntities(area_id))
    } ~> $merge()

The JSONata above is just one long expression line (unnecessary new lines have been added just to make the expression easier to read). Evaluated left to right, it starts with the $areas() function:

  • Without a given area lookup value, this function returns an array of all areas in Home Assistant
    • which is then sorted alphabetically, by name
  • The result is an array, which is mapped (iterated over)
  • applying an {} object constructor for each array item
    • the object creates one key: value pair
    • the key is the area 'name' (this is a string)
    • the value is a constructed text string
  • The function $areaDevices(area_id) returns all devices in each area
    • using 'area_id' for the item area, and returning an array of devices
    • using $count() to count the number of devices in the returned array
  • The function $areaEntities(area_id) returns all entities in that area
    • returning an array, which is similarly counted
  • The resulting array of objects is then merged into one single object

Also see: