ha-persistable-sensors

star 0

Build or modify Home Assistant sensors/entities that must persist native values and custom attributes across restarts using RestoreSensor/RestoreEntity plus ExtraStoredData (e.g., history, timestamps, scenarios); apply when persistence of non-native fields is required.

plebann By plebann schedule Updated 1/20/2026

name: ha-persistable-sensors description: Build or modify Home Assistant sensors/entities that must persist native values and custom attributes across restarts using RestoreSensor/RestoreEntity plus ExtraStoredData (e.g., history, timestamps, scenarios); apply when persistence of non-native fields is required.

Home Assistant Persistable Sensors

Quick Start

  • Inherit from RestoreSensor (or RestoreEntity for other domains).
  • Define an ExtraStoredData subclass to capture custom fields; keep it JSON-serializable.
  • In async_added_to_hass, hydrate via async_get_last_extra_data() before first state write.
  • Override extra_restore_state_data to always return current native value + custom fields.
  • Bound lists (e.g., 50 entries) and keep consistent ordering (newest-first recommended).
  • After any mutation, call async_write_ha_state() so HA persists updated state.

Template

from homeassistant.components.sensor import RestoreSensor
from homeassistant.helpers.restore_state import ExtraStoredData

class MyExtraData(ExtraStoredData):
    def __init__(self, native_value: str | None, history: list[dict[str, Any]]):
        self.native_value = native_value
        self.history = history

    def as_dict(self) -> dict[str, Any]:
        return {"native_value": self.native_value, "history": self.history}

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> MyExtraData:
        history = data.get("history", []) if isinstance(data.get("history"), list) else []
        history = history[:50]  # bound size, newest-first expected
        return cls(data.get("native_value"), history)

class MyPersistableSensor(RestoreSensor):
    _attr_has_entity_name = True
    _attr_native_value: str | None = None

    def __init__(self) -> None:
        self._history: list[dict[str, Any]] = []

    async def async_added_to_hass(self) -> None:
        await super().async_added_to_hass()
        if (extra := await self.async_get_last_extra_data()) is not None:
            restored = MyExtraData.from_dict(extra.as_dict())
            self._attr_native_value = restored.native_value
            self._history = restored.history

    @property
    def extra_restore_state_data(self) -> MyExtraData:
        return MyExtraData(self._attr_native_value, self._history)

    def add_entry(self, entry: dict[str, Any]) -> None:
        self._history.insert(0, entry)
        self._history = self._history[:50]
        self._attr_native_value = entry.get("summary")
        self.async_write_ha_state()

Checklist (Do/Verify)

  • Set _attr_has_entity_name = True and stable _attr_unique_id.
  • Keep properties lightweight; avoid I/O in getters.
  • Clamp list sizes and prefer newest-first ordering.
  • Serialize timestamps as ISO strings; parse in from_dict.
  • Always return extra_restore_state_data, even when empty fields are possible (handle defaults in from_dict).
  • Call async_write_ha_state() after updates to trigger persistence.

Notes

  • Use RestoreEntity if the platform is not a sensor; adapt imports accordingly.
  • For large attribute payloads, consider moving bulky data to dedicated entities instead of attributes to reduce recorder load.
Install via CLI
npx skills add https://github.com/plebann/EnergyOptimizer --skill ha-persistable-sensors
Repository Details
star Stars 0
call_split Forks 0
navigation Branch main
article Path SKILL.md
More from Creator