Part 1: Foundational Concepts¶
1.1 Home Assistant Core Behavior¶
Home Assistant Core is an event-driven application that maintains real-time state for all entities in your system. Understanding this architecture is crucial to understanding how statistics are derived. We first look at some key concepts.
Entities and States¶
Entities are the basic building blocks to hold data in Home Assistant. An entity represents a sensor, actor, or function in Home Assistant. Entities are used to monitor physical properties or to control other entities. An entity is usually part of a device or a service. Entities constantly keep track of their state and associated attributes. For example:
- Entity:
light.kitchen - State:
on - Attributes: color, brightness, etc.
Events¶
Everything that happens in HA is represented as an event:
- A light being turned on
- A motion sensor being triggered
- An automation executing
- A state change occurring
Note that all entities produce state change events. Every time a state changes, a state change event is produced. State change events are just one type of event on the event bus, but there are other kinds of events, such as the built-in events that are used to coordinate between various integrations.
State Update Frequency¶
The frequency of state updates varies by integration:
- Polling integrations: Update at regular intervals (e.g., every 30 seconds for a temperature sensor)
- Push-based integrations: Update when the device reports a change (e.g., a ZigBee temperature sensor waking from sleep)
- Event-based integrations: Update immediately when triggered (e.g., a button press)
Stateless Operation¶
HA Core can run without persistent history. In this mode, you always know the current state of your system, but not how you arrived there. The Recorder integration provides this historical context.
Further Reading: For more details, see the Core Architecture, Sensor entity, Entities: integrating devices & services, and States documentation.
1.2 The Recorder Integration¶
The Recorder integration stores historical data about your system in a database, enabling you to track how states change over time.
Sampling and Storage¶
- Objects are sampled every 5 seconds by default (configurable)
- Values are committed to the database only if they are valid and if they have changed
- This 5-second interval balances responsiveness with storage efficiency. According to the Nyquist-Shannon sampling theorem, a 5-second sampling rate can accurately capture changes that occur at intervals of 10 seconds or longer. For faster-changing values, intermediate states may not be captured, though the system will still record the value present at each 5-second sample.
Database Backend¶
- Default: SQLite (suitable for most installations)
- Alternatives: PostgreSQL, MySQL/MariaDB (for advanced setups with high write volumes)
Further Reading: See the Database Schema documentation for complete table descriptions.
1.3 The States Table¶
The Recorder Integration writes to numerous tables in the database, but in the context of this document, the table we are interested in is the states table that is the primary storage location for entity state history. Understanding its structure is essential for working with raw data and statistics.
Table Schema¶
We only show the fields that are in use at the time of this writing. Other fields in the table are deprecated and should be ignored.
| Field | Type | Description |
|---|---|---|
state_id |
INTEGER | Primary key, auto-incrementing unique identifier for each state record |
metadata_id |
INTEGER | Foreign key tostates_meta table (contains entity_id mapping) |
state |
VARCHAR(255) | The actual state value (e.g., "234.0", "on", "off", "23.5°C") |
last_updated_ts |
FLOAT | Unix timestamp when state was last updated (even if only attributes changed) |
last_changed_ts |
FLOAT | Unix timestamp when the actual state value changed (NULL if same aslast_updated_ts) |
last_reported_ts |
FLOAT | Unix timestamp when the state was last reported by the integration |
old_state_id |
INTEGER | Links to the previousstate_id for this entity (enables state history traversal) |
attributes_id |
INTEGER | Foreign key tostate_attributes table (stored separately to avoid duplication) |
context_id_bin |
BLOB(16) | Binary UUID identifying the context that caused this state change |
context_user_id_bin |
BLOB(16) | Binary UUID of the user who initiated the change (if applicable) |
context_parent_id_bin |
BLOB(16) | Binary UUID of the parent context (for automation chains) |
origin_idx |
SMALLINT | Index indicating the origin of the state change |
Important Distinctions¶
last_updated_ts: Unix timestamp when state OR attributes changelast_changed_ts: Unix timestamp when the actual state value changed (stored as NULL when it equalslast_updated_tsto save database space)last_reported_ts: Unix timestamp from the integration/device
1.4 Entities Generating Statistics¶
The states table tracks all entities, but in this document we focus specifically on "statistics" entities - those that generate long-term statistics.
These entities belong to two main categories (we'll explore these in detail in Part 2):
- the measurement type
- the total/counter type .
Note on Data Retention: While statistics are retained long-term, the detailed state history in the
statestable is typically purged after a configurable period (default: 10 days). This is why statistics are essential for long-term trend analysis.
Let's examine how state tracking works with practical examples.
1.5 Examples tracking statistics¶
Apparent Power Consumption¶
Consider an integration that polls the instantaneous apparent power consumption (a "measurement" type sensor) of a house every minute .
| entity_id | state | last_updated | last_changed | last_reported |
|---|---|---|---|---|
| sensor.linky_sinsts | 2040 | 1/27/2026 13:00 | 1/27/2026 13:00 | 1/27/2026 13:00 |
| sensor.linky_sinsts | 2030 | 1/27/2026 13:01 | 1/27/2026 13:01 | 1/27/2026 13:01 |
| sensor.linky_sinsts | 2023 | 1/27/2026 13:02 | 1/27/2026 13:02 | 1/27/2026 13:02 |
| ... | ... | ... | ... | ... |
ZigBee Temperature Sensor¶
In contrast, a ZigBee temperature sensor (a "measurement" type sensor) reports values at intervals determined by the device itself, which may be irregular:
| entity_id | state | last_updated | last_changed | last_reported |
|---|---|---|---|---|
| sensor.family_temperature | 13.59 | 1/27/26 12:00 | 1/27/26 12:00 | 1/27/26 12:00 |
| sensor.family_temperature | 13.63 | 1/27/26 12:01 | 1/27/26 12:01 | 1/27/26 12:01 |
| sensor.family_temperature | 13.6 | 1/27/26 12:38 | 1/27/26 12:38 | 1/27/26 12:38 |
| sensor.family_temperature | 13.64 | 1/27/26 12:51 | 1/27/26 12:51 | 1/27/26 12:51 |
Energy Meter¶
The two entities presented above generates statistics that belong to the measurement type. This example belongs to the counter type (e.g., energy consumption) where the state values are monotonically increasing:
| entity_id | state | last_updated | last_changed | last_reported |
|---|---|---|---|---|
| sensor.linky_east | 72199456 | 1/27/2026 12:59 | 1/27/2026 12:59 | 1/27/2026 12:59 |
| sensor.linky_east | 72199488 | 1/27/2026 13:00 | 1/27/2026 13:00 | 1/27/2026 13:00 |
| sensor.linky_east | 72199520 | 1/27/2026 13:01 | 1/27/2026 13:01 | 1/27/2026 13:01 |
| ... | ... | ... | ... | ... |