diff --git a/docs/forecasts.md b/docs/forecasts.md index 945d721e..1067a7f5 100644 --- a/docs/forecasts.md +++ b/docs/forecasts.md @@ -204,6 +204,165 @@ curl -i -H "Content-Type: application/json" -X POST -d '{"pv_power_forecast":[0, You need to be careful here to send the correct amount of data on this list, the correct length. For example, if the data time step is defined as 1 hour and you are performing a day-ahead optimization, then this list length should be 24 data points. + ### Understanding forecast data formats: List vs Dictionary + + EMHASS supports two formats for passing forecast data as runtime parameters: **list format** and **dictionary format + with timestamps**. Understanding when to use each format can significantly simplify your Home Assistant automations. + + #### List Format (Traditional) + + The list format passes forecast values as a simple array. This is the most compact format but requires careful + attention to timing and data length. + + **Requirements:** + - The list must contain values for the **current time period first**, followed by future values + - The list length must match your prediction horizon based on `optimization_time_step` + - Values must be in the correct order (chronological) + + **Example:** + ```bash + curl -i -H "Content-Type: application/json" -X POST -d '{ + "load_cost_forecast": [0.25, 0.24, 0.23, 0.26, 0.28, ...], + "prediction_horizon": 24, + "optimization_time_step": 60 + }' http://localhost:5000/action/dayahead-optim +``` + For a 24-hour forecast with 1-hour intervals, you need exactly 24 values starting from the current hour. + + When to use list format: + - Your forecast data is already aligned with EMHASS intervals + - You want minimal JSON payload size + - You generate forecast values programmatically in the correct interval + + Dictionary Format with Timestamps (Recommended for most users) + + The dictionary format allows you to pass forecast values with explicit timestamps. EMHASS will automatically handle + resampling, alignment, and gap filling. + + Advantages: + - Automatic resampling: If your data is hourly but EMHASS runs at 15-minute intervals, resampling happens + automatically + - Flexible timing: No need to calculate exact list length or worry about current time alignment + - Self-documenting: Timestamps make it clear which value applies when + - Automatic gap filling: Missing timestamps are filled using forward-fill and backward-fill + - Timezone aware: Timestamps are parsed and converted to your configured timezone + + Format: + { + "load_cost_forecast": { + "2025-10-16 10:00:00+00:00": 0.25, + "2025-10-16 11:00:00+00:00": 0.28, + "2025-10-16 12:00:00+00:00": 0.23, + ... + } + } + + Example curl command: + curl -i -H "Content-Type: application/json" -X POST -d '{ + "load_cost_forecast": { + "2025-10-16 10:00:00+00:00": 0.25, + "2025-10-16 11:00:00+00:00": 0.28, + "2025-10-16 12:00:00+00:00": 0.23 + }, + "prediction_horizon": 48, + "optimization_time_step": 15 + }' http://localhost:5000/action/naive-mpc-optim + + What happens internally: + 1. Timestamps are parsed as ISO8601 format with timezone + 2. Data is resampled to match your optimization_time_step (e.g., from 1h to 15min intervals) + 3. Values are aligned with the forecast horizon using nearest-neighbor interpolation + 4. Any missing values are filled using forward-fill then backward-fill + 5. The result is converted to a list for the optimizer + + When to use dictionary format: + - Your price data comes from an API (Nordpool, ENTSO-E, Amber, etc.) that provides hourly prices + - You want EMHASS to handle interval conversion automatically + - Your optimization_time_step differs from your data resolution + - You want more readable and maintainable Home Assistant templates + + Practical Home Assistant Examples + + Dictionary format with Nordpool (Simple - Recommended!): + ``` + shell_command: + emhass_dayahead_nordpool: > + curl -i -H "Content-Type: application/json" -X POST -d '{ + "load_cost_forecast": {{ state_attr("sensor.nordpool_kwh_be_eur_3_10_025", "raw_today") | tojson }}, + "prod_price_forecast": {{ state_attr("sensor.nordpool_kwh_be_eur_3_10_025", "raw_today") | tojson }} + }' http://localhost:5000/action/dayahead-optim + ``` + The Nordpool integration already provides data in dictionary format with timestamps, so you can pass it directly using + | tojson! + + List format with Nordpool (Traditional - More Complex): + ``` + shell_command: + emhass_dayahead_nordpool_list: > + curl -i -H "Content-Type: application/json" -X POST -d '{ + "load_cost_forecast": {{( + ([states("sensor.nordpool_kwh_be_eur_3_10_025")|float(0)] + + state_attr("sensor.nordpool_kwh_be_eur_3_10_025", "raw_today") | map(attribute="value") | list + + state_attr("sensor.nordpool_kwh_be_eur_3_10_025", "raw_tomorrow") | map(attribute="value") | list) + [now().hour:][:24] + )}} + }' http://localhost:5000/action/dayahead-optim + ``` + + Notice how the list format requires: + - Adding the current hour value first [states("sensor.nordpool...")] + - Extracting values from dictionaries map(attribute="value") + - Slicing from current hour [now().hour:] + - Limiting to the correct length [:24] + + Dictionary format handles all of this automatically! + + Important Notes + + Timezone handling: + - Timestamps should include timezone information (e.g., +00:00 for UTC, +02:00 for CEST) + - EMHASS will convert timestamps to your configured timezone from secrets_emhass.yaml + - If timestamps don't include timezone, they're assumed to be in your local timezone + + Data resolution: + - Dictionary format works best when your source data is at a coarser resolution than your optimization_time_step + - Example: Hourly price data automatically resampled to 15-minute intervals + - The resampling uses "nearest neighbor" method, so hourly prices are held constant for all 15-minute intervals within + that hour + + Current values: + - When using list format, the first value in the list must be the current period + - Example: If it's 14:30 and your intervals are 30 minutes, the first value should be for 14:30-15:00 + - Dictionary format automatically handles this by using timestamps + + Mixing formats: + - You can use list format for some forecasts and dictionary format for others in the same API call + - Example: pv_power_forecast as list, load_cost_forecast as dictionary + + curl -i -H "Content-Type: application/json" -X POST -d '{ + "pv_power_forecast": [0, 0, 50, 150, 300, ...], + "load_cost_forecast": { + "2025-10-16 10:00:00+00:00": 0.25, + "2025-10-16 11:00:00+00:00": 0.28 + } + }' http://localhost:5000/action/naive-mpc-optim + + Summary: Which Format Should I Use? + + | Scenario | Recommended Format | Reason | + |--------------------------------------------------|--------------------|----------------------------------| + | Using Nordpool/ENTSO-E/Amber price APIs | Dictionary | Data already includes timestamps | + | Data from Home Assistant sensors with attributes | Dictionary | Easier template syntax | + | Hourly data with 15-min optimization intervals | Dictionary | Automatic resampling | + | Self-generated forecast in Python/Node-RED | Either | Choose based on convenience | + | Minimal network payload needed | List | More compact JSON | + | Generated forecast already matches intervals | List | No conversion needed | + + For most Home Assistant users: Use dictionary format with timestamps for simpler, more maintainable automations. + + + --- + ### Example using: Solcast forecast + Amber prices If you're using Solcast then you can define the following sensors in your system: