🏠

Home Assistantのtotal_increasingセンサーに一瞬の異常値が入り数千kWh加算された
July 27, 2026August 01, 2026
#Home Assistant#Develop

Home Assistant の Recorder を PostgreSQL へ変更し、Energy Dashboard の統計をほぼ正常な状態まで戻した。しかしその後、買電と売電にまた数千 kWh 単位の異常値が入った。

前回の復旧作業:

Home Assistant Recorderの壊れたSQLiteを修復してPostgreSQLへ移行した

RecorderのSQLite破損をREINDEXで修復し、pgloaderでPostgreSQLへ移行して障害中の統計をマージした記録

sakakinox.net

Home Assistant Recorderの壊れたSQLiteを修復してPostgreSQLへ移行した

今回はstatisticsstatistics_short_termだけでなく、集計前のstatesまで遡った。その結果、買電と売電の元センサーがほぼ同時に一度だけ急減し、約 30 秒後に正常値へ戻っていたことを確認できた。

買電: 5119.555 → 1370.486 → 5119.573
売電: 3770.158 →  992.608 → 3770.158

この急減がtotal_increasingの新しいメーター周期として扱われ、正常値へ戻った際に巨大な増分がsumへ加算されたと考えられる。

今回はstatisticsだけでなく集計前のstatesまで遡り、異常が加算された時刻と元センサーの値を確認した。補正 SQL はまだ実行していない案なので、流用する場合は必ずバックアップを取得し、自分の環境のテーブル定義と対象行を確認してほしい。

環境

  • インストール方法: Home Assistant Core
  • Core: 2026.6.1
  • フロントエンド: 20260527.4
  • Recorder DB: PostgreSQL
  • タイムゾーン: Asia/Tokyo
  • SPW277-LP から ECHONET Lite 経由で電力量を取得
  • 対象: Energy Dashboard

今回確認した主なテーブルは次のとおり。

  • states: Recorder が保存したエンティティの状態
  • states_meta: エンティティ ID のメタデータ
  • statistics_short_term: 5 分単位の短期統計
  • statistics: 1 時間単位の長期統計
  • statistics_meta: 統計 ID と内部 ID の対応
  • statistics_runs: 統計処理の実行履歴

epoch で保存されている時刻は、次の式で JST へ変換した。

to_timestamp(start_ts) AT TIME ZONE 'Asia/Tokyo'

調査対象のセンサーを特定する

Energy Dashboard で使っている主なセンサーは次の 3 つだった。

発電
sensor.auto_discovery_measured_cumulative_amount_of_electric_energy_generated

買電
sensor.auto_discovery_measured_cumulative_amount_of_electric_energy_normal_direction

売電
sensor.auto_discovery_measured_cumulative_amount_of_electric_energy_reverse_direction

statistics_metaから内部で使われるmetadata_idを確認する。

SELECT statistic_id, id
FROM statistics_meta
WHERE statistic_id IN (
  'sensor.auto_discovery_measured_cumulative_amount_of_electric_energy_generated',
  'sensor.auto_discovery_measured_cumulative_amount_of_electric_energy_normal_direction',
  'sensor.auto_discovery_measured_cumulative_amount_of_electric_energy_reverse_direction'
);

結果は次のとおりだった。

対象metadata_id
売電139
買電140
発電159

以降の SQL ではこの ID を利用した。ただし、metadata_idは環境固有なので、別環境で同じ値をそのまま使ってはいけない。

数千 kWh の異常値が再発した

しばらく正常に動いていたが、買電と売電に再び数千 kWh 級の異常値が入った。

買電と売電に数千 kWh 級の巨大な正負の棒が再発した Energy Dashboard

statistics_short_termを広めの時間範囲で確認すると、2 時 30 分を境にsumだけが急増していた。

買電
02:25 state=5119.555 sum=358.381
02:30 state=5119.688 sum=5478.069

売電
02:25 state=3770.158 sum=51.557
02:30 state=3770.158 sum=3821.715

増加量はそれぞれ、その時点のstateと一致している。

358.381 + 5119.688 = 5478.069
 51.557 + 3770.158 = 3821.715

statisticsにも同じジャンプが反映されていた。

買電
01:00 sum=357.820
02:00 sum=5478.594

売電
01:00 sum=51.557
02:00 sum=3821.715

なお、異常値を探す SQL で期間を先に絞ってからLAG()を使うと、検索範囲の先頭行には直前値がなく、正常な値まで巨大差分に見えることがある。LAG()を計算する範囲には調査開始時刻より前の行も含める必要がある。

元の states に異常値がないか確認する

集計処理だけが壊れたのか、センサーから異常値が渡されたのかを切り分けるため、statesstates_metaを確認した。

SELECT
  sm.entity_id,
  to_timestamp(s.last_updated_ts) AT TIME ZONE 'Asia/Tokyo' AS time,
  s.state
FROM states s
JOIN states_meta sm
  ON sm.metadata_id = s.metadata_id
WHERE sm.entity_id IN (
  'sensor.auto_discovery_measured_cumulative_amount_of_electric_energy_normal_direction',
  'sensor.auto_discovery_measured_cumulative_amount_of_electric_energy_reverse_direction'
)
  AND s.last_updated_ts >= EXTRACT(
    EPOCH FROM TIMESTAMPTZ '2026-07-22 02:20:00+09'
  )
  AND s.last_updated_ts < EXTRACT(
    EPOCH FROM TIMESTAMPTZ '2026-07-22 02:40:00+09'
  )
ORDER BY s.last_updated_ts;

ここで決定的なデータが見つかった。

買電
02:29:38.087152  5119.555
02:30:08.488914  1370.486
02:30:38.786682  5119.573

売電
02:30:08.488766   992.608
02:30:38.786536  3770.158

買電と売電がほぼ同時に一度だけ低い値となり、約 30 秒後には元へ戻っている。

Home Assistant のtotal_increasingは、値の減少を新しいメーター周期の開始やメーター交換として扱う。今回も急減がリセット相当と判断され、その直後に正常な累積値へ戻ったことで、買電の5119.688kWhと売電の3770.158kWhが新しい増分としてsumへ入ったと考えると、実際の統計値と一致する。

これにより、今回の直接原因は Energy Dashboard の表示キャッシュやstatisticsだけの破損ではなく、Recorder へ渡る前のセンサー値に一瞬だけ異常があったことまで確認できた。

買電と売電が同時刻に異常になっているため、SPW277-LP または ECHONET Lite 連携の共通処理が疑わしい。ただし、異常値だった1370.486992.608の由来は分からず、応答の取り違え、別プロパティの参照、係数や桁の問題などは候補にすぎない。根本原因は未解決である。

statistics の補正案

調査時点では、異常加算された値を以後のsumから引く方針にした。

この SQL は補正案であり、実行後の結果は確認できていない。Home Assistant の停止、PostgreSQL のバックアップ、更新対象行の事前確認を行ったうえで、自分の環境に合わせて調整する必要がある。

まず更新対象と補正後の値をSELECTで確認する。

SELECT
  'statistics_short_term' AS source,
  metadata_id,
  to_timestamp(start_ts) AT TIME ZONE 'Asia/Tokyo' AS time,
  sum AS before_sum,
  sum - CASE metadata_id
    WHEN 140 THEN 5119.688
    WHEN 139 THEN 3770.158
  END AS after_sum
FROM statistics_short_term
WHERE metadata_id IN (139, 140)
  AND start_ts >= EXTRACT(
    EPOCH FROM TIMESTAMPTZ '2026-07-22 02:30:00+09'
  )

UNION ALL

SELECT
  'statistics' AS source,
  metadata_id,
  to_timestamp(start_ts) AT TIME ZONE 'Asia/Tokyo' AS time,
  sum AS before_sum,
  sum - CASE metadata_id
    WHEN 140 THEN 5119.688
    WHEN 139 THEN 3770.158
  END AS after_sum
FROM statistics
WHERE metadata_id IN (139, 140)
  AND start_ts >= EXTRACT(
    EPOCH FROM TIMESTAMPTZ '2026-07-22 02:00:00+09'
  )
ORDER BY source, metadata_id, time;

対象が正しいことを確認できた場合の更新案は次のとおり。

BEGIN;

UPDATE statistics_short_term
SET sum = sum - 5119.688
WHERE metadata_id = 140
  AND start_ts >= EXTRACT(
    EPOCH FROM TIMESTAMPTZ '2026-07-22 02:30:00+09'
  );

UPDATE statistics_short_term
SET sum = sum - 3770.158
WHERE metadata_id = 139
  AND start_ts >= EXTRACT(
    EPOCH FROM TIMESTAMPTZ '2026-07-22 02:30:00+09'
  );

UPDATE statistics
SET sum = sum - 5119.688
WHERE metadata_id = 140
  AND start_ts >= EXTRACT(
    EPOCH FROM TIMESTAMPTZ '2026-07-22 02:00:00+09'
  );

UPDATE statistics
SET sum = sum - 3770.158
WHERE metadata_id = 139
  AND start_ts >= EXTRACT(
    EPOCH FROM TIMESTAMPTZ '2026-07-22 02:00:00+09'
  );

COMMIT;

途中で件数や値に問題があれば、COMMITせずに次を実行する。

ROLLBACK;

補正後に期待していた長期統計は次の値だった。

買電
01:00 357.820
02:00 358.906
03:00 360.097
04:00 360.951

売電
01:00 51.557
02:00 51.557
03:00 51.557
04:00 51.557

ただし、これは計算上の期待値であり、確認済みの実行結果ではない。

再発防止について

統計を補正しても、元センサーが同じ異常値を返せば再発する。ただし、確認できたのは一度だけであり、正当なメーターリセットを誤って除外する危険もあるため、現時点ではフィルターを実装せず様子を見ることにした。

同じ問題が再発した場合は、次の対策を検討する。

  • 異常発生時刻の前後に記録された Home Assistant と ECHONET Lite 連携のログを確認する
  • 1370.486992.608が別 EPC や別インスタンスの値と一致しないか調べる
  • 1 回だけの大幅な急減を Recorder へ渡さないフィルターを設ける
  • 複数回連続して同じ傾向を確認してから累積値を採用する
  • 連携側で ECHONET Lite の要求と応答の対応付けを確認する

ただし、正当なメーターリセットまで除外すると別の不整合を生む。単純な上限・下限だけではなく、直前値との差、連続回数、センサーのリセット仕様を含めて判断した方がよい。

調べて分かったこと

statisticsだけを見ていたときは集計処理の問題かと思っていたが、statesまで戻ると、買電と売電の元センサーがほぼ同時に一度だけ急減していた。約 30 秒後に累積値が元へ戻り、その値が巨大な増分として加算されたと考えると実際の統計と一致する。

SPW277-LP または ECHONET Lite 連携のどこで1370.486992.608が生まれたかは分からない。正当なメーターリセットまで除外したくないので、今はフィルターを入れず、再発したら要求と応答の対応まで追うことにした。

参考

おしまい



Home Assistant Recorderの壊れたSQLiteを修復してPostgreSQLへ移行した
July 27, 2026August 08, 2026

RecorderのSQLite破損をREINDEXで修復し、pgloaderでPostgreSQLへ移行して障害中の統計をマージした記録

Continue reading...
sakakinox

Written by sakakinox
Server enginier

Copyright © sakakinox.net 2021-2026.