[GUIDE] Monitoring energy by device category and running averages

I wanted to give my feedback here, maybe it helps someone.

I experimented with the sensors and code described in this thread and developed a strategy to monitor my consumption and generation.

Before that I had several entities for each consumption/generation, a “forever” meter, a “since date x” meter (which has to be the same date for all), a “plan value” and a “calculated yearly value”.
I needed the because only with a defined (and same) start date for each meter I could calculate the consumption for the “rest if the house” (consumption minus all measured devices)
It was all possible in the UI but had several flaws, at the beginning of a period the calculated value is inaccurate, especially there are significant changes in consumption during seasons, e.g. as for heat pumps.

What I did now is I made a SQL sensor for rolling yearly consumption and one for 30 day average. With the help of the base code of this thread and ChatGPT I have a result that seems to work and is quite satisfying for my needs.

  • I can monitor the change in the last days or weeks and it makes sense as a yearly rolling window is not affected by seasonal changes in consumptions
  • I can start with all history that I have as the sensor checks for the older values and if these are less then a year old it takes the oldest ones and considers that in the calculations
  • I can check in the attributes from when the first value is

Here is an example how it looks like:

“Haus Rest” is an example where the data only started at creation of the sensor, so of course it changes significantly but should get closer and closer to a value where it makes sense; the heat pump is an example where I have almost a whole year of data.

Here is the example code:

sql:
  - name: Verbrauch Strom gesamt Jahr rollierend
    unique_id: verbrauch_strom_gesamt_jahr_rollierend
    unit_of_measurement: kWh
    icon: mdi:home-lightning-bolt
    device_class: energy
    state_class: total
    query: >
      SELECT
        CASE
          WHEN fallback_365 IS NOT NULL THEN current_value - fallback_365
          ELSE (current_value - fallback_fixed) * (365.0 / ((strftime('%s','now') - fallback_fixed_ts) / 86400.0))
        END AS value,
        datetime(COALESCE(fallback_365_ts, fallback_fixed_ts), 'unixepoch', 'localtime') AS reference_timestamp,
        ((strftime('%s','now') - COALESCE(fallback_365_ts, fallback_fixed_ts)) / 86400.0) AS days_since_reference
      FROM (
        SELECT
          (SELECT s.Sum
           FROM statistics s
           INNER JOIN statistics_meta m ON s.metadata_id = m.id
           WHERE m.statistic_id = 'sensor.verbrauch_strom_gesamt'
           ORDER BY s.start_ts DESC
           LIMIT 1) AS current_value,
          (SELECT s.Sum
           FROM statistics s
           INNER JOIN statistics_meta m ON s.metadata_id = m.id
           WHERE m.statistic_id = 'sensor.verbrauch_strom_gesamt'
             AND s.start_ts <= strftime('%s','now','-365 days')
           ORDER BY s.start_ts DESC
           LIMIT 1) AS fallback_365,
          (SELECT s.start_ts
           FROM statistics s
           INNER JOIN statistics_meta m ON s.metadata_id = m.id
           WHERE m.statistic_id = 'sensor.verbrauch_strom_gesamt'
             AND s.start_ts <= strftime('%s','now','-365 days')
           ORDER BY s.start_ts DESC
           LIMIT 1) AS fallback_365_ts,
          (SELECT s.Sum
           FROM statistics s
           INNER JOIN statistics_meta m ON s.metadata_id = m.id
           WHERE m.statistic_id = 'sensor.verbrauch_strom_gesamt'
           ORDER BY s.start_ts ASC
           LIMIT 1) AS fallback_fixed,
          (SELECT s.start_ts
           FROM statistics s
           INNER JOIN statistics_meta m ON s.metadata_id = m.id
           WHERE m.statistic_id = 'sensor.verbrauch_strom_gesamt'
           ORDER BY s.start_ts ASC
           LIMIT 1) AS fallback_fixed_ts
      ) sub;
    column: value
    value_template: "{{ value | round(2) }}"

  - name: Verbrauch Strom gesamt 30 Tage Durchschnitt
    unique_id: verbrauch_strom_schnitt_30_tage
    unit_of_measurement: kWh
    device_class: energy
    state_class: total
    icon: mdi:transmission-tower
    query: >
      SELECT 
        (SELECT statistics.Sum 
         FROM statistics 
         INNER JOIN statistics_meta ON statistics.metadata_id = statistics_meta.id 
         WHERE statistics_meta.statistic_id = 'sensor.verbrauch_strom_gesamt' 
         ORDER BY statistics.start_ts DESC 
         LIMIT 1)
        -
        (SELECT statistics.Sum 
         FROM statistics 
         INNER JOIN statistics_meta ON statistics.metadata_id = statistics_meta.id 
         WHERE statistics_meta.statistic_id = 'sensor.verbrauch_strom_gesamt'
           AND statistics.start_ts > UNIXEPOCH("now", "-30 days", "-1 hour")  
         LIMIT 1)
      AS change
    column: change
    value_template: "{{ (value / 30) | round(2) }}"

Appreciate your feedback.