📈 Battery revenue with our forecast simulated:
progrunners / Price forecast / Home Assistant setup
Docs · Home Assistant

Home Assistant setup

Seven sensors from one request every 15 minutes: the price now and tomorrow’s cheapest window for your car, heat pump or home battery. Part of the Personal plan and the paid plans above it — your API key is in your account.

1. Store your key

Add your API key to secrets.yaml in your Home Assistant configuration folder:

# secrets.yaml
progrunners_key: YOUR_API_KEY

2. Add the REST sensors

Paste this into configuration.yaml, replace DE-LU with your zone code (the code shown on your zone page, for example NL, AT or IT-North) and restart Home Assistant. hours sets the length of the cheapest window, 1 to 12 hours.

# configuration.yaml
rest:
  - resource: https://progrunners.com/api/v1/summary?zone=DE-LU&hours=3
    headers:
      X-API-Key: !secret progrunners_key
    scan_interval: 900
    sensor:
      - name: "Power price now"
        unique_id: progrunners_price_now
        value_template: "{{ value_json.now.price if value_json.now else none }}"
        unit_of_measurement: "EUR/MWh"
        state_class: measurement
      - name: "Power price now ct"
        unique_id: progrunners_price_now_ct
        value_template: "{{ (value_json.now.price / 10) | round(2) if value_json.now else none }}"
        unit_of_measurement: "ct/kWh"
        state_class: measurement
      - name: "Cheapest window tomorrow"
        unique_id: progrunners_cheapest_window
        value_template: >-
          {% if value_json.cheapest_window %}{{ value_json.cheapest_window.start_local }}–{{ value_json.cheapest_window.end_local }}{% else %}unknown{% endif %}
      - name: "Next cheapest window start"
        unique_id: progrunners_next_window_start
        device_class: timestamp
        value_template: "{{ value_json.next_window.start_utc if value_json.next_window else none }}"
      - name: "Next cheapest window end"
        unique_id: progrunners_next_window_end
        device_class: timestamp
        value_template: "{{ value_json.next_window.end_utc if value_json.next_window else none }}"
      - name: "Cheapest window tomorrow average"
        unique_id: progrunners_cheapest_avg
        value_template: "{{ value_json.cheapest_window.average if value_json.cheapest_window else none }}"
        unit_of_measurement: "EUR/MWh"
      - name: "Power price tomorrow average"
        unique_id: progrunners_tomorrow_avg
        value_template: "{{ value_json.tomorrow.average }}"
        unit_of_measurement: "EUR/MWh"

Prices are wholesale day-ahead prices in EUR/MWh (Great Britain: GBP/MWh), before grid charges, taxes and your supplier’s margin. 10 EUR/MWh = 1 ct/kWh. Times: start_local and end_local are in the zone’s local time.

3. What the API returns

GET /v1/summary needs your key and returns the price of the current quarter-hour (the published auction price, or our forecast where no price is published yet), tomorrow’s minimum, maximum and average, and the cheapest window tomorrow by our forecast — or by the published prices once the auction has cleared (actual_published). Example:

{"zone": "DE-LU", "unit": "EUR/MWh", "timezone": "Europe/Berlin",
 "created": "2026-11-07T10:34:12+01:00",
 "now": {"time_utc": "2026-11-07T15:45:00Z", "price": 118.4, "actual": true},
 "tomorrow": {"date": "2026-11-08", "quarters": 96, "min": 61.2, "max": 162.9,
              "average": 104.7, "actual_published": false},
 "cheapest_window": {"hours": 3, "start_local": "02:00", "end_local": "05:00",
                     "start_utc": "2026-11-08T01:00:00Z", "end_utc": "2026-11-08T04:00:00Z",
                     "average": 63.8},
 "next_window": {"hours": 3, "start_local": "02:00", "end_local": "05:00",
                 "start_utc": "2026-11-08T01:00:00Z", "end_utc": "2026-11-08T04:00:00Z",
                 "average": 63.8}}

cheapest_window is the cheapest window within tomorrow (local time), for display. next_window is the cheapest window that starts from the current quarter-hour up to the end of tomorrow — use it in automations, because it does not jump to the next day at midnight.

For a chart of the full tomorrow, call GET /v1/forecast?zone=… — every 15 minutes with the 10–90 % range. See the API reference.

4. Use it in an automation

Charge during the next cheapest window:

automation:
  - alias: "Charge in the cheapest window"
    trigger:
      - platform: time
        at: sensor.next_cheapest_window_start
        id: "start"
      - platform: time
        at: sensor.next_cheapest_window_end
        id: "end"
    action:
      - service: "switch.turn_{{ 'on' if trigger.id == 'start' else 'off' }}"
        target:
          entity_id: switch.ev_charger

Replace switch.ev_charger with your charger, heat pump or battery switch. Entity IDs follow the sensor names; check them under Settings → Entities. The window can move when a newer forecast or the published auction prices arrive (around 13:00 CET); the sensors refresh every 15 minutes.

Prices: ENTSO-E Transparency Platform (SDAC day-ahead), GB: Elexon market index. Yearly figures: walk-forward backtest using only data available before each auction. Daily forecasts are stored with a time stamp before the 12:00 CET auction. Built 13 Nov 2026 12:50 UTC.