Events: state

The Events: state node receives state change events for one or more entities, and will output a message in response. The message output can be optionally controlled by a test condition on the state value, and also by a test on the length of time the state remains at that value. Both the state test condition and the state time duration can use JSONata. This node can also provide output message properties, again with the ability to use JSONata.

screenshot

Here are three examples, showing how to use JSONata to perform If-State conditional tests, and to build output properties.

[{"id":"35b892e153bb5bc0","type":"group","z":"776c027950fc8c3f","name":"Events: state node - respond to state changes","style":{"label":true,"color":"#000000"},"nodes":["445466367c412014","e27b6ee2807af2eb","4583560d5089575d","24ed76ccd4da5975","266eadf86abd6481","27857c0c670e452b","e2ba71699db68b1a","1d9b8adce4f77e4e","a9b23a3911f5ef89"],"x":34,"y":919,"w":592,"h":342},{"id":"445466367c412014","type":"comment","z":"776c027950fc8c3f","g":"35b892e153bb5bc0","name":"3a - JSONata builds conditional test value","info":"","x":220,"y":960,"wires":[]},{"id":"e27b6ee2807af2eb","type":"server-state-changed","z":"776c027950fc8c3f","g":"35b892e153bb5bc0","name":"Switch was on for less than 3 minutes","server":"","version":5,"outputs":2,"exposeAsEntityConfig":"","entityId":"switch\\.[a-z][0-9]","entityIdType":"regex","outputInitially":false,"stateType":"str","ifState":"(\t    $new:=$entity();\t    $old:=$prevEntity();\t    $mins:=($toMillis($new.last_changed)-$toMillis($old.last_changed))/60000~>$round(0);\t    $new.state=\"off\" and $old.state=\"on\" and $mins<3\t)","ifStateType":"jsonata","ifStateOperator":"jsonata","outputOnlyOnStateChange":false,"for":"0","forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"\"Device \" & $entity().attributes.friendly_name & \" has been on for less than 3 minutes\"","valueType":"jsonata"},{"property":"topic","propertyType":"msg","value":"","valueType":"triggerId"}],"x":230,"y":1140,"wires":[["4583560d5089575d"],[]]},{"id":"4583560d5089575d","type":"debug","z":"776c027950fc8c3f","g":"35b892e153bb5bc0","name":"Flow trigger","active":true,"tosidebar":false,"console":false,"tostatus":true,"complete":"topic","targetType":"msg","statusVal":"payload","statusType":"auto","x":490,"y":1140,"wires":[]},{"id":"24ed76ccd4da5975","type":"server-state-changed","z":"776c027950fc8c3f","g":"35b892e153bb5bc0","name":"Motion between dawn and dusk","server":"","version":5,"outputs":2,"exposeAsEntityConfig":"","entityId":"motion","entityIdType":"substring","outputInitially":false,"stateType":"str","ifState":"(\t    $ismotion:= $entity().state=\"on\";\t\t    $dawn:=$entities('sensor.sun_next_dawn').state;\t    $dusk:=$entities('sensor.sun_next_dusk').state;\t    $date:=$entities('sensor.date_time_utc').state~>$substringBefore(\",\");\t\t    $isdawn:= $date=$substringBefore($dawn,\"T\");\t    $isdusk:= $date!=$substringBefore($dusk,\"T\");\t    \t    $ismotion and ($isdawn or $isdusk)\t)","ifStateType":"jsonata","ifStateOperator":"jsonata","outputOnlyOnStateChange":true,"for":"0","forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"(\t    $ismotion:= $entity().state=\"on\";\t\t    $dawn:=$entities('sensor.sun_next_dawn').state;\t    $dusk:=$entities('sensor.sun_next_dusk').state;\t    $date:=$entities('sensor.date_time_utc').state~>$substringBefore(\",\");\t\t    $isdawn:= $date=$substringBefore($dawn,\"T\");\t    $isdusk:= $date!=$substringBefore($dusk,\"T\");\t    \t    $fire:= $ismotion and ($isdawn or $isdusk);\t\t    {\"motion\": $ismotion,\t    \"dawn\": $dawn,\t    \"dusk\": $dusk,\t    \"date\": $date,\t    \"isdawn\": $isdawn,\t    \"isdusk\": $isdusk,\t    \"fire\": $fire\t    }\t)","valueType":"jsonata"},{"property":"data","propertyType":"msg","value":"","valueType":"eventData"},{"property":"topic","propertyType":"msg","value":"","valueType":"triggerId"}],"x":210,"y":1220,"wires":[["266eadf86abd6481"],[]]},{"id":"266eadf86abd6481","type":"debug","z":"776c027950fc8c3f","g":"35b892e153bb5bc0","name":"Dawn or Dusk","active":false,"tosidebar":false,"console":false,"tostatus":true,"complete":"true","targetType":"full","statusVal":"payload.isdawn ? \"Before Dawn\" : payload.isdusk ? \"After Dusk\"","statusType":"jsonata","x":500,"y":1220,"wires":[]},{"id":"27857c0c670e452b","type":"server-state-changed","z":"776c027950fc8c3f","g":"35b892e153bb5bc0","name":"","server":"","version":5,"outputs":2,"exposeAsEntityConfig":"","entityId":"motion","entityIdType":"substring","outputInitially":false,"stateType":"str","ifState":"(\t    $time:=$entities('sensor.time').state;\t    $append([\"on\"], $time<\"08:30\" or $time>\"17:30\" ? [\"off\"]);\t)    ","ifStateType":"jsonata","ifStateOperator":"includes","outputOnlyOnStateChange":true,"for":"0","forType":"num","forUnits":"seconds","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"eventData"},{"property":"topic","propertyType":"msg","value":"","valueType":"triggerId"}],"x":240,"y":1020,"wires":[["1d9b8adce4f77e4e"],["e2ba71699db68b1a"]]},{"id":"e2ba71699db68b1a","type":"debug","z":"776c027950fc8c3f","g":"35b892e153bb5bc0","name":"Condition false","active":false,"tosidebar":false,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":500,"y":1040,"wires":[]},{"id":"1d9b8adce4f77e4e","type":"debug","z":"776c027950fc8c3f","g":"35b892e153bb5bc0","name":"Condition true","active":false,"tosidebar":false,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload=\"on\" ? \"Motion at \" & $now('[H]:[m]') : \"end\"","statusType":"jsonata","x":500,"y":980,"wires":[]},{"id":"a9b23a3911f5ef89","type":"comment","z":"776c027950fc8c3f","g":"35b892e153bb5bc0","name":"3b - JSONata builds conditional Boolean","info":"","x":220,"y":1100,"wires":[]}]

Providing a conditional test value (JSONata expression as a value)

Example: Respond to motion events for both "on" (start of motion detection) all day, and also "off" (end of motion detection) but only outside of 08:30 to 17:30.

(
    $time:=$entities('sensor.time').state;
    $append(["on"], $time<"08:30" or $time>"17:30" ? ["off"]);
)

When the If State option is chosen with a conditional (not JSONata) the condition expects a value to test against. The result of the JSONata expression is the final line in the code block. This creates an array containing just ["on"] or if the time is before 08:30 or after 17:30, an array of ["on", "off"]. The motion sensor entity state will be compared with this array value using the inclusive condition 'in'.

screenshot

This JSONata uses the Date-Time integration sensor to obtain the local time. The Time & Date Integrationopen in new window should be added to the configuration file, and then the time sensor will return the current local time.

Conditional test (JSONata expression as a Boolean result)

Example: Switch has just been turned off, and was previously on for less than three minutes.

When the If State option is chosen with JSONata (not a conditional) then the right hand side must be a JSONata expression that returns a Boolean value of either true or false. When true the "If State" test is successful (the message is output from the top exit) when false the test fails (the message is output from the lower exit).

screenshot

(
    $new:=$entity();
    $old:=$prevEntity();
    $mins:=($toMillis($new.last_changed)-$toMillis($old.last_changed))/60000~>$round(0);
    $new.state="off" and $old.state="on" and $mins<3
)

In all the WebSocket nodes, the $entity() function will return an object for the entity that is the subject of the node. For the Event: nodes, the $entity() return is for the current or new state, and an additional $prevEntity() function will return a similar object for the previous state. Use of both functions allows JSONata expressions to work with and compare the triggering state change.

Example: Motion has been detected before dawn or after dusk.

Here JSONata is again used to generate a Boolean result for the If State test. The expression return is the final line in the code block, which tests for motion and either before dawn or after dusk. The use of 'or' here is an example of how JSONata can extend logic testing since the Trigger state node conditions can only group conditions as AND logic.

(
    $ismotion:= $entity().state="on";

    $dawn:=$entities('sensor.sun_next_dawn').state;
    $dusk:=$entities('sensor.sun_next_dusk').state;
    $date:=$entities('sensor.date_time_utc').state~>$substringBefore(",");

    $isdawn:= $date=$substringBefore($dawn,"T");
    $isdusk:= $date!=$substringBefore($dusk,"T");

    $ismotion and ($isdawn or $isdusk)
)

The Sun integration in Home Assistant provides 'nextdawn' and 'next_dusk' sensors, with a date-time string value in UTC. Since the _next dawn will be for today before dawn, but will be for tomorrow after dawn, and similarly the next dusk will be for today before dusk, but for tomorrow after dusk, it is possible to compare just the date parts of the UTC timestamps, so as to determine if the current time is before or after either dawn or dusk.

Creating output properties

To extend this last example, JSONata is used to generate an output object. Note that there is no internal connection between the two JSONata expressions, so all the values have to be recalculated as required.

(
    $ismotion:= $entity().state="on";

    $dawn:=$entities('sensor.sun_next_dawn').state;
    $dusk:=$entities('sensor.sun_next_dusk').state;
    $date:=$entities('sensor.date_time_utc').state~>$substringBefore(",");

    $isdawn:= $date=$substringBefore($dawn,"T");
    $isdusk:= $date!=$substringBefore($dusk,"T");

    $fire:= $ismotion and ($isdawn or $isdusk);

    {"motion": $ismotion,
    "dawn": $dawn,
    "dusk": $dusk,
    "date": $date,
    "isdawn": $isdawn,
    "isdusk": $isdusk,
    "fire": $fire
    }
)

OR conditional for the Events: state node

The Trigger: state node is great if you have several conditions you want to check for but it doesn't allow use of OR conditions. Using a JSONata expression with an Event: state node will allow you to fill this gap.

Example: Motion sensor at the front door triggers, and have a text to speech notification be sent if at least one person is home.

$entity().state = "on" and (
   $entities("person.person1").state = "home" or $entities("person.person2").state = "home"
)

Also see: