Werklio
☰

Integrationen

Home Assistant einrichten

Heartbeats und Batterie-Entitäten ohne manuelle Objektliste sicher ausgehend senden.

Voraussetzungen

  • Home Assistant mit Internetzugang
  • Ein Werklio-Standort mit Integration Home Assistant
  • Der einmalig angezeigte API-Key
  • Optional: die Home-Assistant-Integration Version mit Quelle Lokale Installation

Schritt für Schritt

  1. Öffne in Werklio den Standort und kopiere Standort-ID sowie API-Key.
  2. Lege den Key in secrets.yaml ab.
  3. Füge den vollständigen Connector einschließlich template werklio, rest_command und automation werklio zur configuration.yaml hinzu.
  4. Lass ein vorhandenes automation: !include automations.yaml unverändert; die beschrifteten Werklio-Blöcke dürfen daneben stehen.
  5. Prüfe die Konfiguration und starte Home Assistant vollständig neu. Dabei legt Werklio sensor.werklio_started_at mit dem aktuellen Startzeitpunkt an.
  6. Werklio sucht danach automatisch nach sensor- und binary_sensor-Entitäten mit der Geräteklasse battery; eine manuelle Entity-Liste ist nicht erforderlich.
  7. Prüfe unter Entwicklerwerkzeuge → Zustände, dass sensor.werklio_started_at einen UTC-Zeitpunkt enthält.
  8. Prüfe unter Entwicklerwerkzeuge → Aktionen, ob rest_command.werklio_heartbeat und rest_command.werklio_battery_snapshot vorhanden sind, und führe beide einmal manuell aus.

Beispielkonfiguration

# secrets.yaml
werklio_api_key: wk_live_DEIN_EINMALIGER_KEY

# configuration.yaml
# Eigener Startzeit-Sensor; funktioniert ohne die optionale Uptime-Integration.
template werklio:
  - triggers:
      - trigger: homeassistant
        event: start
    sensor:
      - name: "Werklio Started At"
        default_entity_id: sensor.werklio_started_at
        unique_id: werklio_started_at
        device_class: timestamp
        state: "{{ utcnow().isoformat() }}"

rest_command:
  werklio_heartbeat:
    url: "https://app.werkl.io/api/ingest/homeassistant/heartbeat"
    method: POST
    headers:
      X-Werklio-Key: !secret werklio_api_key
      Idempotency-Key: "ha-{{ now().timestamp() | int }}"
    content_type: "application/json"
    verify_ssl: true
    payload: >-
      {% set version_sensor_value = states("sensor.current_version") %}
      {% set supervisor_version = state_attr("update.home_assistant_core_update", "installed_version") %}
      {% set version_value = version_sensor_value if version_sensor_value not in ["unknown", "unavailable", "none", ""] else supervisor_version %}
      {% set werklio_started_at = as_timestamp(states("sensor.werklio_started_at"), default=none) %}
      {% set uptime_entities = integration_entities("uptime") %}
      {% set uptime_entity = (uptime_entities | first) if (uptime_entities | count) > 0 else none %}
      {% set integration_started_at = as_timestamp(states(uptime_entity), default=none) if uptime_entity is not none else none %}
      {% set started_at = werklio_started_at if werklio_started_at is not none else integration_started_at %}
      {{ {
        "apiVersion": "2026-08-01",
        "siteId": "DEINE-STANDORT-GUID",
        "source": "homeassistant",
        "sourceVersion": version_value if version_value not in [none, "unknown", "unavailable", "none", ""] else none,
        "sentAtUtc": utcnow().isoformat(),
        "status": "online",
        "uptimeSeconds": ((as_timestamp(utcnow()) - started_at) | int(0)) if started_at is not none else none
      } | to_json }}

  # Zero-Configuration-Batterieerkennung: findet Prozent-Sensoren und
  # binäre Low-Battery-Melder anhand ihrer Home-Assistant-Geräteklasse.
  werklio_battery_snapshot:
    url: "https://app.werkl.io/api/ingest/homeassistant/snapshot"
    method: POST
    headers:
      X-Werklio-Key: !secret werklio_api_key
      Idempotency-Key: "ha-battery-{{ (now().timestamp() * 1000) | int }}"
    content_type: "application/json"
    verify_ssl: true
    payload: >-
      {% set ns = namespace(items=[]) %}
      {% for entity in states.sensor | selectattr("attributes.device_class", "defined") | selectattr("attributes.device_class", "eq", "battery") %}
        {% set level = entity.state | float(none) %}
        {% set valid = level is not none and level >= 0 and level <= 100 %}
        {% set room = area_name(entity.entity_id) %}
        {% set label = device_name(entity.entity_id) or entity.name or entity.entity_id %}
        {% set ns.items = ns.items + [{
          "externalId": entity.entity_id,
          "name": label,
          "type": "battery",
          "status": "online" if valid else "unknown",
          "value": (level | round(0) | int) if valid else none,
          "unit": "%" if valid else none,
          "batteryPercent": (level | round(0) | int) if valid else none,
          "lastSeenUtc": utcnow().isoformat(),
          "diagnostic": (("Gemeldeter Batteriestand: " ~ (level | round(0) | int) ~ "%") if valid else "Kein gültiger Batteriewert") ~ ((" · " ~ room) if room else ""),
          "isCritical": false
        }] %}
      {% endfor %}
      {% for entity in states.binary_sensor | selectattr("attributes.device_class", "defined") | selectattr("attributes.device_class", "eq", "battery") %}
        {% set valid = entity.state in ["on", "off"] %}
        {% set low = entity.state == "on" %}
        {% set room = area_name(entity.entity_id) %}
        {% set label = device_name(entity.entity_id) or entity.name or entity.entity_id %}
        {% set ns.items = ns.items + [{
          "externalId": entity.entity_id,
          "name": label,
          "type": "battery",
          "status": "online" if valid else "unknown",
          "value": low if valid else none,
          "batteryLow": low if valid else none,
          "lastSeenUtc": utcnow().isoformat(),
          "diagnostic": (("Batterie schwach gemeldet" if low else "Batterie in Ordnung gemeldet") if valid else "Batteriezustand unbekannt") ~ ((" · " ~ room) if room else ""),
          "isCritical": false
        }] %}
      {% endfor %}
      {{ {
        "apiVersion": "2026-08-01",
        "siteId": "DEINE-STANDORT-GUID",
        "source": "homeassistant",
        "sentAtUtc": utcnow().isoformat(),
        "eventId": "ha-battery-" ~ (as_timestamp(utcnow()) | int),
        "isFullSnapshot": true,
        "scope": "battery",
        "items": ns.items
      } | to_json }}

  # Optionales Beispiel: Wirkleistung als Entitätswert übertragen.
  # Vor der Verwendung die Kommentarzeichen dieses gesamten Blocks entfernen
  # und Entity-ID sowie Anzeigenamen anpassen.
  # werklio_power_snapshot:
  #   url: "https://app.werkl.io/api/ingest/homeassistant/snapshot"
  #   method: POST
  #   headers:
  #     X-Werklio-Key: !secret werklio_api_key
  #     Idempotency-Key: "ha-power-{{ (now().timestamp() * 1000) | int }}"
  #   content_type: "application/json"
  #   verify_ssl: true
  #   payload: >-
  #     {% set entity_id = "sensor.smart_meter_ts_65a_3_wirkleistung" %}
  #     {% set raw_value = states(entity_id) %}
  #     {% set numeric_value = raw_value | float(none) %}
  #     {% set unit = state_attr(entity_id, "unit_of_measurement") or "W" %}
  #     {{ {
  #       "apiVersion": "2026-08-01",
  #       "siteId": "DEINE-STANDORT-GUID",
  #       "source": "homeassistant",
  #       "sentAtUtc": utcnow().isoformat(),
  #       "isFullSnapshot": false,
  #       "items": [
  #         {
  #           "externalId": entity_id,
  #           "name": state_attr(entity_id, "friendly_name") or "Smart Meter Wirkleistung",
  #           "type": "sensor",
  #           "status": "online" if numeric_value is not none else "unknown",
  #           "value": numeric_value,
  #           "unit": unit,
  #           "lastSeenUtc": utcnow().isoformat(),
  #           "diagnostic": (raw_value ~ " " ~ unit) if numeric_value is not none else "Kein gültiger Leistungswert",
  #           "isCritical": false
  #         }
  #       ]
  #     } | to_json }}

# Eigener, beschrifteter Block – kein zweites unbeschriftetes "automation:".
automation werklio:
  - id: werklio_heartbeat
    alias: "Werklio Heartbeat"
    triggers:
      - trigger: time_pattern
        minutes: "/1"
    actions:
      - action: rest_command.werklio_heartbeat
    mode: single

  - id: werklio_battery_snapshot
    alias: "Werklio Batterien automatisch erkennen"
    triggers:
      - trigger: homeassistant
        event: start
      - trigger: time_pattern
        minutes: "/15"
    actions:
      - action: rest_command.werklio_battery_snapshot
    mode: single

  # Optionales Beispiel passend zu werklio_power_snapshot.
  # Fünf Sekunden erzeugen 17.280 Zustandsdatensätze pro Tag; für eine
  # reine Statusanzeige sind 10 oder 30 Sekunden meist ausreichend.
  # - id: werklio_power_snapshot
  #   alias: "Werklio Wirkleistung"
  #   triggers:
  #     - trigger: time_pattern
  #       seconds: "/5"
  #   actions:
  #     - action: rest_command.werklio_power_snapshot
  #   mode: single

Testschritt

Entwicklerwerkzeuge → Aktionen → rest_command.werklio_heartbeat und rest_command.werklio_battery_snapshot ausführen. Danach in Werklio ‚Integration testen‘ wählen.

Erwartetes Ergebnis

HTTP 202; die Integration zeigt ‚Gesund‘ und erkannte Batterien erscheinen automatisch im Batterie-Tab.

Fehlerbehebung

  • Version nicht gemeldet: Die Integration Version mit Quelle Lokale Installation hinzufügen; alternativ wird die installierte Version aus update.home_assistant_core_update gelesen.
  • Uptime nicht gemeldet: Unter Entwicklerwerkzeuge → Zustände sensor.werklio_started_at prüfen. Fehlt er, muss der Block template werklio vollständig übernommen und Home Assistant neu gestartet werden.
  • Sensor-ID abweichend: Eine ältere gleichnamige Entität entfernen oder im REST-Template die unter Entwicklerwerkzeuge sichtbare Entity-ID einsetzen.
  • Unbekannte Aktion rest_command.werklio_heartbeat: configuration.yaml prüfen und Home Assistant vollständig neu starten.
  • 401: Key/Integration passen nicht – Key rotieren und secrets.yaml aktualisieren.
  • 400 site_mismatch: Standort-ID exakt als GUID übernehmen.
  • Kein Kontakt: DNS, Systemzeit und ausgehendes HTTPS prüfen.
  • Templatefehler: Aktion in den Entwicklerwerkzeugen öffnen und gerenderten JSON-Inhalt prüfen.

Sicherheitshinweise

  • Key ausschließlich in secrets.yaml speichern und nicht in Trace-/Debug-Logs ausgeben.
  • Nur für Healthcheck relevante Entitäten übertragen.
  • Keine Anwesenheitsnamen verwenden; neutrale Anzeigenamen wählen.