Fix: CEM work session#188
Draft
Flix6x wants to merge 170 commits into
Draft
Conversation
…, consolidating all dependencies into pyproject.toml and a single uv.lock file. This simplifies and speeds up the development setup greatly. Changes: - Switch build backend from setuptools to hatchling - Remove setup.cfg, tox.ini, .isort.cfg and setup.py in favour of .flake8 and pyproject.toml - Add Poethepoet tasks - Upgrade main Python version (CI/CD, .python-version, etc.) to 3.12 - Deprecate Python 3.9 - Add .python-version for consistent Python version management - Create separate Dockerfile for flexmeasures-client - Replace pip-tools with uv in all CI/CD workflows - Remove ci/run_mypy.sh in favour of Poethepoet task - Update documentation Signed-off-by: Stijn van Houwelingen <teadrinkingprogrammer@github.io>
Signed-off-by: Stijn van Houwelingen <teadrinkingprogrammer@github.io>
Signed-off-by: Stijn van Houwelingen <teadrinkingprogrammer@github.io>
Signed-off-by: F.N. Claessen <claessen@seita.nl>
This reverts commit d63afe5.
…connection shuts down Signed-off-by: F.N. Claessen <claessen@seita.nl>
Signed-off-by: F.N. Claessen <claessen@seita.nl>
Signed-off-by: F.N. Claessen <claessen@seita.nl>
Signed-off-by: F.N. Claessen <claessen@seita.nl>
Signed-off-by: F.N. Claessen <claessen@seita.nl>
Signed-off-by: F.N. Claessen <claessen@seita.nl>
This reverts commit 4799585.
Signed-off-by: F.N. Claessen <claessen@seita.nl>
… is missing Signed-off-by: F.N. Claessen <claessen@seita.nl>
Signed-off-by: F.N. Claessen <claessen@seita.nl>
Signed-off-by: F.N. Claessen <claessen@seita.nl>
Signed-off-by: F.N. Claessen <claessen@seita.nl>
Signed-off-by: F.N. Claessen <claessen@seita.nl>
Signed-off-by: F.N. Claessen <claessen@seita.nl>
This reverts commit 5328de9.
Signed-off-by: F.N. Claessen <claessen@seita.nl>
…) and make system_description_id optional Signed-off-by: F.N. Claessen <claessen@seita.nl>
Signed-off-by: F.N. Claessen <claessen@seita.nl>
This reverts commit 374e44a.
Signed-off-by: F.N. Claessen <claessen@seita.nl>
Signed-off-by: F.N. Claessen <claessen@seita.nl>
Signed-off-by: F.N. Claessen <claessen@seita.nl>
…andlers accordingly Signed-off-by: F.N. Claessen <claessen@seita.nl>
Signed-off-by: F.N. Claessen <claessen@seita.nl>
Signed-off-by: F.N. Claessen <claessen@seita.nl>
Signed-off-by: F.N. Claessen <claessen@seita.nl>
…st duration"; it works after the first schedule, but I fear it may sometimes lead to a very short schedule duration; I prefer not to make this dependent on the usage forecast duration This reverts commit 10fa1556532e789c42e81f2fa26af18ade611257.
Signed-off-by: F.N. Claessen <claessen@seita.nl>
Signed-off-by: F.N. Claessen <claessen@seita.nl>
Signed-off-by: F.N. Claessen <claessen@seita.nl>
…l_id is unavailable Signed-off-by: F.N. Claessen <claessen@seita.nl>
…e slow requests Signed-off-by: F.N. Claessen <claessen@seita.nl>
…top silently swallowing exceptions in the fire-and-forget storage-status task Signed-off-by: F.N. Claessen <claessen@seita.nl>
…ity degrades gracefully
Signed-off-by: F.N. Claessen <claessen@seita.nl>
…n is not a valid queue on this branch)
…onger job timeout
…traints flag, which pushed HiGHS into 10+ minute solves
…he real solver-slowdown cause is fixed
Signed-off-by: F.N. Claessen <claessen@seita.nl>
…, so scheduling jobs run in parallel instead of serializing through a single worker
…stalling the timestep Observed a pandas 'cannot reindex on an axis with duplicate labels' error from a scheduling job during a multi-day, frequently-re-triggered (implementation_horizon_hours=3) run; re-running the exact same job manually succeeded immediately, confirming it's transient. Without a retry, trigger_schedule's fire-and-forget task just logs and drops the exception, so the RM never receives an instruction for that timestep and polls forever. Retries up to 3 times on a ValueError containing 'Scheduling job failed' before giving up for real.
The base override now runs without access to the private ems repo (needed for single-house simulations by collaborators without that repo); community runs add ../ems/docker-compose.community.yml as a third compose file.
Builds the new flex-model "operation-modes" field from the FRBC system description's operation-mode element power ranges (only when they actually restrict the range), so FlexMeasures schedules only power values the device can run at. Requires flexmeasures feat/2113-operation-mode-power-bands.
A plain disconnect (RMs reconnect at every replan boundary) previously left the producer and watchdog tasks and the CEM itself running forever; the old session lived on as a zombie able to keep posting SoC and triggering schedules for an asset the RM no longer implements.
At startup, the CEM's first trigger_schedule can beat the controller's initial battery-SoC post (a separate client writing to the flex-model's state-of-charge sensor). FlexMeasures then rejects the trigger with a 422 "No recent state-of-charge value found", and since this whole call runs as a fire-and-forget task, that single failure permanently stalled the house at its barrier. Treat it as transient alongside "Scheduling job failed" (5 attempts, 2s backoff) - it resolves itself once the SoC post lands moments later. Heavier stacks lose this race more often.
…ted time The CEM now creates a dedicated 'measured-power' sensor (kW, consumption-positive) per site, separate from the StorageScheduler 'power' schedule sensor, and maps ELECTRIC.POWER.L1 measurements to it (replacing a hardcoded fallback sensor id). Measurements are binned and posted at their own SIMULATED timestamp instead of wall-clock time, and posted directly per incoming value (the RM sends one aggregated value per interval, so the old 5-minute wall-clock buffered-averaging would have suppressed nearly every post in a co-simulation). Values are posted in Watts (S2 PowerMeasurement convention) and converted to the kW sensor by FlexMeasures.
…'t crash CEM.close() calls close() on every registered control-type handler when a websocket tears down, but only FRBCTunes implemented it - FRBCSimple (and any other handler) raised AttributeError, which killed the CEM's request handler and left it unable to serve the next RM connection (houses then hang forever waiting for a schedule). Add a default no-op close() on the ControlTypeHandler base class.
Images built from FlexMeasures' uv-based Dockerfile put a pip-less /app/.venv first on PATH while bare `pip` is the system one under /usr/local, so packages installed at container start were invisible to the runtime interpreter (ModuleNotFoundError: aiohttp) on any freshly built image - notably Samuel's Windows setups - while long-cached single-Python images kept working. Use `python3 -m pip` throughout (with an ensurepip bootstrap for pip-less venvs) and exec the server with that same python3. Also set the generic SETUPTOOLS_SCM_PRETEND_VERSION alongside the client-specific one for the git-less editable install. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LQFkeGxDwErydUV5ZmHmki
An S2 PowerRange runs from start_of_range (lower bound) to end_of_range (upper bound), but the capacity derivation introduced in 9f20ab4 (March 2026) read them the other way around: production-capacity became the smallest upper bound across operation modes (e.g. 2.5 kW for a consumption-only heat pump) and consumption-capacity the largest lower bound. The scheduler consequently discharged the heat pump's thermal storage as if it were an electric battery, and capped its consumption below the device's real maximum. Derive the overall [min, max] power range instead, with production only where ranges extend below zero. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LQFkeGxDwErydUV5ZmHmki
… realizations Belief time (defect 4b): PowerMeasurements posted by the CEM now carry a simulated prior (the binned interval's end), so realized apartment power is stamped at simulation time instead of wall-clock 2026, and the UI horizon view no longer shows data "recorded in 2026". Timezone (defect 2): naive S2 measurement timestamps are now localized as Europe/Amsterdam (was UTC), matching the community orchestrator, RM and controller which all localize the same naive sim times as Europe/Amsterdam. Live apartment realizations (defect 4a): besides the dedicated measured-power sensor, the CEM now also mirrors the realized apartment aggregate onto the apartment's flex-context "aggregate-power" sensor, resolved lazily from the asset's flex_context (it is attached by the community runner only after the CEM connects, so it appears from step 1). Realized posts stay distinguishable from the StorageScheduler schedule data on that same sensor by their own source and simulated belief time. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LQFkeGxDwErydUV5ZmHmki
The RM sends one PowerMeasurement per 15-minute interval (stamped at interval start), but the posting path binned and stamped priors with the 5-minute _minimum_measurement_period, yielding belief times 10 minutes before each event's end - an ex-ante horizon on measurements. Bin and stamp at the measured-power sensor's 15-minute event resolution instead, so each realized value is believed exactly when its interval elapses (zero horizon). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LQFkeGxDwErydUV5ZmHmki
An explicit production-capacity of 0 kW gets softened by FlexMeasures' relax-constraints defaults (100 EUR/kW device breach price), so under a tight community capacity the scheduler chose to 'produce' 1.764 kW from a heat pump rather than pay the 10000 EUR/kW site breach. Setting is_strictly_non_positive on the FRBC power sensor keeps production hard-bounded at zero regardless of relaxation settings. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LQFkeGxDwErydUV5ZmHmki
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #187.
FRBC.FillLevelTargetProfileandFRBC.UsageForecastto theFRBCSimplehandler.SimpleFRBChandler to get to the point thatFRBCInstructionsare sent back.FRBC.LeakageBehaviourto theFRBCSimplehandler.