Skip to content

Improve the HEMS tutorial for production use, asynchronous ingestion, cleanup, and interrupted-run recovery. - #222

Merged
nhoening merged 22 commits into
mainfrom
feat/hems-script-improvements
Aug 20, 2026
Merged

Improve the HEMS tutorial for production use, asynchronous ingestion, cleanup, and interrupted-run recovery.#222
nhoening merged 22 commits into
mainfrom
feat/hems-script-improvements

Conversation

@nhoening

@nhoening nhoening commented Aug 14, 2026

Copy link
Copy Markdown
Member

Improve the HEMS tutorial for production use, asynchronous ingestion, cleanup, and interrupted-run recovery.

  • Recommend an account-admin HEMS user instead of a global administrator.
  • Keep price and weather assets inside the configured account.
  • Add HTTPS configuration support.
  • Add data-only cleanup that preserves asset and sensor IDs.
  • Add a new function to delete sensor data
  • Track completed tutorial phases on the community asset.
  • Support recreate, wipe-data, and resume workflows.
  • Fix: the upload function now returns results
  • Fix: Wait for asynchronous ingestion before forecasting, scheduling, and reporting. Supporting FlexMeasures <=0.33 job-status (non-202) behavior, as well.
  • Stop on forecast and report failures instead of continuing with incomplete data.
  • Improve Docker Compose and report-CLI documentation.

Production issues addressed

  • Forecasts no longer start before uploaded training data has been ingested.
  • Simulation reporters no longer read measurements while ingestion is pending.
  • Interrupted runs can resume without repeating completed phases.
  • A data wipe removes uploads, forecasts, schedules, measurements, and report outputs while retaining the asset structure and IDs.
  • Legacy setups without phase markers cannot be resumed ambiguously.

Closes https://github.com/SeitaBV/ems/issues/249

Verification

  • Tested against a live FlexMeasures 0.33 server.
  • 173 non-S2 tests pass.
  • Formatting, linting, compilation, and diff checks pass.

Remaining limitation

Report generation still requires a FlexMeasures CLI connected to the server database. It should be separated from the API-driven setup until reporting APIs are available.

…be admin: account-admin suffices - improve docs and function names as all assets are in account

Signed-off-by: Nicolas Höning <nicolas@seita.nl>
… on circumventing rate limiting as well

Signed-off-by: Nicolas Höning <nicolas@seita.nl>
Signed-off-by: Nicolas Höning <nicolas@seita.nl>
Signed-off-by: Nicolas Höning <nicolas@seita.nl>
… tests

Signed-off-by: Nicolas Höning <nicolas@seita.nl>
…not the strucure

Signed-off-by: Nicolas Höning <nicolas@seita.nl>
@nhoening
nhoening requested a review from BelhsanHmida August 14, 2026 10:53
Signed-off-by: Nicolas Höning <nicolas@seita.nl>
@coveralls

coveralls commented Aug 14, 2026

Copy link
Copy Markdown

Coverage Report for CI Build 32385414968

Coverage increased (+0.08%) to 96.658%

Details

  • Coverage increased (+0.08%) from the base build.
  • Patch coverage: 21 of 21 lines across 1 file are fully covered (100%).
  • No coverage regressions found.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 748
Covered Lines: 723
Line Coverage: 96.66%
Coverage Strength: 9.67 hits per line

💛 - Coveralls

@nhoening nhoening self-assigned this Aug 14, 2026
nhoening and others added 7 commits August 14, 2026 20:35
Signed-off-by: Nicolas Höning <nicolas@seita.nl>
…; add some helpful prints in the startup

Signed-off-by: Nicolas Höning <nicolas@seita.nl>
Signed-off-by: Nicolas Höning <nicolas@seita.nl>
… in graph

Signed-off-by: Nicolas Höning <nicolas@seita.nl>
HEMS cleanup relies on depth zero to select only top-level assets, but the client discarded that value as falsy. This could broaden cleanup queries and make nested name collisions unsafe.

Preserve zero-valued asset query parameters and expose the server's source and event-time filters for sensor data deletion. Add regression coverage for both request payloads.

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Interrupted asset creation, partial data wipes, and legacy site names could leave users with unsafe or destructive recovery paths. Global name lookups could also select assets outside the intended community or account.

Make structure repair idempotent, preserve existing IDs, and offer explicit keep, rename, recreate, continue-wipe, and exit choices where applicable. Validate stored workflow state, scope asset and sensor resolution, retain canonical ingestion jobs, and document the recovery behavior.

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
FlexMeasures 0.33 returns ingestion IDs under job_id and expands asset and sensor queries to include roots or descendants. The HEMS recovery flow treated these valid responses as missing or ambiguous, preventing clean runs and incomplete-structure repair.

Accept both job field names, deduplicate repeated roots by ID, and constrain sensor matches to exact owners while retaining genuine ambiguity checks. Align deletion confirmation and recovery documentation, remove the obsolete global lookup helper, and add regression coverage.

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

@BelhsanHmida BelhsanHmida left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I completed a final review. looks good to me now. i pushed some follow-ups

The follow-up fixes make cleanup respect depth=0, add filtered sensor-data deletion, provide explicit and safe recovery choices for incomplete setups and interrupted wipes, preserve existing IDs when requested, scope asset and sensor lookups correctly, and support both FlexMeasures 0.33 job_id responses and newer job responses.

I manually verified the complete workflow on FlexMeasures 0.33, including resume, wipe recovery, incomplete-structure repair, legacy-name choices, scoped lookup, recreation cancellation, and cleanup. The full automated suite also passes: 220 tests, Black, Flake8, compilation, and git diff --check.

I found no remaining blockers. From my review, the PR is ready.

Building A asset graph:

Image

BelhsanHmida and others added 8 commits August 18, 2026 01:49
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
The pre-commit workflow reordered the HEMS workflow test imports, causing CI to fail because the generated formatting diff was not committed.

Apply the deterministic import order so the repository remains unchanged when the full pre-commit suite runs.

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
…olar by delivered PV instead of available PV, so curtailed energy no longer incorrectly lowers the KPI. Feed-in and curtailment are also reported separately.

Signed-off-by: Nicolas Höning <nicolas@seita.nl>
…es/flexmeasures-client into feat/hems-script-improvements
Signed-off-by: Nicolas Höning <nicolas@seita.nl>
WORKFLOW_VERSION stayed at 1 while the PV commits changed the asset
structure: they added the solar-feed-in and solar-curtailment sensors,
switched the site flex-context to inflexible-consumption/production, and
added dashboard panels. get_workflow_state() accepts any marker whose
version equals WORKFLOW_VERSION, so a setup created before those commits
still validated as current.

That left every existing setup unusable. Asset setup only runs from the
create, recreate and untracked-repair paths; resume and wipe both skip
it, so the new sensors were never created. Report generation then looks
them up unconditionally and find_sensor_by_name_and_asset() raises rather
than skipping, so create_reports() failed with

    LookupError: Sensor 'solar-feed-in' not found in asset 'PV 1'

which propagates out of main(). Every rerun hit the same wall. The wipe
path was worst: it reset the phase markers, re-ran the whole scheduling
simulation, and only then failed. The sole escape was recreation, which
deletes every asset, sensor, ID and all time-series data.

Bump WORKFLOW_VERSION to 2 and accept any marker at or below it, so an
older setup is recognised as upgradable rather than current. After the
existing prompts have been resolved, run the idempotent asset setup again
and re-record the marker.

Ordering matters: the upgrade runs last, so an interrupted wipe is still
recovered through its own prompt first, and a recreation has already
rebuilt the structure at the current version.

The upgrade is deliberately cheap. Asset and sensor IDs are preserved
because get_or_create_* reuse whatever exists. Sensor IDs are re-collected
from the server afterwards, so a later wipe also covers sensors the
upgrade added. The recorded site names and the status are kept, so an
interrupted wipe stays recoverable. Only report generation is re-run,
since the reports write the sensors an upgrade tends to add, while the
uploaded data, forecasts and schedules stay valid.

Markers from a newer version are still rejected, since this script cannot
know what they describe.

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
docs/HEMS.rst stated two different requirements. The environment section
said the example requires FlexMeasures 1.0 or newer, while the setup
steps below still said 0.33.0 or newer was enough for the data-preserving
wipe.

1.0 is the requirement that matches the code. HEMS_setup.py gates on
"1.0.0.dev0", and the floor is substantive rather than cosmetic: the site
flex-context is written with inflexible-consumption and
inflexible-production, which only exist from the 1.0 series. A reader who
followed the 0.33 line would set up a server that rejects the
flex-context on the first schedule.

Remove the stale 0.33 bullet. The 1.0 statement already sits above, next
to the install instructions, and the rate-limiting note further down
also refers to v1.0.

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
const.py was changed to default to toy-user@flexmeasures.io /
toy-password, the account created by `flexmeasures add toy-account`.
The setup instructions were not changed with it: docs/HEMS.rst and the
NOTE comment in HEMS_setup.py still told the reader to create an account
named "HEMS tutorial" with a hems-admin@example.com user.

Following those instructions produced a server with an account the
script never tries to log into. The script then failed at startup with
"User with email 'hems-admin@example.com' does not exist", and nothing
pointed at the shipped defaults as the cause.

Align the instructions with the code rather than the other way around.
The toy account is a single command instead of three, and it already
grants the account-admin role the tutorial needs, so the quick path is
now the documented one and needs no edit to const.py.

Keep the custom-account route for readers who want their own account,
now stated as the alternative it has become, and say explicitly that
const.py has to be updated to match in that case.

Also mention that the toy account brings its own demo assets
(toy-building and its children). The tutorial neither uses nor deletes
them: delete_hems_assets() only removes assets it knows by name, and
collect_hems_structure_ids() only walks the community, market and
weather-station trees.

Verified by running the tutorial end to end against a toy account.

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

@BelhsanHmida BelhsanHmida left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Verified the five commits statically and with a full tutorial run against FM 1.0.0rc5.

The 0.25 energy-cost factor checks out arithmetically on live data (17.007 kW × 0.09717 EUR/kWh × 0.25 = 0.41314, matching the reported value exactly). The EV soc-usage restructuring is accepted by the FM 1.0 scheduler and correctly models both commute legs. Feed-in / curtailment / self-consumption formulas are sign-consistent. Sensor creation is idempotent.

Pushed three commits: the workflow-version bump (existing setups were hitting an unrecoverable LookupError on solar-feed-in), plus two docs fixes.

@nhoening
nhoening merged commit 48b598c into main Aug 20, 2026
17 checks passed
@nhoening
nhoening deleted the feat/hems-script-improvements branch August 20, 2026 15:49
BelhsanHmida added a commit that referenced this pull request Aug 25, 2026
Resolved three conflicts, all in favour of the API-based reporting, while
keeping what #222 added on top:

- reporters.py: keep the CLI probe deleted, keep the new solar-feed-in and
  solar-curtailment outputs
- scheduling.py: keep the async run_community_aggregate, keep #222's
  return-value check and the ingestion wait before it
- HEMS.rst: worker now listens on ingestion and reporting, and the CLI
  workaround section stays deleted

#222 put the solar sensors on the PV asset while the rest of the
self-consumption outputs sit on the site, so that report can no longer
derive its asset. It now names the site, which holds both in its subtree.

Also noted that report triggers share the rate limit with schedules and
forecasts, and raised the documented server floor to 1.1.0.

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
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.

3 participants