Wann wurde HA / Raspi die letzten Male vom Strom getrennt und neu gestartet?

Trigger

Heute Nacht hatte ich Streß mit meiner Frau wegen Homeassi … sie mußte früh raus, Klima ging nicht an und Lichter im Flur nicht aus… selber schon schlafend, sah ich, daß Z2M einen Menge Offline Geräte anzeigte, ok HA durchstarten, keine Besserung, ok ab zum Stromstecker, HA vom Strom trennen, kurz warten und wieder einstecken…nach ein paar Minuten wurden in Z2M wieder alle Geräte erkannt. Licht ging aus und Klima an und meine Frau schlief wieder ein, puhh.

Das habe ich gefühlt alle 2 Monate und ich vermute, der Speicher des Sonoff Zigbee 3.0 Sticks läuft voll mit Meldungen und das Stromausschalten reseted den (Firmware 20240710). Ein Software Durchstart macht das nicht. Einzige Auffälligkeit gestern frühen Abend: Es standen unerledigte 11 Hue OTA Updates an

Im Nachhinein hätte sicher auch gereicht den Stick einmal rauszuziehen und so vom Strom zu trennen. Ist sicher auch gesunder für Raspi und SSD.

Egal, fürs den Moment. Ich muß das mal mehr beobachten.

Vorgehen

Dafür will ich erst einmal wissen, wie oft HA durch Stromtrennen neugestartet wurde. Sensor.system_monitor_last_boot nehme ich als Indikator weil dieser sich bei HA Software Neustarts nicht verändert, nur bei Strom aus/an. Er enthält selber schon die Datums, die ich brauche, natürlich limitiert durch die eingestellten purge days im Rekorder.

Über eine Automatisation schreibe ich die Werte bei jeder Änderung in ein Text-Helfer in einem Semikolon getrenntem Format

Zusammenfassung
alias: om_aut_tech_ha_strom_aus_neustart_time_recording
description: >-
  ## Speichert das Datum des letzten Hardware Neustarts


  - Eigentlich liefert sensor.system_monitor_last_boot bereits diese Information
  aber ältere Info überlebt recorder purge nicht
triggers:
  - trigger: state
    entity_id:
      - sensor.system_monitor_last_boot
conditions:
  - condition: template
    value_template: >-
      {# aber nur wenn ein gültiges Datumsformat vorliegt #}

      {{ (states('sensor.system_monitor_last_boot') |
      as_datetime(default=false)) is not false }}
actions:
  - action: input_text.set_value
    metadata: {}
    data:
      value: >-
        {#speichert 10 Zeitstrings im Format "2025-10-10 10:10;"#}

        {% set number_of_entries = 10 %} {#achte auf 255 Beschränkung#}

        {% set raw = states('input_text.homeassi_hardware_starts') %}

        {% set new_entry =
        as_local(as_datetime(states('sensor.system_monitor_last_boot'))).strftime('%Y-%m-%d
        %H:%M') %}

        {% if not raw or raw == '' %}
          {{ new_entry ~ ';' }}
        {% else %}
          {% set existing = raw.split(';') | reject('equalto', '') | list %}
          {% if existing | length >= number_of_entries %}
            {% set existing = existing[1:] %}
          {% endif %}
          {{ (existing + [new_entry]) | join(';') ~ ';' }}
        {% endif %}
    target:
      entity_id: input_text.homeassi_hardware_starts
mode: single

Dieses Format lese ich in einer Dashboard Markdown Karte wieder aus.

Zusammenfassung
type: markdown
content: >
  {% set raw = states('input_text.homeassi_hardware_starts') -%}

  {% set eintraege = raw.split(';') -%}

  {% set eintraege = eintraege | map('trim') | select('string') |
  reject('equalto', '') | reverse | list -%}

  {% for eintrag in eintraege[-10:] -%}
    {% set ts = strptime(eintrag, '%Y-%m-%d %H:%M') -%}
    {% set diff = (now().replace(tzinfo=None) - ts).days -%}
  - {{ ts.strftime('%d.%m um %H:%M Uhr') }} (vor {{ diff }} Tag{{ 'en' if diff
  != 1 else '' }})

  {% endfor %}
title: Die letzten 10 Strom-Aus Neustarts

Schon komisch, ich hab zwar keinen Sonoff Stick, sondern nen anderen Hersteller, der per LAN mit PoE angeschlossen ist, aber ich hab das Teil noch nie neu starten müssen.

Hast mal einen Bug für die Firmware aufgemacht, bei Github oder wo auch immer die verteilt wird.

Dafür muß ich dem Entwickler erst mal brauchbare Debug Infos liefern können. Meist bin ich in dem Moment so genervt, daß ich alles ausschalte und mir dann Infos fehlen. Ich gestehe, meine Log-Erfahrungen sind bisher eher basic.

Aktualisierter Code ersetzt den von oben

Moin
Es war am Wochenende mal wieder soweit. HA/Raspi stand still und konnte nur durch Strom ab- und anschalten reanimiert werden. Und ich dachte, guter Test für obige Automatisation … aber es wurde kein Strombedingter HA Neustart erkannt, hm.

Also, nochmal Code überarbeitet und diesmal mit Software-reboot und auch wenn es weh tat mit Strom im laufendem Betrieb abgeschaltet.

Automatisation (startet vor dem HA Herunterfahren und nach dem Hochfahren)

Zusammenfassung
alias: om_aut_tech_ha_strom_aus_neustart_time_recording
description: >-
  ## Speichert und liest das Datum/Zeit des letzten Neustarts und vergleicht
  Zeiten


  - Eigentlich liefert sensor.system_monitor_last_boot bereits diese Information
  aber ältere Info überlebt recorder purge nicht

  - Sofern system_monitor_last_boot vorhanden, werden Zeiten verglichen

  - Ansonsten wird geprüft ob ein normales Herunterfahren vor dem Neustart
  innerhalb von 2 Min stattfand
triggers:
  - event: shutdown
    trigger: homeassistant
    id: NormalesHerunterfahren
  - event: start
    trigger: homeassistant
    id: Hochfahren
conditions: []
actions:
  - choose:
      - conditions:
          - condition: trigger
            id:
              - NormalesHerunterfahren
        sequence:
          - action: input_datetime.set_datetime
            metadata: {}
            data:
              datetime: "{{now()}}"
            target:
              entity_id: input_datetime.ha_zeit_von_normalem_herunterfahren
          - action: notify.gmxolaf3
            metadata: {}
            data:
              title: >-
                {{states.sensor.uhrzeit_momentan_formatiert_hh_mm.state}} HA
                normal heruntergefahren (Zeit weurde gespeichert)
              message: >-
                {{states.sensor.uhrzeit_momentan_formatiert_hh_mm.state}} HA
                normal heruntergefahren (Zeit weurde gespeichert)
      - conditions:
          - condition: trigger
            id:
              - Hochfahren
        sequence:
          - if:
              - condition: template
                value_template: >
                  {#

                  True = normales Herunterfahren

                  False = Stromausfall bedingtes Herunterfahren

                  #}

                  {% set time_for_restart_sec = 120 | int %}

                  {% set shutdown_normal =
                  as_local(as_datetime(states('input_datetime.ha_zeit_von_normalem_herunterfahren')))
                  %}

                  {% set ha_start =
                  as_local(as_datetime(states('sensor.uptime'))) %}

                  {% set hw_raw = states('sensor.system_monitor_last_boot') %}

                  {% set valid_hw_starttime = (hw_raw |
                  as_datetime(default=false)) is not false %}


                  {# System_monitor_last_boot ist valide #}

                  {% if valid_hw_starttime %}
                    {% set ha_start_hw = as_local(as_datetime(hw_raw)) %}
                    {% set is_normal_restart = (ha_start_hw < shutdown_normal < ha_start) %}
                  {# 

                  System_monitor_last_boot ist nicht valide aber shutdown_normal
                  ist < ha_start < 120 s

                  Annahme: Es wurde normal gestartet

                  #}

                  {% else %}
                    {% set is_normal_restart = (
                        (ha_start - shutdown_normal).total_seconds() | int < time_for_restart_sec
                    ) %}
                  {% endif %}

                  {{ is_normal_restart }}
            then:
              - action: notify.gmxolaf3
                metadata: {}
                data:
                  title: >-
                    {{states.sensor.uhrzeit_momentan_formatiert_hh_mm.state}} HA
                    gestartet nach normalem Herunterfahren
                  message: >-
                    {{states.sensor.uhrzeit_momentan_formatiert_hh_mm.state}} HA
                    gestartet nach normalem Herunterfahren
            else:
              - action: notify.gmxolaf3
                metadata: {}
                data:
                  title: >-
                    {{states.sensor.uhrzeit_momentan_formatiert_hh_mm.state}} HA
                    gestartet nach Stromausfall !!!
                  message: >-
                    {{states.sensor.uhrzeit_momentan_formatiert_hh_mm.state}} HA
                    gestartet nach Stromausfall
              - action: input_text.set_value
                metadata: {}
                data:
                  value: >-
                    {#speichert 10 Zeitstrings im Format "2025-10-10 10:10;"#}

                    {% set number_of_entries = 10 %} {#achte auf 255
                    Beschränkung#}

                    {% set raw = states('input_text.homeassi_hardware_starts')
                    %}

                    {% set new_entry =
                    as_local(as_datetime(states('sensor.system_monitor_last_boot'))).strftime('%Y-%m-%d
                    %H:%M') %}

                    {% if not raw or raw == '' %}
                      {{ new_entry ~ ';' }}
                    {% else %}
                      {% set existing = raw.split(';') | reject('equalto', '') | list %}
                      {% if existing | length >= number_of_entries %}
                        {% set existing = existing[1:] %}
                      {% endif %}
                      {{ (existing + [new_entry]) | join(';') ~ ';' }}
                    {% endif %}
                target:
                  entity_id: input_text.homeassi_hardware_starts
                enabled: true
mode: single

  • Zeit Helfer input_datetime.ha_zeit_von_normalem_herunterfahren muß angelegt werden
  • Text Helfer input_text.homeassi_hardware_starts muß angelegt werden
  • Die Email Benachrichtigungen könnt Ihr rausnehmen, ist ein Art Debugging für mich

Markdown-Karte

Zusammenfassung
type: markdown
content: >
  {% set raw = states('input_text.homeassi_hardware_starts') -%}

  {% set eintraege = raw.split(';') -%}

  {% set eintraege = eintraege | map('trim') | select('string') |
  reject('equalto', '') | reverse | list -%}

  {% for eintrag in eintraege[-10:] -%}
    {% set ts = strptime(eintrag, '%Y-%m-%d %H:%M') -%}
    {% set diff = (now().replace(tzinfo=None) - ts).days -%}
  - {{ ts.strftime('%d.%m um %H:%M Uhr') }} (vor {{ diff }} Tag{{ 'en' if diff
  != 1 else '' }})

  {% endfor %}
title: Die letzten 10 Strom-Aus Neustarts

1 „Gefällt mir“