- Use urllib.parse.quote instead of requests.utils.quote in the pvnode and
Solcast providers: the runtime re-export exists, but the requests type stubs
do not declare it, so the pre-commit mypy hook failed with
'Module has no attribute "quote"'.
- Mark the force_update keyword in the new provider tests with `# type: ignore`
— it is consumed by the cache_in_file decorator at runtime; same call
convention and ignore style as pvforecastakkudoktor.py.
- Add PVForecastPVNode, PVForecastForecastSolar and PVForecastSolcast to the
expected provider sequence in tests/test_prediction.py (fixture + index
assertions) — the two sequence tests failed because the new providers were
registered in prediction.py but missing from the hardcoded expectations.
Add PVForecastPVNode, a native 15-minute PV forecast provider for the
pvnode.com V2 API, giving operators another forecast source to choose from
alongside Akkudoktor, VRM and Import.
Two request modes, selected by configuration:
* site_id set -> GET /v2/forecast/{site_id} (a saved, possibly calibrated
site managed on pvnode.com — the operator enters site id + API key)
* site_id empty -> POST /v2/forecast/inline (geometry sent inline from the
configured pvforecast.planes; no web-app setup required)
V2 response timestamps are site-local wall-clock accompanied by an IANA
timezone; they are resolved to absolute instants before EOS resamples them.
Nullable pv_power (e.g. at night) is treated as 0 W so the optimizer's linear
resampling does not interpolate phantom production across the night.
Registered in pvforecast.py (provider settings + id list) and prediction.py
(singleton, factory list, container union). Adds tests covering timezone
resolution, null handling, both request modes and HTTP-error propagation.