Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
111 commits
Select commit Hold shift + click to select a range
f97c2f0
feat: add Automation data model
Flix6x Jul 11, 2026
f410437
feat: CLI commands to manage and run automations
Flix6x Jul 11, 2026
6f6591c
feat: record on forecasting jobs how they were created
Flix6x Jul 11, 2026
fb74bfc
feat: API endpoints to list an asset's automations
Flix6x Jul 11, 2026
ab62b9f
feat: UI page listing an asset's automations
Flix6x Jul 11, 2026
db8f288
test: cover automations CLI, API and UI
Flix6x Jul 11, 2026
9cb4f63
docs: document automations
Flix6x Jul 11, 2026
e0575c7
docs: changelog entry for automations
Flix6x Jul 11, 2026
b1f56bf
fix: render cron descriptions in 24-hour format regardless of locale
Flix6x Jul 11, 2026
de6fb71
fix: address code review findings for automations
Flix6x Jul 11, 2026
bf2cc60
fix: address code review findings for automations (remaining files)
Flix6x Jul 11, 2026
0b345b2
feat: record on scheduling jobs how they were created
Flix6x Jul 11, 2026
4c0c5db
feat: schedules as automations
Flix6x Jul 11, 2026
ac4c74a
docs: changelog entry for schedule automations
Flix6x Jul 11, 2026
7493c13
test: assert on the cron validation failure without pinning click's m…
Flix6x Jul 12, 2026
7bc3056
merge: synchronize automations with current main
BelhsanHmida Jul 31, 2026
15c9937
data/schemas: restrict automations to five-field cron
BelhsanHmida Jul 31, 2026
3090cf5
data/schemas/tests: cover automation cron field count
BelhsanHmida Jul 31, 2026
8cc3920
cli/jobs: retain automation guard after queueing failure
BelhsanHmida Jul 31, 2026
29c46b3
cli/tests: cover partial automation queue failure
BelhsanHmida Jul 31, 2026
8666c31
cli: normalize YAML forecasting option files
BelhsanHmida Jul 31, 2026
3433020
cli/tests: cover automation YAML option files
BelhsanHmida Jul 31, 2026
430dcef
data/services: redact inaccessible automation provenance
BelhsanHmida Jul 31, 2026
6c4bbc6
api/v3_0/tests: cover automation provenance authorization
BelhsanHmida Jul 31, 2026
337ad3b
ui/assets: distinguish automation load failures
BelhsanHmida Jul 31, 2026
119fc9d
ui/tests: cover automation load error state
BelhsanHmida Jul 31, 2026
04daae4
utils/docs: preserve standalone asterisks in RST conversion
BelhsanHmida Jul 31, 2026
22addda
utils/tests: cover RST cron wildcard conversion
BelhsanHmida Jul 31, 2026
edf77a5
docs/forecasting: clarify automation execution contract
BelhsanHmida Jul 31, 2026
a6cee99
changelog: record automation API and runner contract
BelhsanHmida Jul 31, 2026
194f8cc
api/docs: show job creation provenance
BelhsanHmida Jul 31, 2026
a3d7ebe
test: keep forecast CLI stub compatible with job provenance
BelhsanHmida Jul 31, 2026
de76798
Merge main into forecast automations
BelhsanHmida Aug 4, 2026
646f9fd
fix: require valid automation generators
BelhsanHmida Aug 4, 2026
4664afe
test: cover automation generator retention
BelhsanHmida Aug 4, 2026
b801d74
fix: constrain forecast automation outputs
BelhsanHmida Aug 5, 2026
006f85c
test: cover forecast automation output scope
BelhsanHmida Aug 5, 2026
dba4edc
docs: explain forecast automation ownership rules
BelhsanHmida Aug 5, 2026
efdda5a
fix: merge automation and main migration heads
BelhsanHmida Aug 5, 2026
5e86232
merge: synchronize schedule automations with reviewed parent
BelhsanHmida Aug 5, 2026
bc1fc32
data/models: allow schedule automations without generators
BelhsanHmida Aug 5, 2026
2f4afe2
cli/tests: cover schedule automation validation
BelhsanHmida Aug 5, 2026
d3c3082
data/tests: cover schedule automation dispatch
BelhsanHmida Aug 5, 2026
9505e2b
api/v3_0/tests: cover schedule job provenance
BelhsanHmida Aug 5, 2026
5de1f20
ui/tests: cover automation type tabs
BelhsanHmida Aug 5, 2026
6bf6143
scheduling: harden automation dispatch
BelhsanHmida Aug 5, 2026
03f1b88
cli: reject forecast options for schedule automations
BelhsanHmida Aug 5, 2026
75b2be6
ui/assets: resize automation tables on tab changes
BelhsanHmida Aug 5, 2026
71a7196
docs: clarify schedule automation inputs
BelhsanHmida Aug 5, 2026
d39f60f
cli/tests: cover malformed automation YAML
BelhsanHmida Aug 5, 2026
5b04664
cli: report malformed automation YAML
BelhsanHmida Aug 5, 2026
1ec9324
data/tests: cover stored schedule flex configuration
BelhsanHmida Aug 5, 2026
90025d3
scheduling: load stored flex config for minimal triggers
BelhsanHmida Aug 5, 2026
2f0b09c
docs/scheduling: describe trigger propagation
BelhsanHmida Aug 5, 2026
c783e8f
data/models: let data generators report their input and output sensors
Flix6x Aug 5, 2026
8b2cc73
data/models/forecasting: only announce a pipeline run when actually r…
Flix6x Aug 5, 2026
b37256f
cli: default the automation recurrence to daily, and reject options t…
Flix6x Aug 5, 2026
aa64afb
api/v3_0: report an automation's input and output sensors
Flix6x Aug 5, 2026
b438e8f
api/v3_0: add an endpoint for one data source
Flix6x Aug 5, 2026
17f432b
api/v3_0: regenerate the OpenAPI specs
Flix6x Aug 5, 2026
1ea8f78
ui: link an automation's details to its sensors, and make the listing…
Flix6x Aug 5, 2026
2b87d5e
ui: show a sensor's data source record and the automations feeding it
Flix6x Aug 5, 2026
1869247
tests: cover the automation and data source review follow-ups
Flix6x Aug 5, 2026
03626b4
docs: describe the automation and data source follow-ups
Flix6x Aug 5, 2026
0f8fe58
Merge the current automations branch into the review follow-ups
Flix6x Aug 5, 2026
1dccf9f
api/v3_0: regenerate the OpenAPI specs after merging
Flix6x Aug 5, 2026
9f1d075
cli: only reject configuration options that were actually given with …
Flix6x Aug 5, 2026
b397907
data/services: only consider automations that could feed a sensor
Flix6x Aug 5, 2026
318cd91
tests: follow the merged automation behaviour
Flix6x Aug 5, 2026
1eb3a50
cli: keep mypy happy about click 8 attributes
BelhsanHmida Aug 7, 2026
9653e10
cli: keep the automation help focused on the automation
BelhsanHmida Aug 7, 2026
87e07f6
data/models: count a source-filtered regressor as an input sensor
BelhsanHmida Aug 7, 2026
8860bd0
data/services: do not report no sensors when an automation's sensors …
BelhsanHmida Aug 10, 2026
2b961cc
Feat automation timezones catchup (#2396)
BelhsanHmida Aug 10, 2026
f75bb6d
Merge branch 'main' into feat/2288-automations-for-forecasts
BelhsanHmida Aug 10, 2026
1e53696
Merge the forecast automation base into the schedule automations
BelhsanHmida Aug 10, 2026
1f68beb
data/migrations: rejoin the two automation migration branches
BelhsanHmida Aug 11, 2026
a98b4fc
Merge origin/main into automation fixes
BelhsanHmida Aug 11, 2026
8eac59f
fix(data/schemas): reject cron expressions without dates
BelhsanHmida Aug 11, 2026
249642f
fix(data/services): isolate invalid recurrences and stale claims
BelhsanHmida Aug 11, 2026
bf23428
fix(api/v3_0): protect automation sensor details
BelhsanHmida Aug 11, 2026
af5957b
test(cli): cover impossible recurrence input
BelhsanHmida Aug 11, 2026
c18f7de
test(data/services): cover resilient automation claims
BelhsanHmida Aug 11, 2026
23ea45a
test(api/v3_0): cover private automation dependencies
BelhsanHmida Aug 11, 2026
a7671de
Merge reviewed forecast automation fixes
BelhsanHmida Aug 11, 2026
5af2170
fix(data/services): resolve schedule automation sensors
BelhsanHmida Aug 11, 2026
32c4970
test(data/services): cover schedule sensor resolution
BelhsanHmida Aug 11, 2026
a0a1944
test(api/v3_0): expose schedule dependency details
BelhsanHmida Aug 11, 2026
63fee6b
Merge branch 'main' into feat/2288-automations-for-forecasts
BelhsanHmida Aug 12, 2026
b8d76a9
cli: refuse forecaster options that were given, not merely ones that …
BelhsanHmida Aug 12, 2026
dd5fae6
data/models: name an automation's cursor after what it points at
Flix6x Aug 31, 2026
b3845d8
tests: follow the automation cursor rename
Flix6x Aug 31, 2026
dbf0bae
docs: explain the automation cursor, and say "run" instead of "occurr…
Flix6x Aug 31, 2026
7e1bab2
docs/changelog: give the automation API changes their own version sec…
Flix6x Aug 31, 2026
d1cd0a2
docs/changelog: restore the v3.0-32 underline to full length
Flix6x Aug 31, 2026
6474eec
data/services: address review findings on the automations service
Flix6x Sep 1, 2026
1bda4b5
data/models: index the automation asset foreign key
Flix6x Sep 1, 2026
8d8514d
api/v3_0: work out an automation's sensors once when they cannot be r…
Flix6x Sep 1, 2026
eca2520
cli: warn which automations a sensor deletion would break
Flix6x Sep 1, 2026
fc91bc4
tests: cover the sensor deletion warning, and stop depending on caplog
Flix6x Sep 1, 2026
05e059e
docs/changelog: record the sensor deletion warning
Flix6x Sep 1, 2026
6541676
Merge branch 'main' into feat/2288-automations-for-forecasts
Flix6x Sep 1, 2026
4051dc2
docs: give automations their own page
Flix6x Sep 1, 2026
208e5be
Merge branch 'feat/2288-automations-for-forecasts' into feat/2288-sch…
Flix6x Sep 1, 2026
06bf14b
data/migrations: index the automation asset FK without adding a revision
Flix6x Sep 1, 2026
170a38e
Merge remote-tracking branch 'origin/feat/2288-automations-for-foreca…
Flix6x Sep 1, 2026
7b83dfa
Merge branch 'main' into feat/2288-schedule-automations
Flix6x Sep 1, 2026
133a6e4
Merge branch 'main' into feat/2288-schedule-automations
Flix6x Sep 2, 2026
0132c63
docs: document schedule automations in the automations chapter
Flix6x Sep 2, 2026
940f22e
Name automation types after the task, like the rest of the codebase
Flix6x Sep 2, 2026
12903db
docs/changelog: move the data source inspection entry to v1.1.0
Flix6x Sep 2, 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
4 changes: 2 additions & 2 deletions documentation/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ v1.1.0 | September XX, 2026
New features
-------------

* Automations: recurring tasks defined per asset, computing forecasts or schedules, managed with new CLI commands (``flexmeasures add|edit|delete automation``), run by ``flexmeasures jobs run-automations``, and viewable in a new UI page and API endpoints (``[GET] /assets/(id)/automations``); each automation interprets its recurrence in its own timezone, and runs missed while the runner was down are caught up once, coalesced into one current forecast; a forecast automation points at a data source holding its forecaster configuration, while a schedule automation stores what the schedule trigger endpoint accepts, and schedules from each run's own time, unless the trigger message fixes a ``start``; an automation's details link to the sensors it reads from and writes to, a sensor's page lists the automations feeding it, and deleting a sensor warns about the automations that use it; jobs now also record whether they were created via the CLI, the API or an automation [see `PR #2290 <https://www.github.com/FlexMeasures/flexmeasures/pull/2290>`_, `PR #2396 <https://www.github.com/FlexMeasures/flexmeasures/pull/2396>`_ and `PR #2293 <https://www.github.com/FlexMeasures/flexmeasures/pull/2293>`_]
* In the UI, the full record of the data source selected on a sensor page can be inspected, backed by a new API endpoint (``[GET] /sources/(id)``) [see `PR #2290 <https://www.github.com/FlexMeasures/flexmeasures/pull/2290>`_]
* Changing the selected time range on an asset or sensor chart now only loads the data that is actually new, instead of reloading the whole range, which makes stepping through or extending a long period much faster; reloading the page, or leaving it open for five minutes, still fetches everything afresh [see `PR #2433 <https://www.github.com/FlexMeasures/flexmeasures/pull/2433>`_]

Infrastructure / Support
Expand Down Expand Up @@ -63,8 +65,6 @@ v1.0.0 | August 25, 2026
New features
-------------

* Automations - first roundtrip for forecasts: recurring tasks defined per asset, managed with new CLI commands (``flexmeasures add|edit|delete automation``), run by ``flexmeasures jobs run-automations``, and viewable in a new UI page and API endpoints (``[GET] /assets/(id)/automations``); each automation interprets its recurrence in its own timezone, and runs missed while the runner was down are caught up once, coalesced into one current forecast; an automation's details link to the sensors it reads from and writes to, a sensor's page lists the automations feeding it, and deleting a sensor warns about the automations that use it; jobs now also record whether they were created via the CLI, the API or an automation [see `PR #2290 <https://www.github.com/FlexMeasures/flexmeasures/pull/2290>`_ and `PR #2396 <https://www.github.com/FlexMeasures/flexmeasures/pull/2396>`_]
* In the UI, the full record of the data source selected on a sensor page can be inspected, backed by a new API endpoint (``[GET] /sources/(id)``) [see `PR #2290 <https://www.github.com/FlexMeasures/flexmeasures/pull/2290>`_]
* ``flexmeasures show data-sources`` now shows which organisation a data source belongs to, and can list the sensors holding data recorded by a given source [see `PR #2401 <https://www.github.com/FlexMeasures/flexmeasures/pull/2401>`_]
* The flex-context can now define multiple commodities, each specifying their own prices and grid capacities [see `PR #1946 <https://www.github.com/FlexMeasures/flexmeasures/pull/1946>`_, `PR #2172 <https://www.github.com/FlexMeasures/flexmeasures/pull/2172>`_, `PR #2235 <https://www.github.com/FlexMeasures/flexmeasures/pull/2235>`_, `PR #2271 <https://www.github.com/FlexMeasures/flexmeasures/pull/2271>`_, `PR #2355 <https://www.github.com/FlexMeasures/flexmeasures/pull/2355>`_ and `PR #2380 <https://www.github.com/FlexMeasures/flexmeasures/pull/2380>`_]
* Support multiple feeders to a shared storage [see `PR #2001 <https://www.github.com/FlexMeasures/flexmeasures/pull/2001>`_, `PR #2321 <https://www.github.com/FlexMeasures/flexmeasures/pull/2321>`_, `PR #2322 <https://www.github.com/FlexMeasures/flexmeasures/pull/2322>`_, `PR #2325 <https://www.github.com/FlexMeasures/flexmeasures/pull/2325>`_ and `PR #2431 <https://www.github.com/FlexMeasures/flexmeasures/pull/2431>`_]
Expand Down
2 changes: 1 addition & 1 deletion documentation/cli/change_log.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ since v1.0.0 | August 11, 2026
* Add ``flexmeasures add plan``, ``flexmeasures show plans`` and ``flexmeasures edit plan``, to manage the rate limits and quotas which apply to the accounts on a plan.
* Add ``flexmeasures edit secret`` to store an encrypted secret on an account or asset.
* Add ``flexmeasures delete secret`` to remove an encrypted secret from an account or asset.
* Add ``flexmeasures add automation``, ``flexmeasures edit automation`` and ``flexmeasures delete automation`` to manage automations (recurring tasks on an asset; for now, computing forecasts). Each automation carries its own IANA timezone (``--timezone``), in which its cron expression is interpreted.
* Add ``flexmeasures add automation``, ``flexmeasures edit automation`` and ``flexmeasures delete automation`` to manage automations (recurring tasks on an asset, with ``--type forecasting`` or ``--type scheduling`` saying which task to automate). Each automation carries its own IANA timezone (``--timezone``), in which its cron expression is interpreted.
* Add ``flexmeasures jobs run-automations`` to queue jobs for all automations that are due to run this minute from standard five-field cron expressions. Run this command once per minute. It makes at most one queueing attempt per automation per minute, including when an attempt fails after partially queueing jobs. Runs missed while the runner was down are caught up once, with several missed forecast runs coalesced into the latest useful forecast, and a run at a skipped or repeated daylight-saving-time hour happens exactly once.
* ``flexmeasures delete sensor`` now warns which automations read from or write to a sensor before it is deleted, as an automation refers to its sensors by ID and would fail on its next run.
* ``flexmeasures show data-sources`` now shows the account a data source belongs to, and lists the sensors holding data recorded by a single source with ``--show-sensors``.
Expand Down
2 changes: 1 addition & 1 deletion documentation/cli/commands.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ of which some are referred to in this documentation.
``flexmeasures add annotation`` Add annotation to accounts, assets and/or sensors.
``flexmeasures add toy-account`` Create a toy account, for tutorials and trying things.
``flexmeasures add report`` Create a report.
``flexmeasures add automation`` Add an automation with its own cron timezone.
``flexmeasures add automation`` Add an automation: a recurring task (computing forecasts or schedules) on an asset, with its own cron timezone.
================================================= =======================================


Expand Down
33 changes: 27 additions & 6 deletions documentation/features/automations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ Automations
============

An **automation** is a recurring task defined on an asset.
For now, an automation computes forecasts; automating schedules and reports is planned.
For now, an automation computes forecasts or schedules; automating reports is planned.

On each run, the automation queues jobs (so make sure a worker is processing the ``forecasting`` queue, see :ref:`redis-queue`).
On each run, the automation queues jobs (so make sure a worker is processing the ``forecasting`` or ``scheduling`` queue, whichever the automation needs, see :ref:`redis-queue`).
The parameters of the task were stored when the automation was created, and validated with the same schema that the CLI and API use.
Timing parameters are resolved on each run — for instance, the forecast start defaults to the time the automation runs, so each run produces fresh forecasts.
Timing parameters are resolved on each run — for instance, the forecast or schedule start defaults to the time the automation runs, so each run produces fresh results.

Creating an automation
----------------------
Expand All @@ -17,10 +17,10 @@ Here is how you create an automation in the CLI, asking for daily (at 6 AM) fore

.. code-block:: bash

flexmeasures add automation --asset 3 --name "Daily PV forecasts" --type forecasts \
flexmeasures add automation --asset 3 --name "Daily PV forecasts" --type forecasting \
--cron "0 6 * * *" --timezone Europe/Amsterdam --sensor 12

``--type`` says what the automation computes, and defaults to ``forecasts``.
``--type`` says which task to automate (``forecasting`` or ``scheduling``, matching the queue the jobs go to), and defaults to ``forecasting``.
The remaining options are the ones the task itself needs: a forecast automation accepts everything `flexmeasures add forecast` accepts, such as ``--forecaster`` to pick the forecaster and ``--config`` to configure it (see :ref:`forecasting`).
The forecaster and its configuration are stored on a data source, so you can also pass ``--source`` to reuse the data source of an existing forecaster, in which case ``--forecaster`` and ``--config`` (and the individual configuration options) are not needed — the data source already determines them.
That data source is required while the automation exists, so it cannot be deleted until the automation is removed.
Expand All @@ -38,6 +38,27 @@ These changes are recorded in the asset's audit log.
For forecast automations, the sensor on which forecasts are saved (``sensor-to-save``, falling back to ``sensor``) must belong to the automation's asset or one of its descendants.
This relationship is checked both when the automation is created and immediately before each run.

Automating schedules
--------------------

A schedule automation's parameters form a schedule trigger message, as accepted by the `[POST] /assets/(id)/schedules/trigger <../api/v3_0.html#post--api-v3_0-assets-id-schedules-trigger>`_ API endpoint (without the asset id).
Use the canonical API field names, including ``flex-model``, ``flex-context`` and ``force-new-job-creation``.
The message is passed in a file, through ``--parameters``, and validated when the automation is created.
No forecaster or data source is involved, so the forecaster options above do not apply to a schedule automation, and are refused when combined with ``--type scheduling``.

Omit the ``start`` field to calculate it afresh from the server time on each run.
It is floored to the fixed, positive ``resolution`` when given, or otherwise to the minute.
A fixed ``start`` is accepted, but every run then schedules the same period and the CLI warns about this when creating the automation.
The ``duration`` must be positive; ``resolution`` does not accept nominal durations such as a month.
As usual, the flex-context and flex-model can also (partly) live on the asset itself, in which case a minimal trigger message suffices.

For example, this automation queues a scheduling job every hour, each time scheduling the next 12 hours:

.. code-block:: bash

echo 'duration: "PT12H"' > trigger-message.yml
flexmeasures add automation --asset 3 --name "Hourly schedules" --cron "0 * * * *" --type scheduling --parameters trigger-message.yml

Running automations
-------------------

Expand All @@ -49,7 +70,7 @@ For automations to actually run, let a cron job execute the following command on

Each due automation then queues its jobs.
If the runner misses runs, because it was down or overloaded, it catches up when it resumes: it queues only the latest missed run of each automation, rather than replaying stale ones.
Timing parameters that default to the run time are resolved when that catch-up run is queued, so it produces a current forecast.
Timing parameters that default to the run time are resolved when that catch-up run is queued, so it produces a current forecast or schedule.

Each scheduled run receives at most one automatic queueing attempt.
If the process crashes, or queueing fails after creating some jobs, that run is not retried automatically, because a retry could duplicate partial work.
Expand Down
1 change: 1 addition & 0 deletions documentation/features/forecasting.rst
Original file line number Diff line number Diff line change
Expand Up @@ -221,3 +221,4 @@ Automating forecasts

Instead of asking for forecasts one at a time, you can set up an *automation*: a recurring task defined on an asset, which queues forecasting jobs on a cron schedule.
See :ref:`automations`.
Schedules can be automated in the same way — see :ref:`automating_schedules`.
9 changes: 9 additions & 0 deletions documentation/features/scheduling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -368,3 +368,12 @@ Here are some thoughts on further innovation:
This is ongoing architecture design work, and therefore happens in development settings, until we are happy with the outcomes.
Thoughts welcome :)
- Aggregating flexibility of a group of assets (e.g. a neighborhood) and optimizing its aggregated usage (e.g. for grid congestion support) is also an exciting direction for expansion.


.. _automating_schedules:

Automating schedules
--------------------
Comment thread
Flix6x marked this conversation as resolved.

Instead of triggering schedules one at a time, you can set up an *automation*: a recurring task defined on an asset, which queues scheduling jobs on a cron schedule.
See :ref:`automations`.
10 changes: 6 additions & 4 deletions flexmeasures/api/v3_0/assets.py
Original file line number Diff line number Diff line change
Expand Up @@ -1388,7 +1388,7 @@ def get_automations(self, id: int, asset: GenericAsset):
get:
summary: Get all automations defined on an asset.
description: |
The response will be a list of automations: recurring tasks (for now, computing forecasts)
The response will be a list of automations: recurring forecasting or scheduling tasks
defined on the asset. Each entry shows the automation's ID, when it was created,
its type, name, activation status, and its recurrence, both as a cron string
and described in natural language. Each entry also shows the IANA timezone in which its cron expression is interpreted, and its cursor.
Expand Down Expand Up @@ -1460,8 +1460,8 @@ def get_automation(self, id: int, automation_id: int, asset: GenericAsset):
summary: Get details of one automation defined on an asset.
description: |
In addition to the fields shown when listing automations, the response shows
the automation's parameters (for forecasts, these are the forecast parameters
used on each run), information about the data generator that runs it,
the automation's parameters (forecast parameters or a schedule trigger message),
information about its data generator (null for schedule automations),
the sensors it reads from and writes to,
and counts of recently created jobs, per job status.
Note that jobs in Redis have a limited TTL, so not all past jobs will be counted.
Expand Down Expand Up @@ -1982,10 +1982,11 @@ def trigger_schedule(
start=start_of_schedule,
end=end_of_schedule,
belief_time=belief_time, # server time if no prior time was sent
resolution=resolution,
flex_model=flex_model,
flex_context=flex_context,
)
if resolution is not None:
scheduler_kwargs["resolution"] = resolution
if sequential:
f = create_sequential_scheduling_job
else:
Expand All @@ -1995,6 +1996,7 @@ def trigger_schedule(
asset=asset,
enqueue=True,
force_new_job_creation=force_new_job_creation,
trigger={"origin": "API"},
**scheduler_kwargs,
)
except ValidationError as err:
Expand Down
1 change: 1 addition & 0 deletions flexmeasures/api/v3_0/sensors.py
Original file line number Diff line number Diff line change
Expand Up @@ -1078,6 +1078,7 @@ def trigger_schedule(
**scheduler_kwargs,
enqueue=True,
force_new_job_creation=force_new_job_creation,
trigger={"origin": "API"},
)
except ValidationError as err:
return unprocessable_entity(err.messages)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def test_asset_jobs_redact_inaccessible_automation_provenance(
asset=source_asset,
generator=generator,
name="Confidential source automation",
type="forecasts",
type="forecasting",
cronstr="0 6 * * *",
parameters={"sensor": target_sensor.id},
)
Expand Down
4 changes: 4 additions & 0 deletions flexmeasures/api/v3_0/tests/test_asset_schedules_fresh_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ def test_asset_trigger_and_get_schedule(
), "the whole scheduling job is handled as a single job (simultaneous scheduling)"
done_job_id = scheduled_jobs[0].id
scheduling_job = scheduled_jobs[0]
assert all(
job.meta["trigger"] == {"origin": "API"}
for job in [*scheduled_jobs, *deferred_jobs]
)

print(scheduling_job.kwargs)
if sequential:
Expand Down
6 changes: 3 additions & 3 deletions flexmeasures/api/v3_0/tests/test_automations_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def add_automations(db, add_battery_assets):
Automation(
asset_id=battery.id,
generator=generator,
type="forecasts",
type="forecasting",
name="Day-ahead forecasts",
cronstr="0 6 * * *",
timezone="Europe/Amsterdam",
Expand All @@ -34,7 +34,7 @@ def add_automations(db, add_battery_assets):
Automation(
asset_id=battery.id,
generator=generator,
type="forecasts",
type="forecasting",
name="Intraday forecasts",
cronstr="0 * * * *",
timezone="UTC",
Expand Down Expand Up @@ -90,7 +90,7 @@ def test_get_automations(
automations = response.json["automations"]
assert len(automations) == 2
day_ahead = next(a for a in automations if a["name"] == "Day-ahead forecasts")
assert day_ahead["type"] == "forecasts"
assert day_ahead["type"] == "forecasting"
assert day_ahead["cronstr"] == "0 6 * * *"
assert day_ahead["timezone"] == "Europe/Amsterdam"
assert day_ahead["cursor"] == "2026-07-11T04:00:00+00:00"
Expand Down
65 changes: 64 additions & 1 deletion flexmeasures/api/v3_0/tests/test_automations_api_fresh_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def test_details_reject_inaccessible_sensor_metadata(
automation = Automation(
asset=prosumer_asset,
generator=generator,
type="forecasts",
type="forecasting",
name="Cross-organisation details",
cronstr="0 6 * * *",
parameters={"sensor": output_sensor.id},
Expand All @@ -67,3 +67,66 @@ def test_details_reject_inaccessible_sensor_metadata(

assert response.status_code == 403
assert hidden_sensor.name not in response.text


@pytest.mark.parametrize(
"requesting_user", ["test_prosumer_user@seita.nl"], indirect=True
)
def test_schedule_details_include_stored_flex_sensors(
client,
fresh_db,
setup_roles_users_fresh_db,
setup_generic_assets_fresh_db,
requesting_user,
):
asset = setup_generic_assets_fresh_db["test_battery"]
power_sensor = Sensor(
name="scheduled power",
unit="MW",
event_resolution=timedelta(minutes=15),
generic_asset=asset,
)
price_sensor = Sensor(
name="schedule price",
unit="EUR/MWh",
event_resolution=timedelta(hours=1),
generic_asset=asset,
)
fresh_db.session.add_all([power_sensor, price_sensor])
fresh_db.session.flush()
asset.flex_model = {
"consumption": {"sensor": power_sensor.id},
"soc-at-start": "2.5 MWh",
"soc-min": "0 MWh",
"soc-max": "5 MWh",
"power-capacity": "2 MW",
}
asset.flex_context = {
"site-power-capacity": "2 MVA",
"consumption-price": {"sensor": price_sensor.id},
}
automation = Automation(
asset=asset,
type="scheduling",
name="Minimal schedule details",
cronstr="0 6 * * *",
parameters={"duration": "PT1H"},
)
fresh_db.session.add(automation)
fresh_db.session.commit()

response = client.get(
url_for(
"AssetAPI:get_automation",
id=asset.id,
automation_id=automation.id,
)
)

assert response.status_code == 200
assert response.json["input_sensors"] == [
{"id": price_sensor.id, "name": price_sensor.name}
]
assert response.json["output_sensors"] == [
{"id": power_sensor.id, "name": power_sensor.name}
]
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ def test_trigger_and_get_schedule(
len(app.queues["scheduling"]) == 1
) # only 1 schedule should be made for 1 asset
job = app.queues["scheduling"].jobs[0]
assert job.meta["trigger"] == {"origin": "API"}
print(job.kwargs)
assert job.kwargs["asset_or_sensor"]["id"] == sensor.id
assert job.kwargs["start"] == parse_datetime(message["start"])
Expand Down
Loading
Loading