From f78f51ec4a906827ae8d5e148528cc9de1100153 Mon Sep 17 00:00:00 2001 From: "F.N. Claessen" Date: Sun, 2 Mar 2025 19:55:33 +0100 Subject: [PATCH 01/10] docs: clarify inline comment Signed-off-by: F.N. Claessen --- flexmeasures/api/v3_0/sensors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flexmeasures/api/v3_0/sensors.py b/flexmeasures/api/v3_0/sensors.py index e7c91dd992..3fa1c789cc 100644 --- a/flexmeasures/api/v3_0/sensors.py +++ b/flexmeasures/api/v3_0/sensors.py @@ -710,7 +710,7 @@ def get_schedule( # noqa: C901 if sensor.get_attribute("consumption_is_positive", True): sign = -1 - # For consumption schedules, positive values denote consumption. For the db, consumption is negative + # For consumption schedules, positive values denote consumption. For the db, consumption is negative unless specified explicitly consumption_schedule = sign * simplify_index(power_values)["event_value"] if consumption_schedule.empty: return unknown_schedule( From 32f92c3a8c1f93807ec5780346158544a74ccbe0 Mon Sep 17 00:00:00 2001 From: "F.N. Claessen" Date: Sun, 2 Mar 2025 20:51:05 +0100 Subject: [PATCH 02/10] fix: the sign should be switched if consumption is positive, and the default should be False Signed-off-by: F.N. Claessen --- flexmeasures/api/v3_0/sensors.py | 2 +- flexmeasures/data/services/scheduling.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/flexmeasures/api/v3_0/sensors.py b/flexmeasures/api/v3_0/sensors.py index 3fa1c789cc..2aaa76609c 100644 --- a/flexmeasures/api/v3_0/sensors.py +++ b/flexmeasures/api/v3_0/sensors.py @@ -707,7 +707,7 @@ def get_schedule( # noqa: C901 ) sign = 1 - if sensor.get_attribute("consumption_is_positive", True): + if 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 diff --git a/flexmeasures/data/services/scheduling.py b/flexmeasures/data/services/scheduling.py index 5dfc59d8a0..7ea3408050 100644 --- a/flexmeasures/data/services/scheduling.py +++ b/flexmeasures/data/services/scheduling.py @@ -358,8 +358,8 @@ def make_schedule( sign = 1 - if result["sensor"].measures_power and result["sensor"].get_attribute( - "consumption_is_positive", True + if result["sensor"].measures_power and not result["sensor"].get_attribute( + "consumption_is_positive", False ): sign = -1 From 60b77a10d88babef42a7d06d30b0955195145cfe Mon Sep 17 00:00:00 2001 From: "F.N. Claessen" Date: Wed, 25 Feb 2026 20:05:26 +0100 Subject: [PATCH 03/10] docs: main changelog entry Signed-off-by: F.N. Claessen --- documentation/changelog.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation/changelog.rst b/documentation/changelog.rst index 720e8051bd..3e528877e6 100644 --- a/documentation/changelog.rst +++ b/documentation/changelog.rst @@ -61,6 +61,7 @@ Infrastructure / Support Bugfixes ----------- +* Fix: schedules are no longer saved upside down [see `PR #1348 `_] * Fix: visiting the job page for any forecasting job led to a server error ("Object of type datetime is not JSON serializable"), by storing serialized kwargs in forecasting job meta [see `PR #1990 `_] * Fix: flex-context dialogue is empty when flex-context has two booleans with the same value [see `PR #1907 `_] * Bring back the ability to show (timed) annotations on the sensor page, and add some color highlighting, too, while we're at it [see `PR #1967 `_] From df60830e762c6679c9f2fae14ef94296b7f0270b Mon Sep 17 00:00:00 2001 From: "F.N. Claessen" Date: Wed, 25 Feb 2026 20:05:49 +0100 Subject: [PATCH 04/10] docs: fix typo Signed-off-by: F.N. Claessen --- documentation/changelog.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/changelog.rst b/documentation/changelog.rst index 3e528877e6..0592ac35be 100644 --- a/documentation/changelog.rst +++ b/documentation/changelog.rst @@ -24,7 +24,7 @@ New features * Added ``root`` and ``depth`` fields to the `[GET] /assets` endpoint for listing assets, to allow selecting descendants of a given root asset up to a given depth [see `PR #1874 `_] * Give ability to edit sensor timezone from the UI [see `PR #1900 `_] * Support creating schedules with only information known prior to some time, now also via the CLI (the API already supported it) [see `PR #1871 `_]. -* Added capability to upate an asset's parent from the UI [`PR #1957 `_] +* Added capability to update an asset's parent from the UI [`PR #1957 `_] * Add ``fields`` param to the asset-listing endpoints, to save bandwidth in response data [see `PR #1884 `_] .. note:: For backwards-compatibility, the new ``fields`` parameter will only be fully active, i.e. also returning less fields per default, in v0.32. Set ``FLEXMEASURES_API_SUNSET_ACTIVE=True`` to test the full effect now. From a9cf916a07d5a9e45000611d8c23425f82e45f14 Mon Sep 17 00:00:00 2001 From: "F.N. Claessen" Date: Wed, 25 Feb 2026 20:06:50 +0100 Subject: [PATCH 05/10] docs: API changelog entry Signed-off-by: F.N. Claessen --- documentation/api/change_log.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation/api/change_log.rst b/documentation/api/change_log.rst index 6b5aa61a0e..c6fdef1583 100644 --- a/documentation/api/change_log.rst +++ b/documentation/api/change_log.rst @@ -17,6 +17,7 @@ These endpoints enable programmatic triggering and retrieval of forecasts via th Also: +- Schedules are no longer saved upside down. - Support saving the aggregate power schedule by referencing a power sensor in the ``flex-context`` (new field ``aggregate-power``). - Added ``root`` and ``depth`` fields to the `/assets` (GET) endpoint for listing assets, to allow selecting descendants of a given root asset up to a given depth. - Added ``fields`` field to the `/assets` (GET) and `/assets/public` endpoints, to transfer less data by default (will be fully active, i.e. also returning less fields per default, in v0.32). From b06a2ad2b1f60184349a8f434988d41abb28ce09 Mon Sep 17 00:00:00 2001 From: "F.N. Claessen" Date: Thu, 26 Feb 2026 08:41:11 +0100 Subject: [PATCH 06/10] delete: remove long deprecated scheduling modules Signed-off-by: F.N. Claessen --- flexmeasures/data/models/planning/battery.py | 11 ----------- flexmeasures/data/models/planning/charging_station.py | 11 ----------- 2 files changed, 22 deletions(-) delete mode 100644 flexmeasures/data/models/planning/battery.py delete mode 100644 flexmeasures/data/models/planning/charging_station.py diff --git a/flexmeasures/data/models/planning/battery.py b/flexmeasures/data/models/planning/battery.py deleted file mode 100644 index c8004792a2..0000000000 --- a/flexmeasures/data/models/planning/battery.py +++ /dev/null @@ -1,11 +0,0 @@ -from flexmeasures.data.models.planning.storage import StorageScheduler - - -def schedule_battery(*args, **kwargs): - import warnings - - warnings.warn( - "The schedule_battery method is deprecated and will be removed from flexmeasures in a future version. Replace with StorageScheduler().schedule to suppress this warning.", - FutureWarning, - ) - return StorageScheduler().schedule(*args, **kwargs) diff --git a/flexmeasures/data/models/planning/charging_station.py b/flexmeasures/data/models/planning/charging_station.py deleted file mode 100644 index 32ef204cf1..0000000000 --- a/flexmeasures/data/models/planning/charging_station.py +++ /dev/null @@ -1,11 +0,0 @@ -from flexmeasures.data.models.planning.storage import StorageScheduler - - -def schedule_charging_station(*args, **kwargs): - import warnings - - warnings.warn( - "The schedule_charging_station method is deprecated and will be removed from flexmeasures in a future version. Replace with StorageScheduler().schedule to suppress this warning.", - FutureWarning, - ) - return StorageScheduler().schedule(*args, **kwargs) From b74b42d60e71e8ed3e683731efd7a22bf62938a9 Mon Sep 17 00:00:00 2001 From: "F.N. Claessen" Date: Thu, 26 Feb 2026 08:45:59 +0100 Subject: [PATCH 07/10] feat: allow identification of time series before and after the switch Signed-off-by: F.N. Claessen --- flexmeasures/data/models/planning/process.py | 2 +- flexmeasures/data/models/planning/storage.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/flexmeasures/data/models/planning/process.py b/flexmeasures/data/models/planning/process.py index 0f820a946b..4217a0d905 100644 --- a/flexmeasures/data/models/planning/process.py +++ b/flexmeasures/data/models/planning/process.py @@ -19,7 +19,7 @@ class ProcessScheduler(Scheduler): - __version__ = "1" + __version__ = "2" __author__ = "Seita" def compute(self) -> pd.Series | None: diff --git a/flexmeasures/data/models/planning/storage.py b/flexmeasures/data/models/planning/storage.py index 4d17ee4596..f5cf84200b 100644 --- a/flexmeasures/data/models/planning/storage.py +++ b/flexmeasures/data/models/planning/storage.py @@ -1224,7 +1224,7 @@ def _ensure_variable_quantity( class StorageFallbackScheduler(MetaStorageScheduler): - __version__ = "2" + __version__ = "3" __author__ = "Seita" def compute(self, skip_validation: bool = False) -> SchedulerOutputType: @@ -1293,7 +1293,7 @@ def compute(self, skip_validation: bool = False) -> SchedulerOutputType: class StorageScheduler(MetaStorageScheduler): - __version__ = "6" + __version__ = "7" __author__ = "Seita" fallback_scheduler_class: Type[Scheduler] = StorageFallbackScheduler From 81473b2e89f4529ec1bb61f581a05f07efd80ab9 Mon Sep 17 00:00:00 2001 From: "F.N. Claessen" Date: Thu, 26 Feb 2026 09:16:45 +0100 Subject: [PATCH 08/10] docs: add changelog warning Signed-off-by: F.N. Claessen --- documentation/changelog.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/documentation/changelog.rst b/documentation/changelog.rst index 0592ac35be..f48771cf45 100644 --- a/documentation/changelog.rst +++ b/documentation/changelog.rst @@ -7,6 +7,19 @@ FlexMeasures Changelog v0.31.0 | February XX, 2026 ============================ +.. warning:: As of this version, power schedules will no longer appear flipped (in UI charts) when they are recorded on *consumption* sensors. + Please note that: + + - Schedules obtained via the dedicated API endpoints for scheduling are not affected by this change! + - The ``consumption_is_positive`` sensor attribute governs the sign of schedules saved to the database. + The sign convention of UI charts is to simply match what is in the database. + - If you inadvertently make use of the `sensor data API endpoint `_ to fetch *schedules*, + or have reporters that compute reports on *schedules*, rather than on *measurements*, be advised that you may experience flipped results. + You may need to adjust your client-side code or reporter configuration accordingly. + (Updating a reporter configuration automatically leads to a fresh data source for the saved time series.) + - Finally, if you maintain a plugin with a custom ``Scheduler`` class that returns time series to be saved on power sensors, we recommend incrementing the version of the ``Scheduler`` class. + This will yield a fresh data source for new schedules and allow you to discriminate your flipped schedules, which, for instance, will make it easier to flip back the historical schedules if you later want to. + .. warning:: Upgrading to this version requires running ``flexmeasures db upgrade`` (you can create a backup first with ``flexmeasures db-ops dump``). New features From 78647c8e54af4b209bb4b874e86940825faef0f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20H=C3=B6ning?= Date: Sat, 28 Feb 2026 18:54:34 +0100 Subject: [PATCH 09/10] small fixes in links of tutorial (scripts) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nicolas Höning --- documentation/tut/scripts/run-tutorial2-in-docker.sh | 6 +++--- documentation/tut/scripts/run-tutorial4-in-docker.sh | 2 +- documentation/tut/toy-example-reporter.rst | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/documentation/tut/scripts/run-tutorial2-in-docker.sh b/documentation/tut/scripts/run-tutorial2-in-docker.sh index 25f9c71da5..b0c8587be1 100755 --- a/documentation/tut/scripts/run-tutorial2-in-docker.sh +++ b/documentation/tut/scripts/run-tutorial2-in-docker.sh @@ -48,9 +48,9 @@ docker exec -it flexmeasures-server-1 flexmeasures add schedule --sensor 2 \ --flex-context '{"inflexible-device-sensors": [3]}' \ --flex-model '{"soc-min": "50 kWh"}' -#echo "[TUTORIAL-RUNNER] showing schedule ..." -#docker exec -it flexmeasures-server-1 flexmeasures show beliefs --sensor 2 --start ${TOMORROW}T07:00:00+01:00 --duration PT12H -# +echo "[TUTORIAL-RUNNER] showing schedule ..." +docker exec -it flexmeasures-server-1 flexmeasures show beliefs --sensor 2 --start ${TOMORROW}T07:00:00+01:00 --duration PT12H + #echo "" #echo "[TUTORIAL-RUNNER] DEMONSTRATING CUSTOM SCHEDULING RESOLUTION ..." #echo "[TUTORIAL-RUNNER] The previous schedule used the sensor's native 15-minute resolution (PT15M)." diff --git a/documentation/tut/scripts/run-tutorial4-in-docker.sh b/documentation/tut/scripts/run-tutorial4-in-docker.sh index ac76c16004..3463fa7370 100755 --- a/documentation/tut/scripts/run-tutorial4-in-docker.sh +++ b/documentation/tut/scripts/run-tutorial4-in-docker.sh @@ -23,4 +23,4 @@ docker exec -it flexmeasures-server-1 flexmeasures add schedule --sensor 6 --sch --flex-context '{"consumption-price": {"sensor": 1}}' \ --flex-model '{"duration": "PT4H", "process-type": "SHIFTABLE", "power": 0.2, "time-restrictions": [{"start": "'"${TOMORROW}"'T15:00:00+02:00", "duration": "PT1H"}]}' -echo "Now visit http://localhost:5000/assets/5/graphs to see all three schedules." +echo "Now visit http://localhost:5000/assets/6/graphs to see all three schedules." diff --git a/documentation/tut/toy-example-reporter.rst b/documentation/tut/toy-example-reporter.rst index c1d022282e..7457c200f3 100644 --- a/documentation/tut/toy-example-reporter.rst +++ b/documentation/tut/toy-example-reporter.rst @@ -137,7 +137,7 @@ Finally, we can create the report with the following command: --start-offset DB,1D --end-offset DB,2D \ --resolution PT15M -Now we can visualize the diminished headroom in the following `link `_, which should resemble the following image: +Now we can visualize the diminished headroom in the following `link `_, which should resemble the following image: .. image:: https://github.com/FlexMeasures/screenshots/raw/main/tut/toy-schedule/sensor-data-headroom.png :align: center From e084006553a5a8ed9887e84c83f8baec7e899949 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20H=C3=B6ning?= Date: Sat, 28 Feb 2026 18:55:19 +0100 Subject: [PATCH 10/10] minimum documentation improvement currently possible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nicolas Höning --- documentation/api/notation.rst | 9 ++++++--- documentation/concepts/data-model.rst | 27 ++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/documentation/api/notation.rst b/documentation/api/notation.rst index 7ae8bbef1c..5b6a5cab45 100644 --- a/documentation/api/notation.rst +++ b/documentation/api/notation.rst @@ -289,7 +289,10 @@ In this case, FlexMeasures will convert the data using the resolution of the tim Signs of power values ^^^^^^^^^^^^^^^^^^^^^ +In general, FlexMeasures lets you store data as you want. Negative power values to indicate production, positive consumption - or the other way around. -USEF recommends to use positive power values to indicate consumption and negative values to indicate production, i.e. -to take the perspective of the Prosumer. -If an asset has been configured as a pure producer or pure consumer, the web service will help avoid mistakes by checking the sign of posted power values. +We'd recommend to use positive power values to indicate consumption and negative values to indicate production, i.e. +-to take the perspective of the Prosumer. + +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). diff --git a/documentation/concepts/data-model.rst b/documentation/concepts/data-model.rst index 0983025288..bff7e7eb7f 100644 --- a/documentation/concepts/data-model.rst +++ b/documentation/concepts/data-model.rst @@ -43,7 +43,8 @@ Asset belong to accounts (read more on accounts below). Assets are often represented in other systems (e.g. IoT gateways / local EMS) with another ID. To link FlexMeasures' representation of assets with such external representations, you can store those IDs as `external_id`. -About asset types: +About asset types +^^^^^^^^^^^^^^^^^ We model asset types explicitly. None are required for running FlexMeasures. Some asset types have support in the UI (for icons, like a sun for ``"solar"``), and in the toy tutorial and test. @@ -97,6 +98,30 @@ Each belief links to a sensor and a data source. Here are two examples: - A thermal demand sensor containing forecasts (data source of type "forecast", e.g. heating usage forecast sent to FlexMeasures or made by FlexMeasures) and measurements (sent into FlexMeasures, data source type "user"). +.. _signs_of_power_beliefs: + +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. +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. +However, there is no universal standard for this. Some systems use positive values for production and negative values for consumption, while others do the opposite. + +FlexMeasures doesn't enforce any perspective (we have a design philosophy of letting users model the system in their own way). + +For example, users can create PV power data with positive values indicating production, and they can also create building power data with positive values indicating consumption. +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. + +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``. + + +.. note:: We will soon document better what the scheduler does in detail, and how the attribute works. + Accounts & Users ----------------