Skip to content

Feat: dynamic soc bounds defaults#2267

Open
BelhsanHmida wants to merge 8 commits into
feat/retire-fallback-schedulerfrom
feat/dynamic-soc-bounds-defaults
Open

Feat: dynamic soc bounds defaults#2267
BelhsanHmida wants to merge 8 commits into
feat/retire-fallback-schedulerfrom
feat/dynamic-soc-bounds-defaults

Conversation

@BelhsanHmida

Copy link
Copy Markdown
Contributor

Description

  • Make soc-min and soc-max the canonical fields for fixed and dynamic storage SoC boundaries.
  • Allow dynamic soc-min / soc-max values through sensor references and time-series specs.
  • Add a generic default field to sensor references, so missing sensor values can be filled, e.g. {"sensor": 300, "default": "10 kWh"}.
  • Keep soc-minima and soc-maxima supported as legacy aliases for dynamic soc-min and soc-max, while marking them deprecated in docs/OpenAPI metadata.
  • Reject ambiguous payloads that define both dynamic soc-min and soc-minima, or both dynamic soc-max and soc-maxima.
  • Preserve backwards compatibility for fixed soc-min / soc-max, including existing fixed soc-min plus legacy soc-minima usage.
  • Update API examples, scheduling docs, UI schema text, and regenerated OpenAPI specs.
  • Add changelog entry

Look & Feel

N/A

Example API flex-model shape:

{
  "soc-at-start": "12 kWh",
  "soc-min": {
    "sensor": 300,
    "default": "10 kWh"
  },
  "soc-max": {
    "sensor": 301,
    "default": "25 kWh"
  },
  "power-capacity": "5 kW"
}

How to test

  • pytest:
uv run pytest \
  flexmeasures/data/schemas/tests/test_sensor.py \
  flexmeasures/data/schemas/tests/test_scheduling.py \
  flexmeasures/data/models/planning/tests/test_utils_fresh_db.py \
  flexmeasures/data/models/planning/tests/test_solver.py \
  • Manual API-style check:
    Use a storage flex-model where soc-min and soc-max are dynamic sensor references with defaults:
{
  "flex-model": {
    "soc-at-start": "12 kWh",
    "soc-min": {
      "sensor": 300,
      "default": "10 kWh"
    },
    "soc-max": {
      "sensor": 301,
      "default": "25 kWh"
    },
    "power-capacity": "5 kW"
  }
}

Expected behavior: soc-min and soc-max are treated as dynamic SoC boundaries, and missing sensor values are filled with the provided default values.

Further Improvements

  • Decide whether to add runtime deprecation warnings for soc-minima / soc-maxima.
  • Handle recurring SoC limits separately in Recurring SoC limits #2255.

Related Items


Sign-off

  • I agree to contribute to the project under Apache 2 License.
  • To the best of my knowledge, the proposed patch is not based on code under GPL or other license that is incompatible with FlexMeasures

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
@BelhsanHmida BelhsanHmida self-assigned this Jul 6, 2026
@BelhsanHmida BelhsanHmida changed the base branch from main to feat/retire-fallback-scheduler July 6, 2026 01:18
@BelhsanHmida BelhsanHmida requested a review from Copilot July 6, 2026 07:38

Copilot AI 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.

Pull request overview

This PR updates FlexMeasures’ storage flex-model schema to make soc-min / soc-max the canonical fields for both fixed and dynamic SoC boundaries, adds a default fallback to sensor references for filling missing values, and keeps soc-minima / soc-maxima as deprecated legacy aliases (including OpenAPI + docs updates).

Changes:

  • Extend VariableQuantityField / SensorReference to support a default fallback quantity and apply it when fetching belief series
  • Route dynamic soc-min / soc-max payloads to the internal dynamic-boundary handling while rejecting ambiguous combinations with legacy aliases
  • Update tests, docs, and regenerated OpenAPI specs/examples to reflect the new canonical behavior and deprecations

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
flexmeasures/ui/static/openapi-specs.json Regenerated OpenAPI specs/examples for canonical soc-min / soc-max, default fallback, and deprecated aliases
flexmeasures/data/schemas/tests/test_sensor.py Add tests for deserializing/serializing sensor references with default
flexmeasures/data/schemas/tests/test_scheduling.py Add schema tests for soc-min / soc-max dynamic sensor refs with default, plus mutual exclusivity cases
flexmeasures/data/schemas/sensors.py Implement default handling in VariableQuantityField + SensorReference and update time series schema examples
flexmeasures/data/schemas/scheduling/storage.py Switch soc_min / soc_max to VariableQuantityField, deprecate legacy metadata, and map dynamic canonical fields to legacy dynamic keys post-load
flexmeasures/data/schemas/scheduling/metadata.py Update field descriptions/examples to document canonical dynamic behavior and mark legacy aliases deprecated
flexmeasures/data/schemas/scheduling/init.py Update UI schema text for SoC boundaries and legacy alias labeling
flexmeasures/data/models/planning/utils.py Apply SensorReference.default to fill missing values in queried belief series
flexmeasures/data/models/planning/tests/test_utils_fresh_db.py Add integration test ensuring default fills missing belief slots
flexmeasures/data/models/planning/tests/test_solver.py Extend solver tests to cover canonical dynamic soc-min / soc-max and time-series cases
flexmeasures/data/models/planning/storage.py Update internal comment to reflect new deserialization routing for dynamic soc-max
flexmeasures/api/v3_0/sensors.py Update API example payload to use canonical soc-min sensor reference with default
flexmeasures/api/v3_0/assets.py Update API example payload to use canonical soc-min for time-series specs
documentation/features/scheduling.rst Update scheduling docs to describe dynamic soc-min / soc-max relaxation behavior and legacy aliases
documentation/api/introduction.rst Update API introduction note on default relaxation behavior for dynamic SoC boundaries

Comment on lines +443 to +446
elif isinstance(value, tuple):
try:
return ur.Quantity.from_tuple(value).to(self.to_unit)
except Exception:
Comment on lines +455 to +457
raise FMValidationError(
f"Unsupported value type. `{type(value)}` was provided but only dict, list and str are supported."
)
Comment on lines 431 to 433
def _deserialize(
self, value: dict[str, int] | list[dict] | str, attr, data, **kwargs
) -> Sensor | list[dict] | ur.Quantity:
Comment on lines +1066 to +1072
default = fields.String(
load_default=None,
metadata=dict(
description="Fallback quantity to use when the referenced sensor has missing values.",
example="0 kWh",
),
)
Comment on lines +281 to +285
self.soc_min = VariableQuantityField(
to_unit="MWh",
default_src_unit=default_soc_unit,
timezone=self.timezone,
event_resolution=self.flooring_resolution,
Comment on lines 126 to 129
FlexMeasures' built-in storage scheduler no longer computes a fallback schedule for infeasible problems.
Instead, ``soc-minima`` and ``soc-maxima`` are relaxed by default through ``"relax-soc-constraints": true``, while ``soc-min``, ``soc-max`` and ``soc-targets`` remain hard constraints.
Instead, dynamic ``soc-min`` and ``soc-max`` boundaries, including the legacy aliases ``soc-minima`` and ``soc-maxima``, are relaxed by default through ``"relax-soc-constraints": true``.
Fixed ``soc-min`` / ``soc-max`` values and exact ``soc-targets`` remain hard constraints.
If hard constraints cannot be satisfied, the scheduling job fails and clients receive the failure reason when requesting the schedule.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make soc-minima and soc-maxima the default, simplifying usage

2 participants