Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
176 commits
Select commit Hold shift + click to select a range
e2fced5
feature: copy trigger_schedule endpoint from SensorAPI to AssetAPI
Flix6x May 16, 2024
bfdd94f
fix: update function signature
Flix6x May 16, 2024
5795e1b
fix: get rid of deprecation warning
Flix6x May 16, 2024
2e4cfe0
fix: update docstring
Flix6x May 16, 2024
2e28ed9
fix: imports
Flix6x May 16, 2024
f3711de
fix: obtain sensors from flex-model
Flix6x May 16, 2024
305d76d
fix: create one scheduling job for each sensor listed in the flex-model
Flix6x May 16, 2024
f6e8075
fix: add todos
Flix6x May 16, 2024
4bf91dc
docs: update endpoint main descriptions and quickrefs
Flix6x May 17, 2024
0917896
style: black
Flix6x May 17, 2024
753b411
fix: changelog syntax
Flix6x May 17, 2024
ba90dd1
fix: remove redundant session commit when calling the API to trigger …
Flix6x May 17, 2024
af4debf
docs: update FlexContextSchema docstring
Flix6x May 17, 2024
49a1a12
feature: helpful message for test developers
Flix6x May 17, 2024
8a3e112
feature: check auth on sensors referenced in flex-context
Flix6x May 17, 2024
25d1180
feature: allow checking permissions on optional fields
Flix6x May 17, 2024
21ac09a
feature: decorator supports custom error handler
Flix6x May 17, 2024
b4ad01a
docs: add inline note explaining status code
Flix6x May 17, 2024
5b4c30f
feature: flex_context_loader lists all sensors contained in a flex-co…
Flix6x May 17, 2024
484a022
feature: support context loader that returns multiple contexts
Flix6x May 17, 2024
8374a9c
feature: check permissions on sensors referenced in flex-context
Flix6x May 17, 2024
4621ef6
feature: add test checking permissions
Flix6x May 17, 2024
ff22fea
fix: response with field names
Flix6x May 17, 2024
be51f1b
add create_sequential_scheduling_job function
May 17, 2024
061e1f3
add fixtures
May 17, 2024
6eb122b
add test_create_sequential_jobs
May 17, 2024
b204e4b
Merge remote-tracking branch 'origin/feature/api/endpoint-for-schedul…
May 17, 2024
22834ca
Revert "fix: response with field names"
Flix6x May 24, 2024
dc07b11
Revert "feature: add test checking permissions"
Flix6x May 24, 2024
b583c89
Revert "feature: check permissions on sensors referenced in flex-cont…
Flix6x May 24, 2024
d04bed0
Revert "feature: support context loader that returns multiple contexts"
Flix6x May 24, 2024
5fd2f63
Revert "feature: flex_context_loader lists all sensors contained in a…
Flix6x May 24, 2024
ee5e19e
Revert "docs: add inline note explaining status code"
Flix6x May 24, 2024
c2bf1af
Revert "feature: decorator supports custom error handler"
Flix6x May 24, 2024
529baa2
Revert "feature: allow checking permissions on optional fields"
Flix6x May 24, 2024
1665974
Revert "feature: check auth on sensors referenced in flex-context"
Flix6x May 24, 2024
8678a0d
docs: add inline note explaining permission decorator
Flix6x May 24, 2024
f42ceaf
fix: remove unused parameter (does not need to be formally deprecated…
Flix6x May 24, 2024
7b5b3ce
feature: check that each flexible device power sensor lives under the…
Flix6x May 24, 2024
e9e6ec9
Merge branch 'main' into feature/api/endpoint-for-scheduling-asset
May 30, 2024
378b0a7
docs: changelog entry
Flix6x Jun 3, 2024
754502a
docs: API changelog entry
Flix6x Jun 3, 2024
e1e1019
feature: allow loading API data from three places, and avoid clashing…
Flix6x Jun 4, 2024
4f86bb1
docs: typos
Flix6x Jun 4, 2024
de811ec
refactor: parameterize test cases
Flix6x Jun 5, 2024
175cd18
refactor: merge AssetIdField and GenericAssetIDField
Flix6x Jun 5, 2024
ffe82b1
refactor: move to AssetTriggerSchema
Flix6x Jun 5, 2024
45592c7
remove
Flix6x Jun 5, 2024
99bd8da
remove: seemingly obsolete workaround
Flix6x Jun 5, 2024
44cfd0c
feature: validate flex-model sensors belong to asset
Flix6x Jun 5, 2024
ee08883
feature: more clearly separate the serialized and deserialized parts …
Flix6x Jun 5, 2024
a9ddce8
feature: add end-to-end test for triggering and getting a schedule
Flix6x Jun 5, 2024
f340a95
docs: add fixture docstring explaining partial deserialization
Flix6x Jun 5, 2024
4c6c52a
style: black
Flix6x Jun 5, 2024
b328921
fix: in case no inflexible-device-sensors were part of the flex-context
Flix6x Jun 5, 2024
b40d40e
docs: fix inline comment
Flix6x Jun 5, 2024
b7961f4
fix: job enqueueing
Flix6x Jun 5, 2024
429d97f
style: black
Flix6x Jun 5, 2024
8423522
refactor: rename argument; sequential scheduling is only for assets
Flix6x Jun 5, 2024
c60f5cf
docs: explain assert statement
Flix6x Jun 5, 2024
8ba79aa
Merge remote-tracking branch 'refs/remotes/origin/main' into feature/…
Flix6x Jun 5, 2024
9f5eb6a
style: black
Flix6x Jun 5, 2024
71da5c4
handle fallback and rescheduling
Jun 5, 2024
07b44b6
style: flake8
Flix6x Jun 5, 2024
a25ab4d
Merge remote-tracking branch 'origin/feature/api/endpoint-for-schedul…
Jun 5, 2024
5f9a4dc
fix: clarify join to avoid `sqlalchemy.exc.AmbiguousForeignKeysError`
Flix6x Jun 5, 2024
1f26fa2
Merge remote-tracking branch 'origin/feature/api/endpoint-for-schedul…
Jun 5, 2024
8b0c0d0
fix merge
Jun 5, 2024
edf38a8
Merge branch 'main' into feature/api/endpoint-for-scheduling-asset
Jun 5, 2024
05064ae
fix: remove 404, because the `asset` field should be seen as part of …
Flix6x Jun 5, 2024
c7e58cb
feature: avoid having magic number for status codes
Flix6x Jun 5, 2024
36c75da
Merge remote-tracking branch 'refs/remotes/origin/main' into feature/…
Flix6x Jun 10, 2025
a15792c
fix: use new flex-context fields
Flix6x Jun 5, 2024
75c80f5
chore: get rid of deprecation warning: The `sensor` keyword argument …
Flix6x Jun 10, 2025
74c3ff5
fix: return the ID of the wrap-up job
Flix6x Jun 10, 2025
0b6ab40
docs: move API changelog entry
Flix6x Jun 10, 2025
d14cb93
docs: mention the multi-device scheduler handles inflexible devices, too
Flix6x Jun 10, 2025
c8eb88e
fix: GenericAsset becomes asset_or_sensor_type=="genericasset" in the…
Flix6x Jun 10, 2025
559c0ea
feat: test getting the schedule for each flexible device described in…
Flix6x Jun 10, 2025
d46a8aa
docs: add clarifying inline comment
Flix6x Jun 10, 2025
7ecab71
feat: create charging hub (hierarchical structure of two existing CP …
Flix6x Jun 10, 2025
2e91265
feat: add util function to sort jobs by time of creation
Flix6x Jun 10, 2025
83ab8bd
feat: test a multi-asset flex-model comprising more than 1 flexible d…
Flix6x Jun 10, 2025
29af4d3
feat: use StorageScheduler by default
Flix6x Jun 10, 2025
e44d472
feat: allow to toggle between sequential and simultaneous scheduling,…
Flix6x Jun 10, 2025
df0a2f7
fix: prepare to rename GenericAsset class to Asset
Flix6x Jun 10, 2025
3c4113a
feat: test simultaneous and sequential scheduling via API
Flix6x Jun 10, 2025
fba0f6e
chore: clean up todo
Flix6x Jun 10, 2025
5b3c06e
fix: update test
Flix6x Jun 11, 2025
d23fc7c
fix: correct type annotation
Flix6x Jun 11, 2025
29144b1
fix: point API users to pick up their schedules for each power sensor…
Flix6x Jun 11, 2025
0a9f811
docs: update endpoint documentation in docstring
Flix6x Jun 11, 2025
36da302
docs: update notes regarding API endpoint(s) for triggering schedule …
Flix6x Jun 11, 2025
9afcdef
fix: scheduler_kwargs should be JSON serializable
Flix6x Jun 11, 2025
f156981
fix: don't validate storage constraints on a non-storage device
Flix6x Jun 11, 2025
4fdb4a6
docs: update main example on posting flex states
Flix6x Jun 11, 2025
9b7f8bd
docs: update comment on persisting flexibility states
Flix6x Jun 11, 2025
c99045c
docs: update the trigger endpoints referenced in the scheduling section
Flix6x Jun 11, 2025
85c144b
docs: update quickref
Flix6x Jun 11, 2025
f7e2843
docs: update note
Flix6x Jun 11, 2025
afed806
docs: fix grammar
Flix6x Jun 11, 2025
217a632
docs: show different texts
Flix6x Jun 11, 2025
7963c54
docs: clarify assumed sensor/asset structure
Flix6x Jun 11, 2025
f95dae6
docs: mention single-asset scheduling can still take into account inf…
Flix6x Jun 11, 2025
f054037
Merge remote-tracking branch 'refs/remotes/origin/main' into feature/…
Flix6x Jun 11, 2025
7162ff0
docs: add code examples for API and flexmeasures-client for triggerin…
Flix6x Jun 11, 2025
26f7f45
docs: add link to flexmeasures-client on PyPI
Flix6x Jun 11, 2025
040b36f
docs: add missing sensor IDs to multi-asset flex-model
Flix6x Jun 11, 2025
5666321
docs: fix RST syntax
Flix6x Jun 11, 2025
588ae1a
docs: improve capitalization
Flix6x Jun 11, 2025
67d3f05
docs: add code examples for API and flexmeasures-client for triggerin…
Flix6x Jun 11, 2025
9fb381e
docs: sync timezone offsets across tutorials
Flix6x Jun 11, 2025
650077b
docs: fix flex-model in API example
Flix6x Jun 11, 2025
d877518
docs: add multi-asset example for PV curtailment in API and flexmeasu…
Flix6x Jun 11, 2025
43e3b4a
fix: serializable job kwargs
Flix6x Jun 12, 2025
e9c65a5
docs: add inline notes explaining the IDs in the flexmeasures-client …
Flix6x Jun 12, 2025
acbc49b
docs: fix url to trigger endpoint
Flix6x Jun 12, 2025
4bc892c
docs: link to the endpoint docs instead of the actual endpoint, which…
Flix6x Jun 12, 2025
de35747
docs: better phrasing
Flix6x Jun 12, 2025
1bd3b5a
style: emphasize new lines with respect to previous examples
Flix6x Jun 12, 2025
48aaf0a
docs: add comment hinting at the parameter name we are introducing in…
Flix6x Jun 12, 2025
29385fc
style: use a new line for each option
Flix6x Jun 12, 2025
9df1392
fix: remove outdated comment (the consumption-price sensor is preconf…
Flix6x Jun 12, 2025
8c141ef
feat: simplify expanded CLI example (the consumption-price sensor is …
Flix6x Jun 12, 2025
075d61a
docs: refer to multiple schedules
Flix6x Jun 12, 2025
e85d511
docs: add note regarding the lack of flex-context in the example
Flix6x Jun 12, 2025
becdf12
docs: highlight consumption-price in flex-context
Flix6x Jun 12, 2025
b874ddd
docs: stop using the --consumption-price-sensor option in the Process…
Flix6x Jun 12, 2025
99eae75
docs: reduce indentation of CLI command output
Flix6x Jun 12, 2025
8040e90
docs: add missing $
Flix6x Jun 12, 2025
07dc5bf
docs: rerun some tutorial steps to get the right indentation (updatin…
Flix6x Jun 12, 2025
903b9c7
docs: fix header navigation
Flix6x Jun 12, 2025
b130b1e
docs: add example setting
Flix6x Jun 13, 2025
822516c
docs: suggested changes
Flix6x Jun 13, 2025
84f9cf9
docs: clarify curtailment model
Flix6x Jun 13, 2025
81a54e0
docs: rewrite quickref
Flix6x Jun 13, 2025
71dff5f
fix: revert accidental revision from resolving merge conflicts
Flix6x Jun 13, 2025
ca6bb86
feat: check resulting schedule
Flix6x Jun 13, 2025
252af4c
fix: extending scheduling horizon with simultaneous scheduling was si…
Flix6x Jun 13, 2025
0b09890
fix: update test accordingly
Flix6x Jun 13, 2025
21d3f81
fix: test charging during cheapest hour
Flix6x Jun 15, 2025
a2b134c
fix: use soc-unit in multi-asset flex-models
Flix6x Jun 16, 2025
2174073
fix: revise test expectations accordingly
Flix6x Jun 16, 2025
a5eaad4
Merge remote-tracking branch 'refs/remotes/origin/main' into feature/…
Flix6x Jun 16, 2025
a47efed
refactor: use explanatory util variable
Flix6x Jun 16, 2025
0eabc38
refactor: remove obsolete argument
Flix6x Jun 16, 2025
9aedfc6
feat: check constraints
Flix6x Jun 16, 2025
47fc431
fix: only check the CP with a target
Flix6x Jun 16, 2025
56f490b
fix: if/else logic
Flix6x Jun 16, 2025
9354979
refactor: simplify
Flix6x Jun 16, 2025
1cc6574
refactor: remove obsolete argument (second part)
Flix6x Jun 16, 2025
26ae60c
refactor: remove another obsolete argument
Flix6x Jun 16, 2025
55c6f5f
refactor: assign intermediate result to variable
Flix6x Jun 16, 2025
d143338
feat: test fetching SoC schedules
Flix6x Jun 16, 2025
54be949
refactor: clarifying variable
Flix6x Jun 16, 2025
eff5761
Merge remote-tracking branch 'refs/remotes/origin/main' into feature/…
Flix6x Jun 16, 2025
45a13f8
fix: API should only switch sign if the scheduling service switched i…
Flix6x Jun 16, 2025
8ba2b50
dev: remove print statement
Flix6x Jun 16, 2025
7fd964c
fix: "%" units not supported in Python 3.8?
Flix6x Jun 16, 2025
10f7f1b
docs: add paragraph on interpreting schedules and making them suit sp…
Flix6x Jun 16, 2025
22ba034
docs: use the same sensor ID as in the previous example from posting_…
Flix6x Jun 16, 2025
59f10c9
docs: add note on retrieving the SoC schedule
Flix6x Jun 16, 2025
673b378
docs: reference the sensor ID in the main body of text
Flix6x Jun 16, 2025
363ad0a
docs: fill in API version 3
Flix6x Jun 16, 2025
96db6e1
docs: also also
Flix6x Jun 16, 2025
9befe96
docs: follow capitalization of package itself
Flix6x Jun 16, 2025
58e7743
Merge remote-tracking branch 'refs/remotes/origin/main' into feature/…
Flix6x Jun 18, 2025
edc099e
refactor: simplify expected schedule
Flix6x Jun 18, 2025
867e1ae
docs: clarify note
Flix6x Jun 18, 2025
d0f4e02
docs: clarify asserts
Flix6x Jun 18, 2025
4fa292d
fix: np.assert_equal does not treat -0.0 the same as 0 (or as 0.0)
Flix6x Jun 19, 2025
6dc8a98
Merge branch 'main' into feature/api/endpoint-for-scheduling-asset
nhoening Jun 20, 2025
ecb355f
docs: rephrase note
Flix6x Jun 20, 2025
094bf05
docs: explain test expectations
Flix6x Jun 20, 2025
d1750b5
Merge remote-tracking branch 'refs/remotes/origin/main' into feature/…
Flix6x Jun 20, 2025
8fc151c
Merge remote-tracking branch 'origin/feature/api/endpoint-for-schedul…
Flix6x Jun 20, 2025
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
6 changes: 6 additions & 0 deletions documentation/api/change_log.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ API change log

.. note:: The FlexMeasures API follows its own versioning scheme. This is also reflected in the URL (e.g. `/api/v3_0`), allowing developers to upgrade at their own pace.

v3.0-24 | 2025-06-10
""""""""""""""""""""
- New API endpoint `[POST] /assets/(id)/schedules/trigger <api/v3_0.html#post--api-v3_0-assets-(id)-schedules-trigger>`_ to schedule a site with multiple flexible devices.
- Updated message for 404 Not Found on endpoints for managing assets: `/assets` (GET, POST) and `/assets/<id>` (GET, PATCH, DELETE).


v3.0-23 | 2025-04-08
""""""""""""""""""""

Expand Down
1 change: 1 addition & 0 deletions documentation/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ v0.27.0 | August XX, 2025
New features
-------------

* New API endpoint `[POST] /assets/(id)/schedules/trigger <api/v3_0.html#post--api-v3_0-assets-(id)-schedules-trigger>`_ to schedule a site with multiple flexible devices [see `PR #1065 <https://github.com/FlexMeasures/flexmeasures/pull/1065/>`_]
* Add form to upload sensor data to the database [see `PR #1481 <https://github.com/FlexMeasures/flexmeasures/pull/1481>`_]
* Allow editing users in the UI [see `PR #1502 <https://github.com/FlexMeasures/flexmeasures/pull/1502>`_]
* Move various warnings to toast notifications [see `PR #1529 <https://github.com/FlexMeasures/flexmeasures/pull/1529>`_]
Expand Down
6 changes: 3 additions & 3 deletions documentation/features/scheduling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ For more details on the possible formats for field values, see :ref:`variable_qu

Where should you set these fields?
Within requests to the API or by editing the relevant asset in the UI.
If they are not sent in via the API (the endpoint triggering schedule computation), the scheduler will look them up on the `flex-context` field of the asset.
If they are not sent in via the API (one of the endpoints triggering schedule computation), the scheduler will look them up on the `flex-context` field of the asset.
And if the asset belongs to a larger system (a hierarchy of assets), the scheduler will also search if parent assets have them set.


Expand Down Expand Up @@ -156,7 +156,7 @@ The process scheduler is suitable for shiftable, breakable and inflexible loads,


We describe the respective flex models below.
At the moment, they have to be sent through the API (the endpoint to trigger schedule computation, or using the FlexMeasures client) or through the CLI (the command to add schedules).
At the moment, they have to be sent through the API (one of the endpoints to trigger schedule computation, or using the FlexMeasures client) or through the CLI (the command to add schedules).
We will soon work on the possibility to store (a subset of) these fields on the data model and edit them in the UI.


Expand Down Expand Up @@ -275,7 +275,7 @@ depending on the first target state of charge and the capabilities of the asset.

Of course, we also log a failure in the scheduling job, so it's important to take note of these failures. Often, mis-configured flex models are the reason.

For a hands-on tutorial on using some of the storage flex-model fields, head over to :ref:`tut_v2g` use case and `the API documentation for triggering schedules <../api/v3_0.html#post--api-v3_0-sensors-(id)-schedules-trigger>`_.
For a hands-on tutorial on using some of the storage flex-model fields, head over to :ref:`tut_v2g` use case and `the API documentation for triggering schedules <../api/v3_0.html#post--api-v3_0-assets-(id)-schedules-trigger>`_.

Finally, are you interested in the linear programming details behind the storage scheduler?
Then head over to :ref:`storage_device_scheduler`!
Expand Down
28 changes: 23 additions & 5 deletions documentation/tut/forecasting_scheduling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ It usually involves a linear program that combines a state of energy flexibility
There are two ways to queue a scheduling job:

First, we can add a scheduling job to the queue via the API.
We already learned about the `[POST] /schedules/trigger <../api/v3_0.html#post--api-v3_0-sensors-(id)-schedules-trigger>`_ endpoint in :ref:`posting_flex_states`, where we saw how to post a flexibility state (in this case, the state of charge of a battery at a certain point in time).
We already learned about the `[POST] /schedules/trigger <../api/v3_0.html#post--api-v3_0-assets-(id)-schedules-trigger>`_ endpoint in :ref:`posting_flex_states`, where we saw how to post a flexibility state (in this case, the state of charge of a battery at a certain point in time).

Here, we extend that (storage) example with an additional target value, representing a desired future state of charge.

Expand All @@ -108,6 +108,7 @@ Here, we extend that (storage) example with an additional target value, represen
{
"start": "2015-06-02T10:00:00+00:00",
"flex-model": {
"sensor": 15,
"soc-at-start": "12.1 kWh",
"soc-targets": [
{
Expand All @@ -130,7 +131,7 @@ A second way to add scheduling jobs is via the CLI, so this is available for peo

.. code-block:: bash

$ flexmeasures add schedule for-storage --sensor 1 --consumption-price-sensor 2 \
$ flexmeasures add schedule for-storage --sensor 15 --consumption-price-sensor 2 \
--start 2022-07-05T07:00+01:00 --duration PT12H \
--soc-at-start 50% --roundtrip-efficiency 90% --as-job

Expand All @@ -154,7 +155,7 @@ A prognosis can be requested at a URL looking like this:

.. code-block:: html

https://company.flexmeasures.io/api/<version>/sensors/data
https://company.flexmeasures.io/api/v3_0/sensors/data

This example requests a prognosis for 24 hours, with a rolling horizon of 6 hours before realisation.

Expand All @@ -180,11 +181,23 @@ We saw above how FlexMeasures can create optimised schedules with control signal

.. code-block:: html

https://company.flexmeasures.io/api/<version>/sensors/<id>/schedules/<uuid>
https://company.flexmeasures.io/api/v3_0/sensors/<id>/schedules/<uuid>

Here, the schedule's Universally Unique Identifier (UUID) should be filled in that is returned in the `[POST] /schedules/trigger <../api/v3_0.html#post--api-v3_0-sensors-(id)-schedules-trigger>`_ response.
Here, the schedule's Universally Unique Identifier (UUID) should be filled in that is returned in the `[POST] /schedules/trigger <../api/v3_0.html#post--api-v3_0-assets-(id)-schedules-trigger>`_ response.
Schedules can be queried by their UUID for up to 1 week after they were triggered (ask your host if you need to keep them around longer).
Afterwards, the exact schedule can still be retrieved through the `[GET] /sensors/data <../api/v3_0.html#get--api-v3_0-sensors-data>`_, using precise filter values for ``start``, ``prior`` and ``source``.
Besides the UUID, the endpoint for retrieving schedules takes a sensor ID, which is the sensor ID of one of the power sensors that was referenced in the flex model.

.. note:: If a ``state-of-charge`` sensor was referenced in the flex model (like in the example below), the scheduled state of charge can be retrieved using the same endpoint and UUID, but then using the state-of-charge sensor ID.

.. code-block:: json

"flex-model": {
"sensor": 15,
"state-of-charge": {"sensor": 16}
}

For instance, if the above snippet represents the flex model used by FlexMeasures to compute the schedule, then to fetch the scheduled state of charge you simply replace the power sensor ID in the URL of the `[GET] /sensors/data <../api/v3_0.html#get--api-v3_0-sensors-data>`_ endpoint with the state-of-charge sensor ID.

The following example response indicates that FlexMeasures planned ahead 45 minutes for the requested battery power sensor.
The list of consecutive power values represents the target consumption of the battery (negative values for production).
Expand Down Expand Up @@ -212,3 +225,8 @@ However, because the targets values represent averages over 15-minute time inter
For example, the battery might start to consume with 2.1 MW at 10.00am and increase its consumption to 2.25 at 10.10am,
increase its consumption to 5 MW at 10.15am and decrease its consumption to 2 MW at 10.20am.
That should result in the same average values for each quarter-hour.

Likewise, the control signals can be used to schedule devices that only run at specific power levels.
For example, let's assume the battery only supports running at an integer number of MW.
In that case, the battery could start to consume with 2 MW at 10.00am, increase its consumption to 3 MW at (15 seconds before) 10.12am, and decrease its consumption to 2 MW at 10.30am.
Again, this results in the same average values for each quarter-hour.
34 changes: 26 additions & 8 deletions documentation/tut/posting_data.rst
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ The exact URL will depend on your domain name, and will look approximately like

.. code-block:: html

[POST] https://company.flexmeasures.io/api/<version>/sensors/data
[POST] https://company.flexmeasures.io/api/v3_0/sensors/data

This example "PostSensorDataRequest" message posts prices for hourly intervals between midnight and midnight the next day
for the Korean Power Exchange (KPX) day-ahead auction, registered under sensor 16.
Expand Down Expand Up @@ -271,28 +271,46 @@ There is one more crucial kind of data that FlexMeasures needs to know about: Wh
For example, a battery has a certain state of charge, which is relevant to describe the flexibility that the battery currently has.
In our terminology, this is called the "flex model" and you can read more at :ref:`describing_flexibility`.

Owners of such devices can post the flex model along with triggering the creation of a new schedule, to `[POST] /schedules/trigger <../api/v3_0.html#post--api-v3_0-sensors-(id)-schedules-trigger>`_.
Owners of such devices can post the flex model along with triggering the creation of a new schedule, to one of two endpoints:

1. `[POST] /assets/<id>/schedules/trigger <../api/v3_0.html#post--api-v3_0-assets-(id)-schedules-trigger>`_ - for scheduling multiple devices
2. `[POST] /sensors/<id>/schedules/trigger <../api/v3_0.html#post--api-v3_0-sensors-(id)-schedules-trigger>`_ - for scheduling a single device (which can also be done with the first endpoint)

The URL might look like this:

.. code-block:: html

https://company.flexmeasures.io/api/<version>/sensors/10/schedules/trigger
https://company.flexmeasures.io/api/v3_0/assets/10/schedules/trigger

The following example triggers a schedule for a power sensor (with ID 10) of a battery asset, asking to take into account the battery's current state of charge.
The following example triggers a schedule for a power sensor (with ID 15) of a battery asset (with ID 10), asking to take into account the battery's current state of charge.
From this, FlexMeasures derives the energy flexibility this battery has in the next 48 hours and computes an optimal charging schedule.
The endpoint also allows to limit the flexibility range and also to set target values.

.. code-block:: json

{
"start": "2015-06-02T10:00:00+00:00",
"flex-model": {
"soc-at-start": "12.1 kWh"
}
"flex-model": [
{
"sensor": 15,
"soc-at-start": "12.1 kWh"
}
]
}

.. note:: More details on supported flex models can be found in :ref:`flex_models_and_schedulers`.

.. note:: Flexibility states are persisted on sensor attributes. To record a more complete history of the state of charge, set up a separate sensor and post data to it using `[POST] /sensors/data <../api/v3_0.html#post--api-v3_0-sensors-data>`_ (see :ref:`posting_sensor_data`).
.. note::
Flexibility states posted in trigger messages are only stored temporarily to describe the scheduling job.
To record a more complete history of the flexibility state, set up separate sensors and post data to them using `[POST] /sensors/data <../api/v3_0.html#post--api-v3_0-sensors-data>`_ (see :ref:`posting_sensor_data`).
Then reference those sensors in your flex model.
For example, say you use sensor 82 to record the power-to-heat efficiency of a heating system, then use this sensor reference in your flex model:

.. code-block:: json

{
"charging-efficiency": {"sensor": 82}
}


In :ref:`how_queue_scheduling`, we'll cover what happens when FlexMeasures is triggered to create a new schedule, and how those schedules can be retrieved via the API, so they can be used to steer assets.
148 changes: 135 additions & 13 deletions documentation/tut/toy-example-expanded.rst
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ Setting the data source type to "forecaster" helps FlexMeasures to visually dist
$ flexmeasures add beliefs --sensor 3 --source 4 solar-tomorrow.csv --timezone Europe/Amsterdam
Successfully created beliefs

The one-hour CSV data is automatically resampled to the 15-minute resolution of the sensor that is recording solar production. We can see solar production in the `FlexMeasures UI <http://localhost:5000/sensors/3>`_ :
The one-hour CSV data is automatically resampled to the 15-minute resolution of the sensor that is recording solar production. We can see solar production in the `FlexMeasures UI <http://localhost:5000/sensors/3>`_:

.. image:: https://github.com/FlexMeasures/screenshots/raw/main/tut/toy-schedule/sensor-data-production.png
:align: center
Expand All @@ -75,17 +75,139 @@ The one-hour CSV data is automatically resampled to the 15-minute resolution of
Trigger an updated schedule
----------------------------

Now, we'll reschedule the battery while taking into account the solar production. This will have an effect on the available headroom for the battery, given the ``site-power-capacity`` limit discussed earlier.

.. code-block:: bash

$ flexmeasures add schedule for-storage --sensor 2 --consumption-price-sensor 1 \
--inflexible-device-sensor 3 \
--start ${TOMORROW}T07:00+02:00 --duration PT12H \
--soc-at-start 50% --roundtrip-efficiency 90%
New schedule is stored.

We can see the updated scheduling in the `FlexMeasures UI <http://localhost:5000/sensors/2>`_ :
Now, we'll reschedule the battery while taking into account the solar production (forecast) as an inflexible device.
This will have an effect on the available headroom for the battery, given the ``site-power-capacity`` limit discussed earlier.

.. tabs::

.. tab:: CLI

.. code-block:: bash
:emphasize-lines: 3

$ flexmeasures add schedule for-storage \
--sensor 2 \
--inflexible-device-sensor 3 \
--start ${TOMORROW}T07:00+01:00 \
--duration PT12H \
--soc-at-start 50% \
--roundtrip-efficiency 90%
New schedule is stored.

.. tab:: API

Example call: `[POST] http://localhost:5000/api/v3_0/assets/2/schedules/trigger <../api/v3_0.html#post--api-v3_0-assets-(id)-schedules-trigger>`_ (update the start date to tomorrow):

.. code-block:: json
:emphasize-lines: 11-13

{
"start": "2025-06-11T07:00+01:00",
"duration": "PT12H",
"flex-model": [
{
"sensor": 2,
"soc-at-start": "50%",
"roundtrip-efficiency": "90%"
}
],
"flex-context": {
"inflexible-device-sensors": [3]
}
}

Alternatively, if the solar production is curtailable, move the solar production to the flex-model.
There, we tell the scheduler to pick any production value between 0 and the production forecast recorded on sensor 3, and to store the resulting schedule on sensor 3 as well (the FlexMeasures UI will still be able to distinguish forecasts from schedules):

.. code-block:: json
:emphasize-lines: 10-14,16

{
"start": "2025-06-11T07:00+01:00",
"duration": "PT12H",
"flex-model": [
{
"sensor": 2,
"soc-at-start": "50%",
"roundtrip-efficiency": "90%"
},
{
"sensor": 3,
"consumption-capacity": "0 kW",
"production-capacity": {"sensor": 3},
}
],
"flex-context": {}
}

.. tab:: FlexMeasures Client

Using the `FlexMeasures Client <https://pypi.org/project/flexmeasures-client/>`_:

.. code-block:: bash

pip install flexmeasures-client

.. code-block:: python
:emphasize-lines: 22-24

import asyncio
from datetime import date
from flexmeasures_client import FlexMeasuresClient as Client

async def client_script():
client = Client(
email="[email protected]",
password="toy-password",
host="localhost:5000",
)
schedule = await client.trigger_and_get_schedule(
asset_id=2, # Toy building (asset ID)
start=f"{date.today().isoformat()}T07:00+01:00",
duration="PT12H",
flex_model=[
{
"sensor": 2, # battery power (sensor ID)
"soc-at-start": "50%",
"roundtrip-efficiency": "90%",
},
],
flex_context={
"inflexible-device-sensors": [3], # solar production (sensor ID)
},
)
print(schedule)
await client.close()

asyncio.run(client_script())

Alternatively, if the solar production is curtailable, move the solar production to the flex-model:

.. code-block:: python
:emphasize-lines: 11-15,17

schedule = await client.trigger_and_get_schedule(
asset_id=2, # Toy building (asset ID)
start=f"{date.today().isoformat()}T07:00+01:00",
duration="PT12H",
flex_model=[
{
"sensor": 2, # battery power (sensor ID)
"soc-at-start": "50%",
"roundtrip-efficiency": "90%",
},
{
"sensor": 3, # solar production (sensor ID)
"consumption-capacity": "0 kW",
"production-capacity": {"sensor": 3},
},
],
flex_context={},
)



We can see the updated scheduling in the `FlexMeasures UI <http://localhost:5000/sensors/2>`_:

.. image:: https://github.com/FlexMeasures/screenshots/raw/main/tut/toy-schedule/sensor-data-charging-with-solar.png
:align: center
Expand Down Expand Up @@ -117,7 +239,7 @@ In the case of the scheduler that we ran in the previous tutorial, which did not

.. note:: You can add arbitrary sensors to a chart using the asset UI or the attribute ``sensors_to_show``. See :ref:`view_asset-data` for more.

A nice feature is that you can check the data connectivity status of your building asset. Now that we have made the schedule, both lamps are green. You can also view it in `FlexMeasures UI <http://localhost:5000/assets/2/status>`_ :
A nice feature is that you can check the data connectivity status of your building asset. Now that we have made the schedule, both lamps are green. You can also view it in `FlexMeasures UI <http://localhost:5000/assets/2/status>`_:

.. image:: https://github.com/FlexMeasures/screenshots/raw/main/tut/toy-schedule/screenshot_building_status.png
:align: center
Expand Down
Loading