🧬Datenmodell

Vom Funkstick bis zur Zahl im Dashboard: Wie Home Assistant Integrationen, Geräte und Entitäten ordnet – und was genau in einem State-Objekt steht.

🪜Die Kette: Integration → Config Entry → Gerät → Entität

Integration  zha              (Code im Core: homeassistant/components/zha)
   │
   └─ Config Entry  „Zigbee-Stick (USB)“       ← eingerichtet über UI / Discovery
         │
         ├─ Gerät  „Wohnzimmer Decke“          ← Device Registry (Hersteller, Modell, Area)
         │     └─ Entität  light.wohnzimmer_decke        ← Entity Registry (unique_id ↔ entity_id)
         │            └─ State  on · {brightness: 255, …} ← State Machine (aktueller Wert)
         │
         └─ Gerät  „Flur Bewegungsmelder“
               ├─ Entität  binary_sensor.flur_bewegung
               └─ Entität  sensor.flur_bewegungsmelder_batterie   (entity_category: diagnostic)
💡 unique_id vs. entity_id
Die unique_id vergibt die Integration (z. B. IEEE-Adresse + Endpunkt) – sie ändert sich nie. Die entity_id ist der Name, den Automationen benutzen; Sie können sie umbenennen, die Registry merkt sich die Zuordnung.
✅ Entitäten ohne Gerät
Helfer (input_boolean, counter, timer), sun.sun oder Template-Sensoren haben kein Gerät. Ohne unique_id landet eine Entität gar nicht in der Registry – dann lässt sie sich in der UI nicht bearbeiten.
⚠️ Neu seit 2026.8
Ein Gerät gehört nur noch zu einem Config Entry (höchstens einem Subentry). Früher konnten mehrere Integrationen dasselbe physische Gerät zusammenführen – mit widersprüchlichen Namen und Modellen.

🗂️Musterhaus-Explorer

Links der Baum in drei Sichten, rechts die Registry-Einträge und das State-Objekt. Alle Geräte, Adressen und IDs sind erfunden.

light.wohnzimmer_decke

Entität der Plattform „zha“. Oben der Eintrag in der Entity Registry (dauerhaft, .storage), unten das State-Objekt in der State Machine (flüchtig, aktuelle Werte).

{
"entity_registry": {
"labels": [
"nachtmodus"
],
"has_entity_name": true,
"name": null,
"entity_id": "light.wohnzimmer_decke",
"unique_id": "0a:bc:de:01:00:00:00:a1-11",
"platform": "zha",
"device_id": "dev_wz_decke",
"config_entry_id": "01JCE0ZHA000000000000000AA",
"original_name": null,
"area_id": null,
"→ area (effektiv)": "Wohnzimmer",
"→ gerät": "Wohnzimmer Decke"
}
}
State-Objekt
{
"entity_id": "light.wohnzimmer_decke",
"state": "off",
"attributes": {
"supported_color_modes": [
"color_temp"
],
"color_mode": null,
"brightness": null,
"min_color_temp_kelvin": 2202,
"max_color_temp_kelvin": 6535,
"friendly_name": "Wohnzimmer Decke",
"supported_features": 40
},
"last_changed": "2026-09-25T19:30:00.000+00:00",
"last_reported": "2026-09-25T19:30:00.000+00:00",
"last_updated": "2026-09-25T19:30:00.000+00:00",
"context": {
"id": "01M3D0QHP0WPZBZBVX18BX041H",
"parent_id": null,
"user_id": null
}
}
🏷️ Nachtmodus

🔤Die entity_id: domain.object_id

light.wohnzimmer_decke✔ gültig

Domain light: bekannte Entitäts-Plattform bzw. Helfer-Domain.

Regel aus homeassistant/core.py: nur a–z, 0–9 und „_“, kein „_“ am Anfang/Ende eines Teils, kein „__“. Die object_id entsteht meist aus Geräte- und Entitätsname (slugify: „Wohnzimmer Decke“ → wohnzimmer_decke, „Küche“ → kuche) und ist in der UI umbenennbar – die interne unique_id bleibt.

# Home Assistant Core (homeassistant/core.py), gekürzt
_OBJECT_ID = r"(?!_)[\da-z_]+(?<!_)"
_DOMAIN = r"(?!.+__)" + _OBJECT_ID
VALID_ENTITY_ID = re.compile(r"^" + _DOMAIN + r"\." + _OBJECT_ID + r"$")

def split_entity_id(entity_id: str) -> tuple[str, str]:
    domain, _, object_id = entity_id.partition(".")
    if not domain or not object_id:
        raise ValueError(f"Invalid entity ID {entity_id}")
    return domain, object_id
💡 Domain = Plattform
Die Domain vor dem Punkt sagt, was die Entität ist (light, sensor, binary_sensor …) und damit, welche Actions passen: light.turn_on geht nur auf light.*. Die Integration (zha, mqtt …) steht nicht in der ID.

📦Das State-Objekt

Jede Entität hat in der State Machine genau ein State-Objekt. Der Zustand ist immer Text – auch bei Zahlen. Einheiten, Helligkeit, Gerätetyp und Anzeigename stehen in den Attributen.
{
  "entity_id": "sensor.wohnzimmer_temperatur",
  "state": "21.4",                       ← Text, max. 255 Zeichen
  "attributes": {
    "state_class": "measurement",
    "unit_of_measurement": "°C",
    "device_class": "temperature",
    "friendly_name": "Wohnzimmer Temperatur"
  },
  "last_changed":  "2026-09-25T19:30:00.000+00:00",   ← UTC
  "last_reported": "2026-09-25T19:30:00.000+00:00",
  "last_updated":  "2026-09-25T19:30:00.000+00:00",
  "context": {
    "id": "01K6…",          ← ULID
    "parent_id": null,     ← wer hat es ausgelöst?
    "user_id": null        ← Mensch? dann dessen ID
  }
}
FeldBedeutung
stateAktueller Zustand als Text: on/off, 21.4, open, unknown, unavailable …
attributesZusätzliche Eigenschaften: Einheit, device_class, Helligkeit, friendly_name …
last_changedZeit der letzten Zustandsänderung – nicht bei reinen Attributänderungen
last_updatedZeit der letzten Änderung von Zustand oder Attributen
last_reportedZeit des letzten Schreibens, auch ohne Änderung
context.idEindeutige ID dieser Änderung
context.parent_idID des auslösenden Contexts (z. B. Automation → Taster)
context.user_idBenutzer, der es ausgelöst hat; bei Automationen None

Zusätzlich abgeleitet: domain, object_id, name (aus friendly_name). Sonderzustände: unavailable (Integration erreicht das Gerät nicht), unknown (noch kein Wert).

⏱️Simulator: last_changed vs. last_updated vs. last_reported

Die Nachbildung folgt der Logik der State Machine in core.py: gleicher Zustand und gleiche Attribute → nur last_reported (Event state_reported); nur Attribute anders → last_updated; Zustand anders → alles.
light.wohnzimmer_decke
💡offbrightness: null
Uhr im Labor
21:00:00
last_changed21:00:00nur wenn sich der Zustand (state) ändert
last_updated21:00:00wenn sich Zustand ODER Attribute ändern
last_reported21:00:00bei jedem Schreiben – auch ohne Änderung (neu seit 2024)

Was ist passiert?

Noch nichts – drücken Sie links einen Knopf. Zwischendurch „+10 s“, damit man die Zeitstempel unterscheiden kann.

    Merksatz: „Seit wann ist das Licht an?“ → last_changed. „Wann hat sich zuletzt irgendetwas getan?“ → last_updated. „Meldet sich der Sensor noch?“ → last_reported.

    🏢Areas, Floors, Labels

    🚪 Area

    Ein Raum oder Bereich. Geräte bekommen eine Area, ihre Entitäten erben sie – einzelne Entitäten dürfen abweichen (im Musterhaus: der Zähler-Helfer im Flur).

    🏢 Floor

    Etage mit Ebene (level). Eine Area gehört zu höchstens einem Floor. Seit 2024.4, zusammen mit Labels eingeführt.

    🏷️ Label

    Freie Schlagworte mit Farbe und Icon – quer zu allem, auch an Automationen. Beliebig viele pro Objekt.

    actions:
      - action: light.turn_off
        target:
          floor_id: obergeschoss        # alle Lichter im Obergeschoss
      - action: homeassistant.turn_off
        target:
          label_id: nachtmodus          # alles mit dem Label „Nachtmodus“
      - action: light.turn_on
        target:
          area_id: wohnzimmer
          entity_id: light.flur         # Ziele lassen sich kombinieren