Skip to content

Fix: forecast values in daily log - #4311

Open
seaspotter wants to merge 3 commits into
openWB:masterfrom
seaspotter:fix-forecast-today-values-stale-snapshot
Open

seaspotter wants to merge 3 commits into
openWB:masterfrom
seaspotter:fix-forecast-today-values-stale-snapshot

Conversation

@seaspotter

@seaspotter seaspotter commented Nov 12, 2026 •

Copy link
Copy Markdown
Collaborator

Folge Fix zu #4270 weil die Prognosewerte im Tageslog nie befüllt wurden.

Zwei Ursachen: _forecast.py schrieb direkt in ein Objekt, das vor jedem Log-Eintrag ohnehin durch eine frische Kopie ersetzt wird - jetzt nur noch publish, wie bei den Strompreisen. Und subdata.py hat bei dict-wertigen Feldern (values/today_values/tomorrow_values/daily_kwh) die Keys des Payloads als Attributnamen interpretiert statt den ganzen Dict zu speichern.

Summary by Sourcery

Ensure forecast data is correctly published, stored, and available to the daily log.

Bug Fixes:

  • Fix forecast values and daily energy totals not being populated in the daily log.
  • Preserve forecast dictionary payloads as complete fields when processing MQTT updates.

Enhancements:

  • Align forecast state updates with the publish-based flow used by other value stores.
  • Add coverage for selecting the current forecast value and handling missing or future-only data.

Tests:

  • Update forecast store tests to validate published values and add coverage for dictionary forecast fields.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 3 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="packages/modules/common/store/_forecast.py" line_range="52" />
<code_context>
-        data.data.optional_data.data.forecast.get.tomorrow_kwh = tomorrow_kwh
+        # publish only - same as FlexibleTariffValueStore/GridFeeValueStore; a direct write here
+        # would hit a stale snapshot, not the live object forecast_get_current_value() reads.
         pub_to_broker("openWB/set/optional/forecast/get/values", values)
         pub_to_broker("openWB/set/optional/forecast/get/today_values", today_values)
         pub_to_broker("openWB/set/optional/forecast/get/tomorrow_values", tomorrow_values)
</code_context>
<issue_to_address>
**Old provider restores stale forecast**

When the provider is changed or cleared while its previous forecast fetch is still running, the old `ConfigurableForecast.update` continues after its provider is replaced and publishes its fetched state to the shared topics; `SubData` then stores those values under the new configuration, so daily logs use the old provider’s forecast until another update replaces it.

Before publishing a completed fetch, verify that its module/configuration is still current, or reject updates from superseded provider generations.
</issue_to_address>

### Comment 2
<location path="packages/modules/common/store/_forecast.py" line_range="52" />
<code_context>
-        data.data.optional_data.data.forecast.get.tomorrow_kwh = tomorrow_kwh
+        # publish only - same as FlexibleTariffValueStore/GridFeeValueStore; a direct write here
+        # would hit a stale snapshot, not the live object forecast_get_current_value() reads.
         pub_to_broker("openWB/set/optional/forecast/get/values", values)
         pub_to_broker("openWB/set/optional/forecast/get/today_values", today_values)
         pub_to_broker("openWB/set/optional/forecast/get/tomorrow_values", tomorrow_values)
</code_context>
<issue_to_address>
**Daily logs retain the previous forecast**

When a daily-log entry is created after forecast publication but before `SubData` processes the queued MQTT update, `create_entry` reads the old in-memory optional-data value because `pub_to_broker` queues the update, so the daily log records the previous forecast or `None`.

Update the live control-side forecast state before queuing the MQTT publication, and have `create_entry` read that updated state.

Also at `packages/modules/common/store/_forecast.py:53`.
</issue_to_address>

### Comment 3
<location path="packages/modules/common/store/_forecast_test.py" line_range="26" />
<code_context>
+def _published(pub: Mock, topic_suffix: str):
+    for call in pub.call_args_list:
+        topic, payload = call.args[0], call.args[1]
+        if topic.endswith(topic_suffix):
+            return payload
+    raise AssertionError(f"no publish for topic ending in {topic_suffix!r}")
</code_context>
<issue_to_address>
**Wrong broker routes still pass**

When a publish uses an incorrect topic path with the expected suffix, when the forecast is published to a wrong MQTT topic that retains the expected suffix, `_published` returns its payload at line 27, so `test_update_splits_by_current_calendar_day` and the other publishing tests pass even though the daily-log consumer receives nothing on the expected topics.

Match the exact expected topic in `_published` or assert each published topic explicitly.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant