Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
b02e111
feat: allow setting a power sensor in the flex_model of an asset when…
Flix6x May 18, 2026
db45c30
Merge remote-tracking branch 'origin/main' into feat/sensor-in-db-fle…
Flix6x May 20, 2026
3ffdaa0
fix: fields without a data_key just use the variable name as data_key
Flix6x May 20, 2026
4f5b116
feat: switch to consumption and production sensor reference fields in…
Flix6x May 20, 2026
c3f2d68
feat: add UI support for new fields
Flix6x May 20, 2026
711e228
docs: document new fields in scheduling.rst
Flix6x May 20, 2026
1fa459e
feat: add new fields to StorageFlexModelSchema
Flix6x May 20, 2026
ed640b2
chore: update openapi-specs.json
Flix6x May 20, 2026
4733868
storage: add consumption and production output sensor support
Flix6x May 20, 2026
a96edd4
tests: expand storage scheduler tests for consumption/production outp…
Flix6x May 20, 2026
e63ee43
docs: document consumption/production output sensor semantics and add…
Flix6x May 20, 2026
82c6015
style: black
Flix6x May 20, 2026
f9adee9
Merge remote-tracking branch 'refs/remotes/origin/main' into feat/sen…
Flix6x May 26, 2026
6d2b33b
Merge remote-tracking branch 'origin/main' into feat/sensor-in-db-fle…
Flix6x May 26, 2026
4b1ab4f
fix: guard sensor_d against None in StorageScheduler._prepare
saerts-gp Apr 2, 2026
5811ca8
Merge remote-tracking branch 'origin/main' into feat/sensor-in-db-fle…
Flix6x May 26, 2026
a8a3e9e
feat: resample from the resolution of the storage-efficiency sensor t…
Flix6x May 26, 2026
1546e51
docs: extend field description accordingly
Flix6x May 26, 2026
d42f65f
fix: remove obsolete validator
Flix6x May 26, 2026
9bd75ed
feat: do not allow storage-efficiency to be set without a known resol…
Flix6x May 26, 2026
d6e15b6
docs: fill in PR number
Flix6x May 26, 2026
75fa2eb
docs: API changelog entry
Flix6x May 26, 2026
9f173fa
docs: simplify main changelog entry
Flix6x May 26, 2026
1033baf
feat: add more explicit checks in test
Flix6x May 26, 2026
061389b
data/services/scheduling: fix double sign inversion for consumption/p…
Flix6x May 26, 2026
7d902c3
fix: refine sign inversion logic for consumption/production output se…
Flix6x May 26, 2026
82da372
refactor: extract sign resolution logic to utility function
Flix6x May 26, 2026
40128b7
fix: explicitly set the consumption_is_positive attribute on consumpt…
Flix6x May 26, 2026
d5521d4
Merge remote-tracking branch 'origin/main' into feat/sensor-in-db-fle…
Flix6x May 27, 2026
9e31174
feat: test fetching schedules from consumption and production sensors
Flix6x May 27, 2026
6eae5c8
fix: set_attribute is a no-op when the attribute does not exist; also…
Flix6x May 27, 2026
2cd8d25
feat: prevent mutating consumption_is_positive once it is set
Flix6x May 27, 2026
e2ccc08
data/services/scheduling: extract _set_output_sensor_consumption_is_p…
Flix6x May 27, 2026
e555ea4
api/v3_0/tests: add test for conflicting consumption_is_positive attr…
Flix6x May 27, 2026
7038e53
fix: test expectations for production sensors
Flix6x May 28, 2026
a2a2b95
docs: clarify sign convention for the get_schedule endpoint
Flix6x May 28, 2026
dfbc2a0
feat: add sign-convention query parameter to get_schedule endpoint
Flix6x May 28, 2026
f19088c
docs: document sign-convention parameter for get_schedule endpoint
Flix6x May 28, 2026
3e7b818
api/v3_0/tests: extend sign-convention tests to cover all three modes
Flix6x May 28, 2026
5eb1772
docs: touch up sign explanations
Flix6x May 28, 2026
99f5d90
docs: clarify how the scheduler records the data, mention the sign o…
Flix6x May 28, 2026
e29111c
docs: clarify confusing comments
Flix6x May 28, 2026
7e6ab51
data/models/planning/storage: pass consumption-positive values to mak…
Flix6x May 28, 2026
6905eac
data/services/scheduling: set consumption_is_positive at trigger time…
Flix6x May 28, 2026
5600f6f
api/v3_0/tests: update conflict test to expect 422 at trigger time
Flix6x May 28, 2026
36d685d
style: punctuation
Flix6x May 28, 2026
8944fd4
Merge remote-tracking branch 'origin/main' into feat/sensor-in-db-fle…
Flix6x May 29, 2026
2a7ca41
docs: clarify effect of setting consumption_is_positive
Flix6x May 29, 2026
c5f5124
fix: improve test quality
Flix6x May 29, 2026
5ea784c
docs: use past tense to discriminate between what the endpoint does a…
Flix6x May 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions documentation/api/change_log.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ v3.0-31 | 2026-05-20
- Added a unified job status endpoint ``GET /api/v3_0/jobs/<uuid>`` that returns the current execution status and a human-readable result message for any background job (scheduling, forecasting, etc.) identified by its UUID.
- Switched from ``force_new_job_creation`` to ``force-new-job-creation`` (maintaining backwards compatibility) and added the field to `/assets/(id)/schedules/trigger` (POST) endpoint, too.
- Support both snake_case and kebab-case fields in `/sensors/<id>/data` (GET), while only documenting the kebab-case ones.
- The ``consumption`` and ``production`` flex-model fields for the ``StorageScheduler`` now act as output sensors: the scheduler writes the resulting power schedule to those sensors, with unit conversion and resampling applied. When only one of the two is defined, the full power profile is written (sign-inverted for the production sensor). When both are defined, the schedule is split into its non-negative (consumption) and non-positive (production) parts.
- Added a ``sign-convention`` query parameter to ``GET /sensors/<id>/schedules/<uuid>`` with three modes: ``consumption-positive`` (default, unchanged behaviour), ``production-positive``, and ``wysiwyg`` (sign of database values and as seen in UI charts).

v3.0-30 | 2026-04-15
""""""""""""""""""""
Expand Down
7 changes: 7 additions & 0 deletions documentation/api/notation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -302,3 +302,10 @@ We'd recommend to use positive power values to indicate consumption and negative

Read more at :ref:`signs_of_power_beliefs` about our treatment of data, which includes data you send in, or you get from forecasts and schedules
(hint: you are free to define the sign for your data, but it might affect how you receive your schedules).

The ``GET /api/v3_0/sensors/<id>/schedules/<uuid>`` endpoint supports three sign conventions via the ``sign-convention`` query parameter:

- ``consumption-positive`` (**default**): schedules are returned with consumption as positive values and production as negative values, regardless of how they are stored in the database.
- ``production-positive``: schedules are returned with production as positive values and consumption as negative values.
- ``wysiwyg`` (*what-you-see-is-what-you-get*): schedules are returned with the same sign as database values and as seen in the UI charts.
The values indicate exactly what was stored, which was itself governed by the sensor's ``consumption_is_positive`` attribute (if present) or the scheduler's default convention (which stored production as positive values in the database).
2 changes: 2 additions & 0 deletions documentation/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ New features
* Improve UX after deleting a child asset through the UI [see `PR #2119 <https://www.github.com/FlexMeasures/flexmeasures/pull/2119>`_]
* Improve source filtering in the sensor data GET endpoint by exposing the documented query parameters in Swagger and allowing filtering by the account linked to data sources [see `PR #2083 <https://www.github.com/FlexMeasures/flexmeasures/pull/2083>`_ and `PR #2151 <https://www.github.com/FlexMeasures/flexmeasures/pull/2151>`_]
* Support sensor references for efficiency fields in storage flex-models [see `PR #2142 <https://www.github.com/FlexMeasures/flexmeasures/pull/2142>`_]
* Introduce the ``consumption`` and ``production`` flex-model fields for the ``StorageScheduler`` to save schedules to [see `PR #2190 <https://www.github.com/FlexMeasures/flexmeasures/pull/2190>`_]
* Added a unified job status endpoint ``GET /api/v3_0/jobs/<uuid>`` to retrieve the current execution status and result message for any background job [see `PR #2141 <https://www.github.com/FlexMeasures/flexmeasures/pull/2141>`_]
* Add ``flexmeasures jobs inspect-job`` CLI command to show job status and metadata information (similar to the job status endpoint in the API) [see `PR #2202 <https://www.github.com/FlexMeasures/flexmeasures/pull/2202>`_]
* New ``GET /api/v3_0/sources`` endpoint to list accessible data sources and defined types, with ``only_latest=true`` by default to return only the most recent version per source [see `PR #2126 <https://www.github.com/FlexMeasures/flexmeasures/pull/2126>`_]
Expand Down Expand Up @@ -141,6 +142,7 @@ Bugfixes


v0.31.3 | April 11, 2026
============================

Bugfixes
-----------
Expand Down
23 changes: 19 additions & 4 deletions documentation/concepts/data-model.rst
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ A data source can be a FlexMeasures user, but also simply a named source from ou
In FlexMeasures, data sources have a type. It is just a string which you can freely choose (we do not model them explicitly im the data model like Asset types).
We do support some types out of the box: "scheduler", "forecaster" "reporter", "demo script" and "user".

.. _beliefs:

Beliefs
---------
Expand Down Expand Up @@ -156,7 +157,8 @@ More information, including code examples, is available in :ref:`annotations`.
About signs of power & energy values
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In short: You can use any sign you want for power data.
But the scheduler in FlexMeasures needs to know how to apply the signs. Positive (+) means consumption, negative (-) means production.
What is recorded in the database is exactly as seen in UI charts.
But the scheduler in FlexMeasures needs to know how to apply the signs.
Let us explain.

When beliefs are about power or energy, the sign of the value is important. It indicates whether the asset is consuming or producing.
Expand All @@ -168,12 +170,25 @@ For example, users can create PV power data with positive values indicating prod
We allow this because we want the UI to match what is in the database, and users often desire both of these datasets to be shown as positive values.
We assume that this is what users send in.

Note that, if forecasts are created, they will have the same sign as original data.
Note that, if forecasts are created, they will have the same sign as the original data.

For schedules, the sign of resulting power data (beliefs) is being switched when data is stored (assuming consumption , and you can prevent that by setting ``sensor.attributes["consumption_is_positive"] = True``.
For schedules, the sign of the power schedule (as :ref:`beliefs <beliefs>`) recorded in the database, and as seen in UI charts, is determined as follows:

- If the flex-model contains the ``sensor`` field, and that sensor has power units (e.g. kW), the ``"consumption_is_positive"`` attribute of the sensor is used to decide the sign of the recorded data.
Comment thread
nhoening marked this conversation as resolved.
If `True`, consumption will be saved as positive, otherwise not. To clarify:
- If the attribute is not defined, **by default, scheduled power is recorded with production as positive values** (and consumption as negative values).
- To record scheduled power data with consumption as positive values, set ``sensor.attributes["consumption_is_positive"] = True``.
- To record scheduled power data with production as positive values (already the default, but this makes it explicit), set ``sensor.attributes["consumption_is_positive"] = False``.
- If the flex-model contains the ``consumption`` field, scheduled power is recorded with consumption as positive values.
The ``"consumption_is_positive"`` attribute of the referenced sensor is set automatically to ``True``.
- If the flex-model contains the ``production`` field, scheduled power is recorded with production as positive values.
The ``"consumption_is_positive"`` attribute of the referenced sensor is set automatically to ``False``.

.. note:: We will soon document better what the scheduler does in detail, and how the attribute works.
The ``GET /api/v3_0/sensors/<id>/schedules/<uuid>`` endpoint supports three sign conventions via the ``sign-convention`` query parameter:

- ``consumption-positive`` (default): schedules are always returned with consumption as positive values and production as negative values.
- ``production-positive``: schedules are returned with production as positive values and consumption as negative values.
- ``wysiwyg`` (*what-you-see-is-what-you-get*): schedules are returned with the same sign as database values and as seen in the UI charts, indicating exactly what the scheduler stored.


Accounts & Users
Expand Down
8 changes: 7 additions & 1 deletion documentation/features/scheduling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,13 @@ For more details on the possible formats for field values, see :ref:`variable_qu

* - Field
- Example value
- Description
- Description
* - ``consumption``
- |CONSUMPTION.example|
- .. include:: ../_autodoc/CONSUMPTION.rst
* - ``production``
- |PRODUCTION.example|
- .. include:: ../_autodoc/PRODUCTION.rst
* - ``state-of-charge``
- |STATE_OF_CHARGE.example|
- .. include:: ../_autodoc/STATE_OF_CHARGE.rst
Expand Down
61 changes: 54 additions & 7 deletions flexmeasures/api/v3_0/sensors.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,10 @@
)
from flexmeasures.data.schemas import AssetIdField, SourceIdField
from flexmeasures.api.common.schemas.search import SearchFilterField
from flexmeasures.data.schemas.scheduling import GetScheduleSchema
from flexmeasures.data.schemas.scheduling import (
GetScheduleSchema,
ScheduleSignConvention,
)
from flexmeasures.data.schemas.units import UnitField
from flexmeasures.data.services.sensors import get_sensor_stats
from flexmeasures.data.services.sensors import delete_sensor as delete_sensor_and_data
Expand Down Expand Up @@ -1040,6 +1043,7 @@ def get_schedule( # noqa: C901
job_id: str,
duration: timedelta,
unit: str | None = None,
sign_convention: str = ScheduleSignConvention.CONSUMPTION_POSITIVE,
**kwargs,
):
"""
Expand All @@ -1054,6 +1058,21 @@ def get_schedule( # noqa: C901

- "duration" (6 hours by default; can be increased to plan further into the future)
- "unit" (by default, the unit of the schedule is the sensor's unit; a compatible unit can be requested)
- "sign-convention" (controls how power values are signed in the response; see below)

**Sign convention**

By default (``sign-convention: consumption-positive``), the endpoint always returns schedules where
consumption is positive and production is negative, regardless of how the values are stored in the database.
This is the most common convention and matches the perspective of a consumer.

Set ``sign-convention: production-positive`` to flip the sign so that production is returned as
positive and consumption as negative. This matches the perspective of a producer.

Set ``sign-convention: wysiwyg`` (*what-you-see-is-what-you-get*) to return the values with the same sign
as database values and what is seen in UI charts. The values will indicate exactly what is stored,
which is itself determined by the sensor's ``consumption_is_positive`` attribute (if set)
or by the scheduler's default storage convention (production positive in the database).
security:
- ApiKeyAuth: []
parameters:
Expand Down Expand Up @@ -1095,6 +1114,21 @@ def get_schedule( # noqa: C901
example: kW
schema:
type: string
- in: query
name: sign-convention
required: false
description: |
Sign convention applied to power values in the response.
- ``consumption-positive`` (default): consumption is positive, production is negative.
- ``production-positive``: production is positive, consumption is negative.
- ``wysiwyg`` (*what-you-see-is-what-you-get*): sign of database values and as seen in UI charts.
example: consumption-positive
schema:
type: string
enum:
- consumption-positive
- production-positive
- wysiwyg
responses:
200:
description: PROCESSED
Expand Down Expand Up @@ -1221,12 +1255,25 @@ def get_schedule( # noqa: C901
)

sign = 1
if sensor.measures_power and not sensor.get_attribute(
"consumption_is_positive", False
):
sign = -1

# For consumption schedules, positive values denote consumption. For the db, consumption is negative unless specified explicitly
if sign_convention == ScheduleSignConvention.WYSIWYG:
# Return values without adjusting the sign of database values.
# No sign inversion: what's in the DB and what is seen in UI charts is what the caller receives.
pass
elif sensor.measures_power:
# Determine whether the database stores consumption as positive or negative.
db_consumption_is_positive = sensor.get_attribute(
"consumption_is_positive", False
)
if sign_convention == ScheduleSignConvention.CONSUMPTION_POSITIVE:
# Caller wants consumption positive. Invert if DB stores it as negative.
if not db_consumption_is_positive:
sign = -1
elif sign_convention == ScheduleSignConvention.PRODUCTION_POSITIVE:
# Caller wants production positive. Invert if DB already stores consumption positive.
if db_consumption_is_positive:
sign = -1

# Apply sign to get the values in the requested convention
consumption_schedule = sign * simplify_index(power_values)["event_value"]
if consumption_schedule.empty:
# for not in-built schedulers, we are not sure if they would store time series in the db
Expand Down
Loading
Loading