Skip to main content

Historical sensors for HomeAssistant

Project description

Historical sensors for Home Assistant

GitHub Release (latest SemVer including pre-releases) CodeQL Code style: black

Buy Me A Coffee

Feed historical statistics into Home Assistant database.

HomeAssistant architecture is built around polling (or pushing) data from devices, or data providers, in "real-time". Some data sources (e.g, energy, water or gas providers) can't be polled in real-time or readings are not accurate. However reading historical data, like last month consumption, is possible and accurate. This module adds support to this.

This module uses the recorder component and Home Assistant's official statistics API to import historical statistics data.

Current projects using this module:

Important: v3.0 Breaking Changes

Version 3.0 removes state writing entirely. Historical sensors now only write statistics, not individual states. This means:

What still works:

  • Energy dashboard integration
  • Long-term statistics and trends
  • Hourly/daily/monthly aggregated data
  • All existing integration code (minimal changes needed)

What no longer works:

  • Individual state points in entity history graphs
  • Granular state visualization in the UI

Why this change? Directly manipulating Home Assistant's recorder database was extremely complex, fragile, and error-prone. The code for maintaining state chains, handling schema changes, and managing database integrity was unsustainable. Statistics provide everything needed for 99% of use cases while using Home Assistant's official, stable API.

See [https://github.com/ldotlopez/ha-historical-sensor/issues/18] for detailed explanation and migration guide.

How to implement a historical sensor

💡 Check the delorian test integration in this repository

  1. Import home_assistant_historical_sensor and define your sensor. ⚠️ Don't set the SensorEntity.state_class property. See FAQ below
from homeassistant_historical_sensor import (
    HistoricalSensor, HistoricalState, PollUpdateMixin,
)


class Sensor(PollUpdateMixin, HistoricalSensor, SensorEntity):
    ...
  1. Define the async_update_historical method and save your historical states into the HistoricalSensor._attr_historical_states attribute.
async def async_update_historical(self):
    self._attr_historical_states = [
        HistoricalState(state=x.state, timestamp=x.when.timestamp()) 
        for x in await api.fetch()
    ]

Note: timestamp expects a Unix timestamp (float).

  1. Define the get_statistic_metadata method for your sensor.
def get_statistic_metadata(self) -> StatisticMetaData:
    meta = super().get_statistic_metadata()
    meta["has_sum"] = True  # For counters (energy, water, gas)
    # OR
    meta["has_mean"] = True  # For measurements (temperature, power)
    
    return meta
  1. Define the async_calculate_statistic_data method for your sensor.

This method calculates statistics from your historical states. Check the delorian integration for a full example.

async def async_calculate_statistic_data(
    self, 
    hist_states: list[HistoricalState], 
    *, 
    latest: StatisticsRow | None = None,
) -> list[StatisticData]:
    # Calculate hourly statistics from your states
    # Return list of StatisticData with start, state, sum/mean
    ...
  1. Done! Besides other Home Assistant considerations, this is everything you need to implement statistics importing into Home Assistant.

Technical details

Q. How does it work?

A. The architecture is straightforward:

  1. _attr_historical_states property: Holds a list of HistoricalState objects, each containing a state value and a timestamp (Unix timestamp as float).

  2. async_update_historical hook: Your implementation updates _attr_historical_states with data from your source. This is the only method you must implement.

  3. async_calculate_statistic_data method: Calculates statistics (sum/mean/min/max) from historical states. You must implement this to generate statistics.

  4. async_write_ha_historical_states method: Implemented by HistoricalSensor, handles writing statistics to Home Assistant using the official async_import_statistics API.

Q. What happened to state writing?

A. Removed in v3.0. Writing states directly to the database was extremely complex and fragile. The module now only writes statistics using Home Assistant's official API, which is:

  • Simpler and more maintainable
  • Forward-compatible with HA updates
  • Sufficient for energy dashboards and long-term trends

Individual state points no longer appear in entity history graphs, but statistics work perfectly for energy monitoring and trend analysis.

Q. What is PollUpdateMixin and why do I need to inherit from it?

A. Home Assistant sensors can use the poll or the push model to update data.

Historical sensors use a false push model: they are never updated by themselves (the state property always returns STATE_UNKNOWN).

PollUpdateMixin provides automatic periodic updates without any code. The sensor will be updated at startup and every hour. This interval can be configured via the UPDATE_INTERVAL class attribute.

Q. Why should I NOT set the state_class property?

A. Because it causes Home Assistant to calculate its own statistics from the sensor's current state, which:

  • Doesn't make sense for historical data
  • Creates incorrect/duplicate statistics
  • Conflicts with your manual statistics calculations

Historical sensors provide statistics through async_calculate_statistic_data, not through state_class.

Q. Why is my sensor in "Unknown" state?

A. This is expected and correct. Historical sensors don't provide current state—they only import past statistics. The sensor will always show "Unknown" as its state because:

  • The last historical data point (from hours/days ago) is NOT the current state
  • The current state is genuinely unknown
  • Only statistics are meaningful for this type of sensor

Q. Why doesn't my sensor show up in the energy panel?

A. Energy dashboard uses statistics, not sensor states. If your sensor doesn't appear:

  1. Make sure you've implemented get_statistic_metadata() with has_sum=True
  2. Make sure you've implemented async_calculate_statistic_data()
  3. Trigger an update to import data and generate statistics
  4. Statistics will appear after the first successful import

Q. Can I provide BOTH current state AND historical statistics?

A. You need two separate sensors:

  • One regular sensor for current state (with state_class)
  • One HistoricalSensor for importing historical statistics

If you're using the data coordinator pattern, this should be straightforward.

Q. Can I calculate energy/water/gas costs?

A. Cost calculation must be done in Home Assistant's Energy dashboard configuration, not in the sensor itself. The Energy dashboard has built-in cost calculation features.

The energy websocket API may be useful for advanced use cases.

Q. Do I need to worry about overlapping data when re-importing?

A. No. The library handles this automatically:

  • New statistics are only added if they're newer than the last imported statistic
  • You can safely re-run imports without creating duplicates

Migration from v2.x to v3.x

Breaking Changes

  1. HistoricalState parameter renamed: tstimestamp (but ts still works for backward compatibility)

  2. group_by_interval parameter fixed: granuralitygranularity (typo fix)

  3. Minimum Home Assistant version: Now requires HA >= 2025.12.0

  4. statistic_id property removed: Statistics now always use entity_id

  5. No more state writing: Only statistics are written to the database

What You Need to Update

# Before (v2.x)
HistoricalState(state=value, ts=timestamp)

# After (v3.x) - both work, but timestamp is preferred
HistoricalState(state=value, timestamp=timestamp)
HistoricalState(state=value, ts=timestamp)  # Still supported

# Before (v2.x)
group_by_interval(states, granurality=3600)

# After (v3.x)
group_by_interval(states, granularity=3600)

What Stays the Same

✅ The integration API is unchanged
async_update_historical() works the same
async_calculate_statistic_data() works the same
get_statistic_metadata() works the same
✅ Energy dashboard integration works the same

What's Removed (probably not relevant to you)

  • All internal state writing methods
  • Direct database manipulation utilities
  • statistic_id property (uses entity_id now)
  • patches.py module

Helper Functions

group_by_interval

Groups historical states into time intervals (typically hourly) for statistics calculation:

from homeassistant_historical_sensor import group_by_interval

for block_timestamp, states_in_hour in group_by_interval(
    hist_states, 
    granularity=60 * 60  # 1 hour in seconds
):
    states = list(states_in_hour)
    # Calculate statistics for this hour
    ...

Importing CSV files

To be implemented: https://github.com/ldotlopez/ha-historical-sensor/issues/3

Licenses

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

homeassistant_historical_sensor-3.0.0a4.tar.gz (24.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

File details

Details for the file homeassistant_historical_sensor-3.0.0a4.tar.gz.

File metadata

File hashes

Hashes for homeassistant_historical_sensor-3.0.0a4.tar.gz
Algorithm Hash digest
SHA256 ff1ddd94ea1c80af2240b8ae8946160cf56b709e67b0516fdfecff088f106432
MD5 8c176151b9891313195351ae40c7c2ee
BLAKE2b-256 f15a1dc9ffa0e1d22f1c732e0ace619088c9083431492d073cb49731405f5c36

See more details on using hashes here.

Provenance

The following attestation bundles were made for homeassistant_historical_sensor-3.0.0a4.tar.gz:

Publisher: publish.yml on ldotlopez/ha-historical-sensor

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file homeassistant_historical_sensor-3.0.0a4-py3-none-any.whl.

File metadata

File hashes

Hashes for homeassistant_historical_sensor-3.0.0a4-py3-none-any.whl
Algorithm Hash digest
SHA256 801b61eb45e7213a2d7ca48557ebdae7bb6e5fa1862b27007a49c4546fec5049
MD5 e5d15b91b7455659cc89531fe8f749b0
BLAKE2b-256 92d95e15fc2582bd4d7f02b048d1edc18d64bf2da1f820e1a17330fae6f2524e

See more details on using hashes here.

Provenance

The following attestation bundles were made for homeassistant_historical_sensor-3.0.0a4-py3-none-any.whl:

Publisher: publish.yml on ldotlopez/ha-historical-sensor

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page