Files
EOS/docs/_generated/configpvforecast.md
T
7bafc8d02d feat: add PVForecastHomeAssistant provider (#1258)
* feat: add PVForecastHomeAssistant provider

Reads a PV forecast time series directly from a Home Assistant entity
attribute (matching the {"forecast": [{"datetime", "watts"}]} shape
already exposed by common HA PV forecast integrations, e.g. Helios
Forecast and Solcast) and feeds it into pvforecast_ac_power, following
the same self-polling provider pattern as PVForecastVrm.

Closes #1232.

* fix: use MagicMock instead of monkeypatched Response for mypy

requests.Response().json is a typed bound method; reassigning it to a
lambda fails mypy's method-assign check. Use MagicMock(spec=...) instead,
which mocks the response without fighting its static type.

* fix: address PR review on PVForecastHomeAssistant provider

Fixes two issues raised in review on PR #1258:
- _update_data() left stale pvforecast_ac_power values in place when a
  refreshed forecast was empty or shorter than a previous one; it now
  clears the active forecast window before writing and raises instead
  of silently no-op'ing when the response has no usable data.
- pvforecast.homeassistant.entity_id used a "select" widget with no
  manual-entry fallback in EOSdash, leaving it unusable in standalone
  mode where the entity list can't be resolved without SUPERVISOR_TOKEN;
  switched to a plain text field.

Also fills in the config docs and openapi.json for the new
pvforecast.homeassistant.* fields, which were missing from the
original commit.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix: preserve retained forecast history when clearing stale entries

The previous fix cleared pvforecast_ac_power from start-of-day, but
PredictionProvider deliberately retains historical records back to
keep_datetime (prediction.historic_hours). Since Home Assistant
forecasts are future-only, that clear wiped out retained history
between midnight and the EMS start on every refresh.

Narrow the clear to [ems_start_datetime, end_datetime) - the actual
active forecast window, DST-adjusted - instead of the day boundary.

Addresses review feedback from @NormannK on PR #1258.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Mathias <mathias@Mathiass-MacBook-Air.local>
Co-authored-by: Mathias <mathias@Mathiass-Air.localdomain>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 00:15:40 +02:00

18 KiB

PV Forecast Configuration

:::{table} pvforecast :widths: 10 20 10 5 5 30 :align: left

Name Environment Variable Type Read-Only Default Description
forecastsolar EOS_PVFORECAST__FORECASTSOLAR PVForecastForecastSolarCommonSettings rw required ForecastSolar provider settings
homeassistant EOS_PVFORECAST__HOMEASSISTANT PVForecastHomeAssistantCommonSettings rw required Home Assistant provider settings
max_planes EOS_PVFORECAST__MAX_PLANES `int None` rw 0
planes EOS_PVFORECAST__PLANES `list[akkudoktoreos.prediction.pvforecast.PVForecastPlaneSetting] None` rw None
planes_azimuth List[float] ro N/A Compute a list of the azimuths per active planes.
planes_inverter_paco Any ro N/A Compute a list of the maximum power rating of the inverter per active planes.
planes_peakpower List[float] ro N/A Compute a list of the peak power per active planes.
planes_tilt List[float] ro N/A Compute a list of the tilts per active planes.
planes_userhorizon Any ro N/A Compute a list of the user horizon per active planes.
provider EOS_PVFORECAST__PROVIDER `str None` rw None
providers list[str] ro N/A Available PVForecast provider ids.
pvforecastimport EOS_PVFORECAST__PVFORECASTIMPORT PVForecastImportCommonSettings rw required PV forecast import provider settings
pvlib EOS_PVFORECAST__PVLIB PVForecastPVLibCommonSettings rw required PVLib provider settings
pvnode EOS_PVFORECAST__PVNODE PVForecastPVNodeCommonSettings rw required PVNode provider settings
solcast EOS_PVFORECAST__SOLCAST PVForecastSolcastCommonSettings rw required Solcast provider settings
vrm EOS_PVFORECAST__VRM PVForecastVrmCommonSettings rw required Victron Remote Management (VRM) provider settings
:::

Example Input

   {
       "pvforecast": {
           "provider": "PVForecastAkkudoktor",
           "pvforecastimport": {
               "import_file_path": null,
               "import_json": null
           },
           "vrm": {
               "token": "your-token",
               "site_id": 12345
           },
           "homeassistant": {
               "entity_id": "sensor.pv_forecast",
               "attribute": "forecast",
               "datetime_key": "datetime",
               "value_key": "watts",
               "value_unit": "W",
               "base_url": null,
               "token": null
           },
           "pvlib": {},
           "pvnode": {
               "api_key": "",
               "site_id": null,
               "forecast_days": 2
           },
           "forecastsolar": {
               "api_key": null
           },
           "solcast": {
               "api_key": "",
               "site_id": ""
           },
           "planes": [
               {
                   "surface_tilt": 10.0,
                   "surface_azimuth": 180.0,
                   "userhorizon": [
                       10.0,
                       20.0,
                       30.0
                   ],
                   "peakpower": 5.0,
                   "pvtechchoice": "crystSi",
                   "mountingplace": "free",
                   "loss": 14.0,
                   "trackingtype": 0,
                   "optimal_surface_tilt": false,
                   "optimalangles": false,
                   "albedo": null,
                   "module_model": null,
                   "inverter_model": null,
                   "inverter_paco": 6000,
                   "modules_per_string": 20,
                   "strings_per_inverter": 2
               },
               {
                   "surface_tilt": 20.0,
                   "surface_azimuth": 90.0,
                   "userhorizon": [
                       5.0,
                       15.0,
                       25.0
                   ],
                   "peakpower": 3.5,
                   "pvtechchoice": "crystSi",
                   "mountingplace": "free",
                   "loss": 14.0,
                   "trackingtype": 1,
                   "optimal_surface_tilt": false,
                   "optimalangles": false,
                   "albedo": null,
                   "module_model": null,
                   "inverter_model": null,
                   "inverter_paco": 4000,
                   "modules_per_string": 20,
                   "strings_per_inverter": 2
               }
           ],
           "max_planes": 1
       }
   }

Example Output

   {
       "pvforecast": {
           "provider": "PVForecastAkkudoktor",
           "pvforecastimport": {
               "import_file_path": null,
               "import_json": null
           },
           "vrm": {
               "token": "your-token",
               "site_id": 12345
           },
           "homeassistant": {
               "entity_id": "sensor.pv_forecast",
               "attribute": "forecast",
               "datetime_key": "datetime",
               "value_key": "watts",
               "value_unit": "W",
               "base_url": null,
               "token": null
           },
           "pvlib": {},
           "pvnode": {
               "api_key": "",
               "site_id": null,
               "forecast_days": 2
           },
           "forecastsolar": {
               "api_key": null
           },
           "solcast": {
               "api_key": "",
               "site_id": ""
           },
           "planes": [
               {
                   "surface_tilt": 10.0,
                   "surface_azimuth": 180.0,
                   "userhorizon": [
                       10.0,
                       20.0,
                       30.0
                   ],
                   "peakpower": 5.0,
                   "pvtechchoice": "crystSi",
                   "mountingplace": "free",
                   "loss": 14.0,
                   "trackingtype": 0,
                   "optimal_surface_tilt": false,
                   "optimalangles": false,
                   "albedo": null,
                   "module_model": null,
                   "inverter_model": null,
                   "inverter_paco": 6000,
                   "modules_per_string": 20,
                   "strings_per_inverter": 2
               },
               {
                   "surface_tilt": 20.0,
                   "surface_azimuth": 90.0,
                   "userhorizon": [
                       5.0,
                       15.0,
                       25.0
                   ],
                   "peakpower": 3.5,
                   "pvtechchoice": "crystSi",
                   "mountingplace": "free",
                   "loss": 14.0,
                   "trackingtype": 1,
                   "optimal_surface_tilt": false,
                   "optimalangles": false,
                   "albedo": null,
                   "module_model": null,
                   "inverter_model": null,
                   "inverter_paco": 4000,
                   "modules_per_string": 20,
                   "strings_per_inverter": 2
               }
           ],
           "max_planes": 1,
           "providers": [
               "PVForecastAkkudoktor",
               "PVForecastForecastSolar",
               "PVForecastImport",
               "PVForecastPVLib",
               "PVForecastPVNode",
               "PVForecastSolcast",
               "PVForecastVrm"
           ],
           "planes_peakpower": [
               5.0,
               3.5
           ],
           "planes_azimuth": [
               180.0,
               90.0
           ],
           "planes_tilt": [
               10.0,
               20.0
           ],
           "planes_userhorizon": [
               [
                   10.0,
                   20.0,
                   30.0
               ],
               [
                   5.0,
                   15.0,
                   25.0
               ]
           ],
           "planes_inverter_paco": [
               6000.0,
               4000.0
           ]
       }
   }

Common settings for PV forecast VRM API

:::{table} pvforecast::vrm :widths: 10 10 5 5 30 :align: left

Name Type Read-Only Default Description
site_id int rw 12345 VRM-Installation-ID
token str rw your-token Access token for connecting to the Victron Remote Management (VRM) API
:::

Example Input/Output

   {
       "pvforecast": {
           "vrm": {
               "token": "your-token",
               "site_id": 12345
           }
       }
   }

Common settings for pvforecast data from a Home Assistant entity

:::{table} pvforecast::homeassistant :widths: 10 10 5 5 30 :align: left

Name Type Read-Only Default Description
entity_id str rw sensor.pv_forecast Home Assistant entity providing the PV forecast.
attribute str rw forecast Entity attribute holding the forecast list.
datetime_key str rw datetime Key for the timestamp in each forecast entry.
value_key str rw watts Key for the AC power value in each forecast entry.
value_unit Literal['W', 'kW'] rw W Unit of the forecast value. Converted to W internally.
base_url `str None` rw None
token `str None` rw None
:::

Example Input/Output

   {
       "pvforecast": {
           "homeassistant": {
               "entity_id": "sensor.pv_forecast",
               "attribute": "forecast",
               "datetime_key": "datetime",
               "value_key": "watts",
               "value_unit": "W",
               "base_url": null,
               "token": null
           }
       }
   }

Common settings for the Solcast PV forecast provider

:::{table} pvforecast::solcast :widths: 10 10 5 5 30 :align: left

Name Type Read-Only Default Description
api_key str rw `` Solcast API key (Bearer auth). Required.
site_id str rw `` Solcast rooftop site (resource) id. Required.
:::

Example Input/Output

   {
       "pvforecast": {
           "solcast": {
               "api_key": "your-solcast-key",
               "site_id": "abcd-1234-efgh-5678"
           }
       }
   }

Common settings for the pvnode.com PV forecast provider

:::{table} pvforecast::pvnode :widths: 10 10 5 5 30 :align: left

Name Type Read-Only Default Description
api_key str rw `` pvnode.com API key (Bearer auth). Required.
forecast_days int rw 2 Forecast horizon in days (1-7, capped by the pvnode plan).
site_id `str None` rw None
:::

Example Input/Output

   {
       "pvforecast": {
           "pvnode": {
               "api_key": "pvn_live_xxxxxxxxxxxxxxxx",
               "site_id": "abcd-1234",
               "forecast_days": 2
           }
       }
   }

Common settings for pvforecast data calculation with PVLib

:::{table} pvforecast::pvlib :widths: 10 10 5 5 30 :align: left

Name Type Read-Only Default Description
:::

Example Input/Output

   {
       "pvforecast": {
           "pvlib": {}
       }
   }

Common settings for pvforecast data import from file or JSON string

:::{table} pvforecast::pvforecastimport :widths: 10 10 5 5 30 :align: left

Name Type Read-Only Default Description
import_file_path `str pathlib.Path None` rw
import_json `str None` rw None
:::

Example Input/Output

   {
       "pvforecast": {
           "pvforecastimport": {
               "import_file_path": null,
               "import_json": "{\"pvforecast_ac_power\": [0, 8.05, 352.91]}"
           }
       }
   }

PV Forecast Plane Configuration

:::{table} pvforecast::planes::list :widths: 10 10 5 5 30 :align: left

Name Type Read-Only Default Description
albedo `float None` rw 0.2
inverter_model `str None` rw None
inverter_paco `int None` rw None
loss `float None` rw 14.0
module_model `str None` rw None
modules_per_string `int None` rw None
mountingplace `str None` rw building
optimal_surface_tilt `bool None` rw False
optimalangles `bool None` rw False
peakpower `float None` rw None
pvtechchoice `str None` rw crystSi
strings_per_inverter `int None` rw None
surface_azimuth `float None` rw 180.0
surface_tilt `float None` rw 30.0
trackingtype `int None` rw None
userhorizon `List[float] None` rw None
:::

Example Input/Output

   {
       "pvforecast": {
           "planes": [
               {
                   "surface_tilt": 10.0,
                   "surface_azimuth": 180.0,
                   "userhorizon": [
                       10.0,
                       20.0,
                       30.0
                   ],
                   "peakpower": 5.0,
                   "pvtechchoice": "crystSi",
                   "mountingplace": "building",
                   "loss": 14.0,
                   "trackingtype": 0,
                   "optimal_surface_tilt": false,
                   "optimalangles": false,
                   "albedo": null,
                   "module_model": null,
                   "inverter_model": null,
                   "inverter_paco": 6000,
                   "modules_per_string": 20,
                   "strings_per_inverter": 2
               }
           ]
       }
   }

Common settings for the Forecast.Solar PV forecast provider

:::{table} pvforecast::forecastsolar :widths: 10 10 5 5 30 :align: left

Name Type Read-Only Default Description
api_key `str None` rw None
:::

Example Input/Output

   {
       "pvforecast": {
           "forecastsolar": {
               "api_key": null
           }
       }
   }