Safety Plug On_With_Timed_Off and Safe Off State fall back at start up

This blueprint implements an automation for safety monitoring a plug switch of safety aware manufacturers that are respecting the harmonized 3.0 Zigbee standard. Without any guarantee to function, this safety blueprint is intended to monitor high power consumers to reduce the risk of fire hazards by using standardized plug included functions to bring the plug back into a predefined safe state which is “Off”. This script is provided AS IS without any guarantee and in your responsibility to use it or not!

Status: Early Draft!

For this automation to maybe function, the following requirements are required to satisfy:

  • HACS (Home Assistant Community Store) installed in you HA, essential for testing
    the countdown timer in action. Otherwise you plug is expected to switch off shortly.
  • require a plug or switch, that has an internal power metering
  • provides an on_with_timed_off countdown that is stored in on_time attribute of the OnOff cluster.
  • provides start_up_on_off attribute in the OnOff cluster
  • complies with zigbee standard 3.0, respectively harmonizes with other manufacturers with respect to the on_with_timed_off or start_up_on_off functionality.

The following devices are simply desktop tested to show the intended functionality:

  • LEDVANCE SMART+ PLUG EU EM T
  • INNR Smart Plug SP 240

Disclaimer:
Please be informed that this script is to be used in your full responsibility and risk and neither I nor anyone else will take any responsibility that it will work at all, work with your plug or in your environment or even is fully implemented to satisfy any safety requirement that it will not! Please ask your manufacturer if they comply your plug to fulfill IEC62368 safety regulations which is part of their CE and FCC certification.

Testing:
import this blueprint and select one of the above or any other plug or switch you want to test for some of the above documented behavior. Let the default timeout value for testing as is (10s) and create an automation for your plug. trigger this automation by switching your plug on in your dashboard and count the seconds multiple times until it switches back to off. If it suddenly switches off before the 10s expired, your plug may not be complying to the zigbee standard or countdown funktionality is not supported. Use the ZHA device management to see if this automation properly sets the StartupOnOff attribute to “Off” in the ONOffCluster after you changed it to “On”

What it does or is at least intended to do (use at own risk!)

  1. Select a plug switch entity to be safety monitored and setup the safety timeout that is high enough to not expire in normal usage but expires short enough to avoid or reduce possible fire hazards. The default start up state is “Off” is assumed as off and can’t be changed.
  2. The created automation Is triggered every time when the plug is switched from “Off” to “On”
  3. Write the on_time attribute, as it is expected to overwrite the on_time argument of the on_with_timed_off argument
  4. Send the on_with_timed_off command to the plug including the on_time with off_wait_time beeing zero and beeing executed only when switching from off to on.
  5. Create a timeout to wait for an answer or switch the plug off if not arriving in time of 5s
  6. Wait and read back the on_time attribute to prove the countdown is running
  7. If the counter cannot be proved to be running or the on_time value cannot be read back the plug is immediately switched back to safe state
  8. Reprogram the StartUpOnOff attribut only if the read back value is not as expected “Off”

What to do next, or should be improved by your help or suggestions:

  • Create two values that represent the expected operation power consumption
  • Compare a measured power consumption is in the desired power range
  • If the power cannot be approve in range at latest at 4s after switch “On” switch the plug to safe “Off” stare
  • find out, how a safety timeout using on_with_timed_off can be used to disable a soft fuse and detect the failure, that the switch ran into timeout which should never happen.
  • Behave like a fuse such as any failure prevents the plug from ever switching on again or until a manual reset of the fuse happens that tells the monitor that the failure is repaired.

Open your Home Assistant instance and show the blueprint import dialog with a specific blueprint pre-filled.

blueprint:
  name: Safety Start-Off, Timed-Off for PWR-Plug [!IEEE aus Name!]
  description: >
    Bei jedem Einschalten wird zuerst das konfigurierte **SafetyâTimeout**
    in das ZHAâAttribut *on_time* geschrieben und anschlieÃBefehl **on_with_timed_off** (Clusterâ¯0x0006, Commandâ¯1) gesendet.
  domain: automation

  input:
    plug_entity:
      name: Plug / Schalter
      description: >
        Entity des ZHAâPlugs. Der FriendlyâName muss die IEEEâAdresse in eckigen
        Klammern enthalten, z.â¯B. "[8c:6f:b9:ff:fe:ae:49:f8]".
      selector:
        entity:
          domain: switch

    safety_timeout_s:
      name: SafetyâAbschaltzeit
      description: >
        Maximale on_timeâDauer, bevor das GerÀt automatisch abgeschaltet wird.
        Werte von **10â¯s** bis **4000â¯s** in 10âMinutenâSchritten.
      default: 10                     # <- Standardwert, verhindert â
      selector:
        number:
          min: 10
          max: 4000
          step: 600
          unit_of_measurement: s
          mode: slider

    desired_state:
      name: Desired State
      description: Select the desired state for the LEDVANCE plug, but use 'On' only for testing!
      default: 'Off'
      selector:
        select:
          options:
            - "Off"

trigger:
  - platform: state
    entity_id: !input plug_entity
    from: "off"
    to: "on"

mode: single

variables:
  plug_entity: !input plug_entity
  safety_timeout_s: !input safety_timeout_s
  desired_state: !input desired_state
  safety_timeout: "{{ safety_timeout_s | int * 10 }}"

  # ------------------------------------------------------------------
  # IEEE aus dem FriendlyâName extrahieren
  # ------------------------------------------------------------------
  ieee: >
    {% set name = states[plug_entity].attributes.friendly_name %}
    {% set m = name | regex_findall('\\[([0-9A-Fa-f:]{23})\\]') %}
    {{ m[-1] | lower if m else 'ERROR_NO_IEEE' }}

  ieee_slug: "{{ ieee | replace(':','_') }}"
  on_time_entity: "zha.{{ ieee_slug }}_on_time_value"

action:
  # ------------------------------------------------------------------
  # 1ïžâ£ Sicherstellen, dass eine gÃŒltige IEEEâAdresse gefunden wurde
  # ------------------------------------------------------------------
  - condition: template
    value_template: "{{ ieee != 'ERROR_NO_IEEE' }}"

  # ------------------------------------------------------------------
  # 2ïžâ£ WriteâOperation: safety_timeout in das on_timeâAttribut schreiben
  #    (Clusterâ¯0x0006, Attributâ¯0x4001)
  # ------------------------------------------------------------------
  - service: zha.set_zigbee_cluster_attribute
    data:
      ieee: "{{ ieee }}"
      endpoint_id: 1
      cluster_id: 0x0006
      attribute: 0x4001
      value: "{{ safety_timeout }}"
      cluster_type: in

  - delay: "00:00:01"

  # ------------------------------------------------------------------
  # 3ïžâ£ ZigbeeâBefehl on_with_timed_off (Clusterâ¯0x0006, Commandâ¯1)
  #    Payload: [on_time, off_wait_time]
  #    Wir setzen on_time = 0 (sofort an) und off_wait_time = safety_timeout
  # ------------------------------------------------------------------
  - service: zha.issue_zigbee_cluster_command
    data:
      ieee: "{{ ieee }}"
      endpoint_id: 1
      cluster_id: 6                      # OnOff Cluster
      command_type: 'server'
      cluster_type: 'in'
      command: 66                        # on with timed off
      params:                                                                                          
        on_off_control: 0                # Accept Only When On (false) - erstes Attribut
        on_time: "{{ safety_timeout }}"  # on_time in Sekunden
        off_wait_time: 0                 # off_wait_time in Sekunden

  # ------------------------------------------------------------------
  # 5ïžâ£ Aktuelles on_time auslesen
  # ------------------------------------------------------------------
  - delay: "00:00:01"
  - service: zha_toolkit.execute
    data:
      command: attr_read
      ieee: "{{ ieee }}"
      cluster: 6
      attribute: 16385
      state_id: "{{ on_time_entity }}"
      allow_create: true

  # ------------------------------------------------------------------
  # 6ïžâ£ on_time-Wert auslesen und mit safety_timeout vergleichen
  # ------------------------------------------------------------------
  - wait_template: "{{ states(on_time_entity) | int > 0 }}"
    timeout: "00:00:05"
    continue_on_timeout: true
    # ErklÀrung: Wartet, bis der on_time-Wert ausgelesen und verfÌgbar ist.
    # Wenn der Wert innerhalb von 5 Sekunden nicht verfÃŒgbar ist, wird die Automation fortgesetzt.

  - variables:
      current_on_time: "{{ states(on_time_entity) | int }}"

  - service: logbook.log
    data:
      name: "Timeout Check: current_on_time, safety_timeout"
      message: >
        current_on_time: {{ current_on_time }},
        safety_timeout: {{ safety_timeout }},
        diff: {{ safety_timeout - current_on_time }}

  # ------------------------------------------------------------------
  # 7ïžâ£ Entscheidung: Countdown aktiv oder nichticht
  # ------------------------------------------------------------------
  - choose:
      # Countdown ist praktisch abgelaufen -> plug_entity ausschalten
      - conditions:
          - condition: template
            value_template: "{{ (safety_timeout - current_on_time) < 5 }}"
        sequence:
          - service: switch.turn_off
            target:
              entity_id: "{{ plug_entity }}"
    # Countdown laeuft noch -> nichts tun aber automation laeuft weiter
    default: []

  # ------------------------------------------------------------------
  # 8 Default StartUpOnOff Attribut fuer Schalter -> Safe State "Off"
  # ------------------------------------------------------------------
  - service: zha_toolkit.execute
    data:
      command: attr_read
      ieee: "{{ ieee }}"
      cluster: 6
      attribute: 16387
      state_id: "sensor.startup_onoff_read"
      allow_create: true
    response_variable: read_result

  # ------------------------------------------------------------------
  # 9 Entscheidung: Enstpricht StartUpOnOff Attribut gew. Safe State?
  # ------------------------------------------------------------------
  - choose:
      - conditions:
          - condition: template
            value_template: >
              {{ read_result.result_read[0][16387].value != (1 if desired_state == 'On' else 0) }}
        sequence:
          - service: zha.set_zigbee_cluster_attribute
            data:
              ieee: "{{ ieee }}"
              endpoint_id: 1
              cluster_id: 6
              attribute: 16387
              value: "{{ 1 if desired_state == 'On' else 0 }}"
              cluster_type: in
          - service: logbook.log
            data:
              name: "StartupOnOff Update"
              message: "StartupOnOff was changed to {{ desired_state }}"
    default:
      - service: logbook.log
        data:
          name: "StartupOnOff Update"
          message: "StartupOnOff already {{ desired_state }}, no change needed"