Add opt-in 15-minute PVPC price resolution / Resolución opcional de PVPC a 15 minutos - #14
Open
txubelaxu wants to merge 2 commits into
Open
Add opt-in 15-minute PVPC price resolution / Resolución opcional de PVPC a 15 minutos#14txubelaxu wants to merge 2 commits into
txubelaxu wants to merge 2 commits into
Conversation
Since Oct 2025 Spain's day-ahead/intraday settlement moved to 15-min
slots (BOE-A-2025-4908/5342). ESIOS indicator 1001 (used today) stays
hourly regardless; indicator 791 ("Precio medio cuarto horario final
comercializadores de referencia") is the genuinely quarter-hourly
PVPC-equivalent series.
This adds an opt-in "Fetch PVPC at 15-minute resolution" toggle,
gated behind the existing private-API token (no new credential),
selectable in the price-mode step of both config flows.
- aiopvpc/const.py: new ESIOS_PVPC_QUARTER_HOURLY = "791".
- aiopvpc/parser.py: get_daily_urls_to_download() takes an optional
per-sensor data_id override, used to swap PVPC to indicator 791.
- aiopvpc/pvpc_data.py: PVPCData gets a quarter_hourly_pvpc flag; when
set, the "current price" lookup rounds to the current 15-min bucket
instead of the top of the hour.
- aiopvpc/prices.py: the price_XXh per-hour tag attributes only tag
the top-of-hour sample in quarter-hourly mode, avoiding the
DST-duplicate-hour collision logic misfiring 4x/hour.
- sensor.py: "Current Price" and the price-series-derived attributes
(Next Price, Better Prices Ahead, ...) refresh every 15 min instead
of hourly when the option is on. Tariff/power-period attributes are
untouched (they're clock-based, not price-resolution-based).
- config_flow.py / const.py / coordinator.py: new
ATTR_QUARTER_HOURLY_PVPC option, defaulting to off.
- strings.json / translations/es.json: label for the new option.
Verified with standalone checks against the changed pure functions
(URL/indicator selection, price_XXh tagging, minute-bucket rounding)
since pytest-homeassistant-custom-component's latest available release
in this environment pins an older Home Assistant core than this
integration targets, and collection fails identically on a clean
unmodified checkout (pre-existing environment issue, unrelated to
this change).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
EN
Context
Since Oct 2025, Spain's day-ahead/intraday electricity market settles per 15-minute slot instead of hourly (BOE-A-2025-4908, BOE-A-2025-5342, ENTSO-E 15-min ISP harmonization). ESIOS indicator
1001(used today for PVPC) stays hourly regardless oftime_trunc; indicator791("Precio medio cuarto horario final comercializadores de referencia") is the genuinely quarter-hourly PVPC-equivalent series (96 values/day), confirmed against the live ESIOS API.What this adds
An opt-in "Fetch PVPC at 15-minute resolution" toggle, reusing the existing private-API token (no new credential, no new config step) — selectable in the
price_modestep of both the initial config flow and the options flow, so it's only offered once a token is already configured.When enabled:
791instead of1001.price_XXhper-hour attribute tags only pick the top-of-hour sample (avoids 4 quarter-hour values colliding into the same key — see below).Disabled by default; existing hourly-mode behavior is unchanged.
Files touched
aiopvpc/const.py: newESIOS_PVPC_QUARTER_HOURLY = "791".aiopvpc/parser.py:get_daily_urls_to_download()takes an optional per-sensordata_idoverride.aiopvpc/pvpc_data.py:PVPCDatagets aquarter_hourly_pvpcflag; the "current price" lookup rounds to the current 15-min bucket instead of the top of the hour when enabled.aiopvpc/prices.py: fixed a latent bug in_make_price_tag_attributes— with a quarter-hourly series, all 4 samples of an hour would collide into the sameprice_XXhkey, incorrectly triggering the "DST duplicate hour" disambiguation logic 4x/hour. Now only the top-of-hour sample is tagged whenquarter_hourly=True.sensor.py: added a shared_current_price_bucket()helper;_next_price_candidate()and_num_better_prices_ahead()now use it instead of a hardcoded 1-hour jump. The twoasync_track_time_changetriggers (ElecPriceSensorandupdate_on_hourattribute sensors) fire at:00/:15/:30/:45instead of just:00when the option is on.config_flow.py/const.py/coordinator.py: newATTR_QUARTER_HOURLY_PVPCoption, defaultFalse, gated behinduse_private_api.strings.json/translations/es.json: label for the new option.Testing
I don't have a PR-ready new automated test yet — happy to add one if you point me at the pattern you'd prefer (e.g. extending
test_sensor_periods.py/test_price_mode.py). What I did verify:_make_price_tag_attributesproducing exactly 24 non-collidingprice_XXhkeys from a synthetic 96-value quarter-hourly series (and unchanged behavior on a plain 24-value hourly series), and the minute→bucket rounding for all 60 minute values.python -m py_compileon every touched file.tests/suite in my environment: the latestpytest-homeassistant-custom-componentavailable there pins a Home Assistant core older thanAddConfigEntryEntitiesCallback(used insensor.py), and this fails identically on a clean, unmodified checkout — so it's a pre-existing environment limitation on my end, not something introduced by this change. If your CI runs green, that's the real signal here.I'm not on this integration's actively-tested HA version locally, so please treat this as a starting point for review rather than a finished, CI-verified PR.
Happy to adjust scope/naming/anything else you'd prefer.
ES
Contexto
Desde octubre de 2025, el mercado eléctrico español (diario/intradiario) liquida por franjas de 15 minutos en vez de por hora (BOE-A-2025-4908, BOE-A-2025-5342, armonización ISP de 15 min de ENTSO-E). El indicador ESIOS
1001(el que se usa hoy para el PVPC) sigue siendo horario aunque se pida contime_trunc; el indicador791("Precio medio cuarto horario final comercializadores de referencia") es la serie realmente de cuarto de hora equivalente al PVPC (96 valores/día), confirmado contra la API real de ESIOS.Qué añade esto
Un interruptor opcional "Fetch PVPC at 15-minute resolution" (obtener el PVPC con resolución de 15 min), que reutiliza el token de la API privada ya existente (sin credencial nueva, sin paso de configuración nuevo) — seleccionable en el paso
price_modetanto del flujo de configuración inicial como del de opciones, de modo que solo se ofrece cuando ya hay un token configurado.Cuando está activo:
791en vez del1001.price_XXhsolo recogen la muestra en punto (evita que choquen los 4 valores de cada hora, ver más abajo).Desactivado por defecto; el comportamiento horario existente no cambia.
Ficheros modificados
aiopvpc/const.py: nuevoESIOS_PVPC_QUARTER_HOURLY = "791".aiopvpc/parser.py:get_daily_urls_to_download()admite un override opcional dedata_idpor sensor.aiopvpc/pvpc_data.py:PVPCDataincorpora un flagquarter_hourly_pvpc; la búsqueda del "precio actual" redondea al cuarto de hora en curso en vez de a la hora en punto cuando está activo.aiopvpc/prices.py: arreglado un bug latente en_make_price_tag_attributes— con una serie de cuarto de hora, las 4 muestras de cada hora chocarían en la misma claveprice_XXh, disparando incorrectamente 4 veces/hora la lógica de desambiguación de "hora duplicada por DST". Ahora solo se etiqueta la muestra en punto cuandoquarter_hourly=True.sensor.py: añadido un helper compartido_current_price_bucket();_next_price_candidate()y_num_better_prices_ahead()lo usan en vez de un salto fijo de 1 hora. Los dos disparadoresasync_track_time_change(ElecPriceSensory los sensores de atributoupdate_on_hour) se disparan en:00/:15/:30/:45en vez de solo:00cuando la opción está activa.config_flow.py/const.py/coordinator.py: nueva opciónATTR_QUARTER_HOURLY_PVPC, por defectoFalse, condicionada ause_private_api.strings.json/translations/es.json: etiqueta para la nueva opción.Pruebas
Todavía no tengo un test automatizado nuevo listo para la PR — encantado de añadir uno si me indicas el patrón que prefieras (p.ej. extendiendo
test_sensor_periods.py/test_price_mode.py). Lo que sí verifiqué:_make_price_tag_attributesgenerando exactamente 24 clavesprice_XXhsin colisiones a partir de una serie sintética de 96 valores de cuarto de hora (y comportamiento sin cambios sobre una serie horaria normal de 24 valores), y el redondeo minuto→franja para los 60 valores de minuto posibles.python -m py_compilesobre todos los ficheros modificados.tests/existente en mi entorno: la última versión disponible depytest-homeassistant-custom-componentfija un core de Home Assistant más antiguo queAddConfigEntryEntitiesCallback(usado ensensor.py), y esto falla igual en una copia limpia sin modificar — es una limitación previa de mi entorno, no algo introducido por este cambio. Si vuestro CI pasa en verde, esa es la señal real aquí.No tengo localmente la versión de HA sobre la que se prueba activamente esta integración, así que trata esto como un punto de partida para revisar, no como una PR terminada y verificada por CI.
Encantado de ajustar alcance/nombres/lo que prefieras.