|
| 1 | +.. _forecasting: |
| 2 | + |
| 3 | +Forecasting |
| 4 | +=========== |
| 5 | + |
| 6 | +The FlexMeasures Client supports the forecasting API endpoints introduced in |
| 7 | +FlexMeasures v0.31.0: |
| 8 | + |
| 9 | +- ``POST /sensors/<id>/forecasts/trigger`` — queue a forecasting job |
| 10 | +- ``GET /sensors/<id>/forecasts/<uuid>`` — poll for results |
| 11 | + |
| 12 | +These are exposed through three client methods: |
| 13 | + |
| 14 | +- :meth:`trigger_forecast` — trigger and return the job UUID |
| 15 | +- :meth:`get_forecast` — poll until results are ready |
| 16 | +- :meth:`trigger_and_get_forecast` — convenience wrapper for both |
| 17 | + |
| 18 | +.. note:: |
| 19 | + |
| 20 | + These endpoints require a FlexMeasures server of version **0.31.0** or above. |
| 21 | + |
| 22 | + |
| 23 | +Basic example |
| 24 | +------------- |
| 25 | + |
| 26 | +Forecast the next 24 hours for a sensor, using server-side defaults for the |
| 27 | +training window: |
| 28 | + |
| 29 | +.. code-block:: python |
| 30 | +
|
| 31 | + import asyncio |
| 32 | + from flexmeasures_client import FlexMeasuresClient |
| 33 | +
|
| 34 | + async def main(): |
| 35 | + client = FlexMeasuresClient( |
| 36 | + host="localhost:5000", |
| 37 | + ssl=False, |
| 38 | + email="user@example.com", |
| 39 | + password="password", |
| 40 | + ) |
| 41 | +
|
| 42 | + forecast = await client.trigger_and_get_forecast( |
| 43 | + sensor_id=1, |
| 44 | + duration="PT24H", |
| 45 | + ) |
| 46 | + print(forecast) |
| 47 | + # e.g. {"values": [1.2, 1.5, 1.8, ...], "start": "...", "duration": "PT24H", "unit": "kW"} |
| 48 | +
|
| 49 | + await client.close() |
| 50 | +
|
| 51 | + asyncio.run(main()) |
| 52 | +
|
| 53 | +
|
| 54 | +Specifying a forecast window |
| 55 | +----------------------------- |
| 56 | + |
| 57 | +Use ``start`` and ``end`` (or ``start`` and ``duration``) to define the exact |
| 58 | +period to forecast: |
| 59 | + |
| 60 | +.. code-block:: python |
| 61 | +
|
| 62 | + forecast = await client.trigger_and_get_forecast( |
| 63 | + sensor_id=1, |
| 64 | + start="2025-01-15T00:00:00+01:00", |
| 65 | + end="2025-01-17T00:00:00+01:00", |
| 66 | + ) |
| 67 | +
|
| 68 | +
|
| 69 | +Controlling the training window |
| 70 | +--------------------------------- |
| 71 | + |
| 72 | +Pass training parameters inside a nested structure via the ``train_start``, |
| 73 | +``train_period``, and ``retrain_frequency`` keyword arguments: |
| 74 | + |
| 75 | +.. code-block:: python |
| 76 | +
|
| 77 | + forecast = await client.trigger_and_get_forecast( |
| 78 | + sensor_id=1, |
| 79 | + start="2025-01-15T00:00:00+01:00", |
| 80 | + duration="PT48H", |
| 81 | + # Training configuration |
| 82 | + train_start="2025-01-01T00:00:00+01:00", # historical data start |
| 83 | + train_period="P14D", # use 14 days of history |
| 84 | + retrain_frequency="PT24H", # retrain every 24 h |
| 85 | + ) |
| 86 | +
|
| 87 | +
|
| 88 | +Using regressors |
| 89 | +---------------- |
| 90 | + |
| 91 | +You can improve forecast accuracy by supplying regressor sensor IDs: |
| 92 | + |
| 93 | +.. code-block:: python |
| 94 | +
|
| 95 | + forecast = await client.trigger_and_get_forecast( |
| 96 | + sensor_id=1, |
| 97 | + duration="PT24H", |
| 98 | + # Sensors whose *forecasts* matter (e.g. weather forecasts) |
| 99 | + future_regressors=[10, 11], |
| 100 | + # Sensors whose *measurements* matter (e.g. price history) |
| 101 | + past_regressors=[20], |
| 102 | + ) |
| 103 | +
|
| 104 | +
|
| 105 | +Step-by-step usage |
| 106 | +------------------- |
| 107 | + |
| 108 | +Trigger and retrieve separately to handle the job UUID yourself: |
| 109 | + |
| 110 | +.. code-block:: python |
| 111 | +
|
| 112 | + # Step 1 – enqueue the forecasting job |
| 113 | + forecast_id = await client.trigger_forecast( |
| 114 | + sensor_id=1, |
| 115 | + start="2025-01-15T00:00:00+01:00", |
| 116 | + end="2025-01-17T00:00:00+01:00", |
| 117 | + ) |
| 118 | + print(f"Job queued: {forecast_id}") |
| 119 | +
|
| 120 | + # Step 2 – poll until the job finishes |
| 121 | + forecast = await client.get_forecast( |
| 122 | + sensor_id=1, |
| 123 | + forecast_id=forecast_id, |
| 124 | + ) |
| 125 | + print(forecast) |
| 126 | +
|
| 127 | +
|
| 128 | +Polling behaviour |
| 129 | +----------------- |
| 130 | + |
| 131 | +``get_forecast`` polls the server with a ``GET`` request and returns when the |
| 132 | +server responds with HTTP 200. The polling respects the same client-level |
| 133 | +settings as scheduling: |
| 134 | + |
| 135 | +- ``polling_interval`` (default 10 s) — time between retries |
| 136 | +- ``polling_timeout`` (default 200 s) — maximum total wait time |
| 137 | +- ``max_polling_steps`` (default 10) — maximum number of poll attempts |
| 138 | + |
| 139 | +Override them at client construction time: |
| 140 | + |
| 141 | +.. code-block:: python |
| 142 | +
|
| 143 | + client = FlexMeasuresClient( |
| 144 | + ..., |
| 145 | + polling_interval=5.0, # check every 5 seconds |
| 146 | + polling_timeout=300.0, # wait up to 5 minutes |
| 147 | + ) |
0 commit comments