diff --git a/homeassistant/components/airthings/config_flow.py b/homeassistant/components/airthings/config_flow.py index 23711b7a9a20b..42e21b2846734 100644 --- a/homeassistant/components/airthings/config_flow.py +++ b/homeassistant/components/airthings/config_flow.py @@ -23,6 +23,10 @@ } ) +URL_API_INTEGRATION = { + "url": "https://dashboard.airthings.com/integrations/api-integration" +} + class AirthingsConfigFlow(ConfigFlow, domain=DOMAIN): """Handle a config flow for Airthings.""" @@ -37,11 +41,7 @@ async def async_step_user( return self.async_show_form( step_id="user", data_schema=STEP_USER_DATA_SCHEMA, - description_placeholders={ - "url": ( - "https://dashboard.airthings.com/integrations/api-integration" - ), - }, + description_placeholders=URL_API_INTEGRATION, ) errors = {} @@ -65,5 +65,8 @@ async def async_step_user( return self.async_create_entry(title="Airthings", data=user_input) return self.async_show_form( - step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors + step_id="user", + data_schema=STEP_USER_DATA_SCHEMA, + errors=errors, + description_placeholders=URL_API_INTEGRATION, ) diff --git a/homeassistant/components/airthings/strings.json b/homeassistant/components/airthings/strings.json index 610891fff1043..4135e3fd387b7 100644 --- a/homeassistant/components/airthings/strings.json +++ b/homeassistant/components/airthings/strings.json @@ -4,9 +4,9 @@ "user": { "data": { "id": "ID", - "secret": "Secret", - "description": "Login at {url} to find your credentials" - } + "secret": "Secret" + }, + "description": "Login at {url} to find your credentials" } }, "error": { diff --git a/homeassistant/components/airthings_ble/config_flow.py b/homeassistant/components/airthings_ble/config_flow.py index 2d32fa6e7df04..fa6a52a5a7983 100644 --- a/homeassistant/components/airthings_ble/config_flow.py +++ b/homeassistant/components/airthings_ble/config_flow.py @@ -171,7 +171,7 @@ async def async_step_user( return self.async_abort(reason="no_devices_found") titles = { - address: discovery.device.name + address: get_name(discovery.device) for (address, discovery) in self._discovered_devices.items() } return self.async_show_form( diff --git a/homeassistant/components/airthings_ble/strings.json b/homeassistant/components/airthings_ble/strings.json index 4b38923384a2f..f73546bbe422e 100644 --- a/homeassistant/components/airthings_ble/strings.json +++ b/homeassistant/components/airthings_ble/strings.json @@ -6,6 +6,9 @@ "description": "[%key:component::bluetooth::config::step::user::description%]", "data": { "address": "[%key:common::config_flow::data::device%]" + }, + "data_description": { + "address": "The Airthings devices discovered via Bluetooth." } }, "bluetooth_confirm": { diff --git a/homeassistant/components/firefly_iii/sensor.py b/homeassistant/components/firefly_iii/sensor.py index f73238d7b2e16..e6facfb6b948b 100644 --- a/homeassistant/components/firefly_iii/sensor.py +++ b/homeassistant/components/firefly_iii/sensor.py @@ -100,15 +100,6 @@ def native_value(self) -> str | None: """Return the state of the sensor.""" return self._account.attributes.current_balance - @property - def extra_state_attributes(self) -> dict[str, str] | None: - """Return extra state attributes for the account entity.""" - return { - "account_role": self._account.attributes.account_role or "", - "account_type": self._account.attributes.type or "", - "current_balance": str(self._account.attributes.current_balance or ""), - } - class FireflyCategoryEntity(FireflyBaseEntity, SensorEntity): """Entity for Firefly III category.""" diff --git a/homeassistant/components/frontend/__init__.py b/homeassistant/components/frontend/__init__.py index 4bdaff92b0162..ebd354c5e8390 100644 --- a/homeassistant/components/frontend/__init__.py +++ b/homeassistant/components/frontend/__init__.py @@ -452,6 +452,10 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: hass.http.app.router.register_resource(IndexView(repo_path, hass)) + async_register_built_in_panel(hass, "light") + async_register_built_in_panel(hass, "security") + async_register_built_in_panel(hass, "climate") + async_register_built_in_panel(hass, "profile") async_register_built_in_panel( diff --git a/homeassistant/components/homeassistant_connect_zbt2/config_flow.py b/homeassistant/components/homeassistant_connect_zbt2/config_flow.py index 34af7b6168a1a..1d95601211e44 100644 --- a/homeassistant/components/homeassistant_connect_zbt2/config_flow.py +++ b/homeassistant/components/homeassistant_connect_zbt2/config_flow.py @@ -67,11 +67,7 @@ class ZBT2FirmwareMixin(ConfigEntryBaseFlow, FirmwareInstallFlowProtocol): """Mixin for Home Assistant Connect ZBT-2 firmware methods.""" context: ConfigFlowContext - - # `rts_dtr` targets older adapters, `baudrate` works for newer ones. The reason we - # try them in this order is that on older adapters `baudrate` entered the ESP32-S3 - # bootloader instead of the MG24 bootloader. - BOOTLOADER_RESET_METHODS = [ResetTarget.RTS_DTR, ResetTarget.BAUDRATE] + BOOTLOADER_RESET_METHODS = [ResetTarget.RTS_DTR] async def async_step_install_zigbee_firmware( self, user_input: dict[str, Any] | None = None diff --git a/homeassistant/components/homeassistant_connect_zbt2/update.py b/homeassistant/components/homeassistant_connect_zbt2/update.py index 6c8819a7da965..e6d66ca822d51 100644 --- a/homeassistant/components/homeassistant_connect_zbt2/update.py +++ b/homeassistant/components/homeassistant_connect_zbt2/update.py @@ -157,7 +157,7 @@ async def async_setup_entry( class FirmwareUpdateEntity(BaseFirmwareUpdateEntity): """Connect ZBT-2 firmware update entity.""" - bootloader_reset_methods = [ResetTarget.RTS_DTR, ResetTarget.BAUDRATE] + bootloader_reset_methods = [ResetTarget.RTS_DTR] def __init__( self, diff --git a/homeassistant/components/matter/climate.py b/homeassistant/components/matter/climate.py index c15dd42d62b67..4b28fe7625b4a 100644 --- a/homeassistant/components/matter/climate.py +++ b/homeassistant/components/matter/climate.py @@ -30,6 +30,7 @@ from .helpers import get_matter from .models import MatterDiscoverySchema +HUMIDITY_SCALING_FACTOR = 100 TEMPERATURE_SCALING_FACTOR = 100 HVAC_SYSTEM_MODE_MAP = { HVACMode.OFF: 0, @@ -261,6 +262,18 @@ def _update_from_device(self) -> None: self._attr_current_temperature = self._get_temperature_in_degrees( clusters.Thermostat.Attributes.LocalTemperature ) + + self._attr_current_humidity = ( + int(raw_measured_humidity) / HUMIDITY_SCALING_FACTOR + if ( + raw_measured_humidity := self.get_matter_attribute_value( + clusters.RelativeHumidityMeasurement.Attributes.MeasuredValue + ) + ) + is not None + else None + ) + if self.get_matter_attribute_value(clusters.OnOff.Attributes.OnOff) is False: # special case: the appliance has a dedicated Power switch on the OnOff cluster # if the mains power is off - treat it as if the HVAC mode is off @@ -428,6 +441,7 @@ def _get_temperature_in_degrees( clusters.Thermostat.Attributes.TemperatureSetpointHold, clusters.Thermostat.Attributes.UnoccupiedCoolingSetpoint, clusters.Thermostat.Attributes.UnoccupiedHeatingSetpoint, + clusters.RelativeHumidityMeasurement.Attributes.MeasuredValue, clusters.OnOff.Attributes.OnOff, ), device_type=(device_types.Thermostat, device_types.RoomAirConditioner), diff --git a/homeassistant/components/matter/sensor.py b/homeassistant/components/matter/sensor.py index b8249e9efa3ae..0c95cda947426 100644 --- a/homeassistant/components/matter/sensor.py +++ b/homeassistant/components/matter/sensor.py @@ -351,6 +351,7 @@ def _update_from_device(self) -> None: required_attributes=( clusters.RelativeHumidityMeasurement.Attributes.MeasuredValue, ), + allow_multi=True, # also used for climate entity ), MatterDiscoverySchema( platform=Platform.SENSOR, diff --git a/homeassistant/components/media_source/models.py b/homeassistant/components/media_source/models.py index 2cf5d231741ef..ac633e8753dbc 100644 --- a/homeassistant/components/media_source/models.py +++ b/homeassistant/components/media_source/models.py @@ -7,6 +7,7 @@ from homeassistant.components.media_player import BrowseMedia, MediaClass, MediaType from homeassistant.core import HomeAssistant, callback +from homeassistant.helpers.translation import async_get_cached_translations from .const import MEDIA_SOURCE_DATA, URI_SCHEME, URI_SCHEME_REGEX @@ -62,12 +63,15 @@ def media_source_id(self) -> str: async def async_browse(self) -> BrowseMediaSource: """Browse this item.""" if self.domain is None: + title = async_get_cached_translations( + self.hass, self.hass.config.language, "common", "media_source" + ).get("component.media_source.common.sources_default", "Media Sources") base = BrowseMediaSource( domain=None, identifier=None, media_class=MediaClass.APP, media_content_type=MediaType.APPS, - title="Media Sources", + title=title, can_play=False, can_expand=True, children_media_class=MediaClass.APP, diff --git a/homeassistant/components/media_source/strings.json b/homeassistant/components/media_source/strings.json index 40204fc32db9e..12f69ad439008 100644 --- a/homeassistant/components/media_source/strings.json +++ b/homeassistant/components/media_source/strings.json @@ -9,5 +9,8 @@ "unknown_media_source": { "message": "Unknown media source: {domain}" } + }, + "common": { + "sources_default": "Media sources" } } diff --git a/homeassistant/components/nordpool/__init__.py b/homeassistant/components/nordpool/__init__.py index dd2626aaa41c7..8fb6a5eaf3b4a 100644 --- a/homeassistant/components/nordpool/__init__.py +++ b/homeassistant/components/nordpool/__init__.py @@ -34,6 +34,7 @@ async def async_setup_entry( coordinator = NordPoolDataUpdateCoordinator(hass, config_entry) await coordinator.fetch_data(dt_util.utcnow(), True) + await coordinator.update_listeners(dt_util.utcnow()) if not coordinator.last_update_success: raise ConfigEntryNotReady( translation_domain=DOMAIN, diff --git a/homeassistant/components/nordpool/coordinator.py b/homeassistant/components/nordpool/coordinator.py index 51bc0e638dd82..f2f41322aff22 100644 --- a/homeassistant/components/nordpool/coordinator.py +++ b/homeassistant/components/nordpool/coordinator.py @@ -44,9 +44,10 @@ def __init__(self, hass: HomeAssistant, config_entry: NordPoolConfigEntry) -> No name=DOMAIN, ) self.client = NordPoolClient(session=async_get_clientsession(hass)) - self.unsub: Callable[[], None] | None = None + self.data_unsub: Callable[[], None] | None = None + self.listener_unsub: Callable[[], None] | None = None - def get_next_interval(self, now: datetime) -> datetime: + def get_next_data_interval(self, now: datetime) -> datetime: """Compute next time an update should occur.""" next_hour = dt_util.utcnow() + timedelta(hours=1) next_run = datetime( @@ -56,23 +57,45 @@ def get_next_interval(self, now: datetime) -> datetime: next_hour.hour, tzinfo=dt_util.UTC, ) - LOGGER.debug("Next update at %s", next_run) + LOGGER.debug("Next data update at %s", next_run) + return next_run + + def get_next_15_interval(self, now: datetime) -> datetime: + """Compute next time we need to notify listeners.""" + next_run = dt_util.utcnow() + timedelta(minutes=15) + next_minute = next_run.minute // 15 * 15 + next_run = next_run.replace( + minute=next_minute, second=0, microsecond=0, tzinfo=dt_util.UTC + ) + + LOGGER.debug("Next listener update at %s", next_run) return next_run async def async_shutdown(self) -> None: """Cancel any scheduled call, and ignore new runs.""" await super().async_shutdown() - if self.unsub: - self.unsub() - self.unsub = None + if self.data_unsub: + self.data_unsub() + self.data_unsub = None + if self.listener_unsub: + self.listener_unsub() + self.listener_unsub = None + + async def update_listeners(self, now: datetime) -> None: + """Update entity listeners.""" + self.listener_unsub = async_track_point_in_utc_time( + self.hass, + self.update_listeners, + self.get_next_15_interval(dt_util.utcnow()), + ) + self.async_update_listeners() async def fetch_data(self, now: datetime, initial: bool = False) -> None: """Fetch data from Nord Pool.""" - self.unsub = async_track_point_in_utc_time( - self.hass, self.fetch_data, self.get_next_interval(dt_util.utcnow()) + self.data_unsub = async_track_point_in_utc_time( + self.hass, self.fetch_data, self.get_next_data_interval(dt_util.utcnow()) ) if self.config_entry.pref_disable_polling and not initial: - self.async_update_listeners() return try: data = await self.handle_data(initial) diff --git a/homeassistant/components/onedrive/backup.py b/homeassistant/components/onedrive/backup.py index bea1edce692e2..4243a920fe570 100644 --- a/homeassistant/components/onedrive/backup.py +++ b/homeassistant/components/onedrive/backup.py @@ -163,7 +163,10 @@ async def async_upload_backup( ) try: backup_file = await LargeFileUploadClient.upload( - self._token_function, file, session=async_get_clientsession(self._hass) + self._token_function, + file, + upload_chunk_size=UPLOAD_CHUNK_SIZE, + session=async_get_clientsession(self._hass), ) except HashMismatchError as err: raise BackupAgentError( diff --git a/homeassistant/components/ovo_energy/manifest.json b/homeassistant/components/ovo_energy/manifest.json index 0fc90808bc95c..da6fb5232f71b 100644 --- a/homeassistant/components/ovo_energy/manifest.json +++ b/homeassistant/components/ovo_energy/manifest.json @@ -7,5 +7,5 @@ "integration_type": "service", "iot_class": "cloud_polling", "loggers": ["ovoenergy"], - "requirements": ["ovoenergy==2.0.1"] + "requirements": ["ovoenergy==3.0.1"] } diff --git a/homeassistant/components/portainer/entity.py b/homeassistant/components/portainer/entity.py index 5fd53236cd825..907e8cf4afe90 100644 --- a/homeassistant/components/portainer/entity.py +++ b/homeassistant/components/portainer/entity.py @@ -1,7 +1,9 @@ """Base class for Portainer entities.""" from pyportainer.models.docker import DockerContainer +from yarl import URL +from homeassistant.const import CONF_URL from homeassistant.helpers.device_registry import DeviceInfo from homeassistant.helpers.update_coordinator import CoordinatorEntity @@ -31,6 +33,9 @@ def __init__( identifiers={ (DOMAIN, f"{coordinator.config_entry.entry_id}_{self.device_id}") }, + configuration_url=URL( + f"{coordinator.config_entry.data[CONF_URL]}#!/{self.device_id}/docker/dashboard" + ), manufacturer=DEFAULT_NAME, model="Endpoint", name=device_info.endpoint.name, @@ -63,6 +68,9 @@ def __init__( (DOMAIN, f"{self.coordinator.config_entry.entry_id}_{device_name}") }, manufacturer=DEFAULT_NAME, + configuration_url=URL( + f"{coordinator.config_entry.data[CONF_URL]}#!/{self.endpoint_id}/docker/containers/{self.device_id}" + ), model="Container", name=device_name, via_device=( diff --git a/homeassistant/components/recorder/const.py b/homeassistant/components/recorder/const.py index 4797eecda0fbb..b1563d85d5665 100644 --- a/homeassistant/components/recorder/const.py +++ b/homeassistant/components/recorder/const.py @@ -53,7 +53,6 @@ CONTEXT_ID_AS_BINARY_SCHEMA_VERSION = 36 EVENT_TYPE_IDS_SCHEMA_VERSION = 37 STATES_META_SCHEMA_VERSION = 38 -LAST_REPORTED_SCHEMA_VERSION = 43 CIRCULAR_MEAN_SCHEMA_VERSION = 49 LEGACY_STATES_EVENT_ID_INDEX_SCHEMA_VERSION = 28 diff --git a/homeassistant/components/recorder/core.py b/homeassistant/components/recorder/core.py index c88a65b78c667..d662416012f31 100644 --- a/homeassistant/components/recorder/core.py +++ b/homeassistant/components/recorder/core.py @@ -56,7 +56,6 @@ DEFAULT_MAX_BIND_VARS, DOMAIN, KEEPALIVE_TIME, - LAST_REPORTED_SCHEMA_VERSION, MARIADB_PYMYSQL_URL_PREFIX, MARIADB_URL_PREFIX, MAX_QUEUE_BACKLOG_MIN_VALUE, @@ -806,6 +805,10 @@ def _run(self) -> None: # Catch up with missed statistics self._schedule_compile_missing_statistics() + + # Kick off live migrations + migration.migrate_data_live(self, self.get_session, schema_status) + _LOGGER.debug("Recorder processing the queue") self._adjust_lru_size() self.hass.add_job(self._async_set_recorder_ready_migration_done) @@ -822,8 +825,6 @@ def _activate_and_set_db_ready( # there are a lot of statistics graphs on the frontend. self.statistics_meta_manager.load(session) - migration.migrate_data_live(self, self.get_session, schema_status) - # We must only set the db ready after we have set the table managers # to active if there is no data to migrate. # @@ -1224,7 +1225,7 @@ def _commit_event_session(self) -> None: if ( pending_last_reported := self.states_manager.get_pending_last_reported_timestamp() - ) and self.schema_version >= LAST_REPORTED_SCHEMA_VERSION: + ): with session.no_autoflush: session.execute( update(States), diff --git a/homeassistant/components/recorder/history/modern.py b/homeassistant/components/recorder/history/modern.py index 566e30713f065..a636ed34ef4d8 100644 --- a/homeassistant/components/recorder/history/modern.py +++ b/homeassistant/components/recorder/history/modern.py @@ -29,7 +29,7 @@ from homeassistant.util import dt as dt_util from homeassistant.util.collection import chunked_or_all -from ..const import LAST_REPORTED_SCHEMA_VERSION, MAX_IDS_FOR_INDEXED_GROUP_BY +from ..const import MAX_IDS_FOR_INDEXED_GROUP_BY from ..db_schema import ( SHARED_ATTR_OR_LEGACY_ATTRIBUTES, StateAttributes, @@ -388,10 +388,9 @@ def _state_changed_during_period_stmt( limit: int | None, include_start_time_state: bool, run_start_ts: float | None, - include_last_reported: bool, ) -> Select | CompoundSelect: stmt = ( - _stmt_and_join_attributes(no_attributes, False, include_last_reported) + _stmt_and_join_attributes(no_attributes, False, True) .filter( ( (States.last_changed_ts == States.last_updated_ts) @@ -424,22 +423,22 @@ def _state_changed_during_period_stmt( single_metadata_id, no_attributes, False, - include_last_reported, + True, ).subquery(), no_attributes, False, - include_last_reported, + True, ), _select_from_subquery( stmt.subquery(), no_attributes, False, - include_last_reported, + True, ), ).subquery(), no_attributes, False, - include_last_reported, + True, ) @@ -454,9 +453,6 @@ def state_changes_during_period( include_start_time_state: bool = True, ) -> dict[str, list[State]]: """Return states changes during UTC period start_time - end_time.""" - has_last_reported = ( - get_instance(hass).schema_version >= LAST_REPORTED_SCHEMA_VERSION - ) if not entity_id: raise ValueError("entity_id must be provided") entity_ids = [entity_id.lower()] @@ -489,14 +485,12 @@ def state_changes_during_period( limit, include_start_time_state, oldest_ts, - has_last_reported, ), track_on=[ bool(end_time_ts), no_attributes, bool(limit), include_start_time_state, - has_last_reported, ], ) return cast( @@ -543,10 +537,10 @@ def _get_last_state_changes_single_stmt(metadata_id: int) -> Select: def _get_last_state_changes_multiple_stmt( - number_of_states: int, metadata_id: int, include_last_reported: bool + number_of_states: int, metadata_id: int ) -> Select: return ( - _stmt_and_join_attributes(False, False, include_last_reported) + _stmt_and_join_attributes(False, False, True) .where( States.state_id == ( @@ -568,9 +562,6 @@ def get_last_state_changes( hass: HomeAssistant, number_of_states: int, entity_id: str ) -> dict[str, list[State]]: """Return the last number_of_states.""" - has_last_reported = ( - get_instance(hass).schema_version >= LAST_REPORTED_SCHEMA_VERSION - ) entity_id_lower = entity_id.lower() entity_ids = [entity_id_lower] @@ -595,9 +586,8 @@ def get_last_state_changes( else: stmt = lambda_stmt( lambda: _get_last_state_changes_multiple_stmt( - number_of_states, metadata_id, has_last_reported + number_of_states, metadata_id ), - track_on=[has_last_reported], ) states = list(execute_stmt_lambda_element(session, stmt, orm_rows=False)) return cast( diff --git a/homeassistant/components/recorder/migration.py b/homeassistant/components/recorder/migration.py index 58af15c2aa72a..1c53b52814155 100644 --- a/homeassistant/components/recorder/migration.py +++ b/homeassistant/components/recorder/migration.py @@ -117,10 +117,10 @@ if TYPE_CHECKING: from . import Recorder -# Live schema migration supported starting from schema version 42 or newer -# Schema version 41 was introduced in HA Core 2023.4 -# Schema version 42 was introduced in HA Core 2023.11 -LIVE_MIGRATION_MIN_SCHEMA_VERSION = 42 +# Live schema migration supported starting from schema version 48 or newer +# Schema version 47 was introduced in HA Core 2024.9 +# Schema version 48 was introduced in HA Core 2025.1 +LIVE_MIGRATION_MIN_SCHEMA_VERSION = 48 MIGRATION_NOTE_OFFLINE = ( "Note: this may take several hours on large databases and slow machines. " diff --git a/homeassistant/components/reolink/__init__.py b/homeassistant/components/reolink/__init__.py index 81e000d8a7556..a10a926f6e50f 100644 --- a/homeassistant/components/reolink/__init__.py +++ b/homeassistant/components/reolink/__init__.py @@ -25,7 +25,7 @@ device_registry as dr, entity_registry as er, ) -from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, format_mac +from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC from homeassistant.helpers.event import async_call_later from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed @@ -497,16 +497,6 @@ def migrate_entity_ids( entity_reg = er.async_get(hass) entities = er.async_entries_for_config_entry(entity_reg, config_entry_id) for entity in entities: - # Can be removed in HA 2025.1.0 - if entity.domain == "update" and entity.unique_id in [ - host.unique_id, - format_mac(host.api.mac_address), - ]: - entity_reg.async_update_entity( - entity.entity_id, new_unique_id=f"{host.unique_id}_firmware" - ) - continue - if host.api.supported(None, "UID") and not entity.unique_id.startswith( host.unique_id ): diff --git a/homeassistant/components/reolink/entity.py b/homeassistant/components/reolink/entity.py index dcda6b843ad15..c180e5f77b260 100644 --- a/homeassistant/components/reolink/entity.py +++ b/homeassistant/components/reolink/entity.py @@ -252,7 +252,7 @@ def __init__( chime: Chime, coordinator: DataUpdateCoordinator[None] | None = None, ) -> None: - """Initialize ReolinkChimeCoordinatorEntity for a chime.""" + """Initialize ReolinkHostChimeCoordinatorEntity for a chime.""" super().__init__(reolink_data, coordinator) self._channel = chime.channel self._chime = chime diff --git a/homeassistant/components/reolink/manifest.json b/homeassistant/components/reolink/manifest.json index c547aee39c2f3..116c2928ff346 100644 --- a/homeassistant/components/reolink/manifest.json +++ b/homeassistant/components/reolink/manifest.json @@ -19,5 +19,5 @@ "iot_class": "local_push", "loggers": ["reolink_aio"], "quality_scale": "platinum", - "requirements": ["reolink-aio==0.16.0"] + "requirements": ["reolink-aio==0.16.1"] } diff --git a/homeassistant/components/reolink/sensor.py b/homeassistant/components/reolink/sensor.py index a0939046a1728..fe9744543c036 100644 --- a/homeassistant/components/reolink/sensor.py +++ b/homeassistant/components/reolink/sensor.py @@ -284,7 +284,7 @@ def native_value(self) -> StateType | date | datetime | Decimal: class ReolinkHddSensorEntity(ReolinkHostCoordinatorEntity, SensorEntity): - """Base sensor class for Reolink host sensors.""" + """Base sensor class for Reolink storage device sensors.""" entity_description: ReolinkSensorEntityDescription @@ -294,7 +294,7 @@ def __init__( hdd_index: int, entity_description: ReolinkSensorEntityDescription, ) -> None: - """Initialize Reolink host sensor.""" + """Initialize Reolink storage device sensor.""" self.entity_description = entity_description super().__init__(reolink_data) self._hdd_index = hdd_index diff --git a/homeassistant/components/reolink/strings.json b/homeassistant/components/reolink/strings.json index d9bcc80406f3e..dda68c6b4ad40 100644 --- a/homeassistant/components/reolink/strings.json +++ b/homeassistant/components/reolink/strings.json @@ -132,10 +132,6 @@ "title": "Reolink firmware update required", "description": "\"{name}\" with model \"{model}\" and hardware version \"{hw_version}\" is running an old firmware version \"{current_firmware}\", while at least firmware version \"{required_firmware}\" is required for proper operation of the Reolink integration. The firmware can be updated by pressing \"install\" in the more info dialog of the update entity of \"{name}\" from within Home Assistant. Alternatively, the latest firmware can be downloaded from the [Reolink download center]({download_link})." }, - "hub_switch_deprecated": { - "title": "Reolink Home Hub switches deprecated", - "description": "The redundant 'Record', 'Email on event', 'FTP upload', 'Push notifications', and 'Buzzer on event' switches on the Reolink Home Hub are deprecated since the new firmware no longer supports these. Please use the equally named switches under each of the camera devices connected to the Home Hub instead. To remove this issue, please adjust automations accordingly and disable the switch entities mentioned." - }, "password_too_long": { "title": "Reolink password too long", "description": "The password for \"{name}\" is more than 31 characters long, this is no longer compatible with the Reolink API. Please change the password using the Reolink app/client to a password with is shorter than 32 characters. After changing the password, fill in the new password in the Reolink Re-authentication flow to continue using this integration. The latest version of the Reolink app/client also has a password limit of 31 characters." diff --git a/homeassistant/components/reolink/switch.py b/homeassistant/components/reolink/switch.py index d5f45872661ea..b7d249b6fecb6 100644 --- a/homeassistant/components/reolink/switch.py +++ b/homeassistant/components/reolink/switch.py @@ -11,10 +11,8 @@ from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription from homeassistant.const import EntityCategory from homeassistant.core import HomeAssistant -from homeassistant.helpers import entity_registry as er, issue_registry as ir from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback -from .const import DOMAIN from .entity import ( ReolinkChannelCoordinatorEntity, ReolinkChannelEntityDescription, @@ -41,11 +39,11 @@ class ReolinkSwitchEntityDescription( @dataclass(frozen=True, kw_only=True) -class ReolinkNVRSwitchEntityDescription( +class ReolinkHostSwitchEntityDescription( SwitchEntityDescription, ReolinkHostEntityDescription, ): - """A class that describes NVR switch entities.""" + """A class that describes host switch entities.""" method: Callable[[Host, bool], Any] value: Callable[[Host], bool] @@ -156,7 +154,7 @@ class ReolinkChimeSwitchEntityDescription( cmd_key="GetRec", translation_key="record", entity_category=EntityCategory.CONFIG, - supported=lambda api, ch: api.supported(ch, "recording") and api.is_nvr, + supported=lambda api, ch: api.supported(ch, "rec_enable") and api.is_nvr, value=lambda api, ch: api.recording_enabled(ch), method=lambda api, ch, value: api.set_recording(ch, value), ), @@ -247,8 +245,8 @@ class ReolinkChimeSwitchEntityDescription( ), ) -NVR_SWITCH_ENTITIES = ( - ReolinkNVRSwitchEntityDescription( +HOST_SWITCH_ENTITIES = ( + ReolinkHostSwitchEntityDescription( key="email", cmd_key="GetEmail", translation_key="email", @@ -257,7 +255,7 @@ class ReolinkChimeSwitchEntityDescription( value=lambda api: api.email_enabled(), method=lambda api, value: api.set_email(None, value), ), - ReolinkNVRSwitchEntityDescription( + ReolinkHostSwitchEntityDescription( key="ftp_upload", cmd_key="GetFtp", translation_key="ftp_upload", @@ -266,7 +264,7 @@ class ReolinkChimeSwitchEntityDescription( value=lambda api: api.ftp_enabled(), method=lambda api, value: api.set_ftp(None, value), ), - ReolinkNVRSwitchEntityDescription( + ReolinkHostSwitchEntityDescription( key="push_notifications", cmd_key="GetPush", translation_key="push_notifications", @@ -275,16 +273,16 @@ class ReolinkChimeSwitchEntityDescription( value=lambda api: api.push_enabled(), method=lambda api, value: api.set_push(None, value), ), - ReolinkNVRSwitchEntityDescription( + ReolinkHostSwitchEntityDescription( key="record", cmd_key="GetRec", translation_key="record", entity_category=EntityCategory.CONFIG, - supported=lambda api: api.supported(None, "recording") and not api.is_hub, + supported=lambda api: api.supported(None, "rec_enable") and not api.is_hub, value=lambda api: api.recording_enabled(), method=lambda api, value: api.set_recording(None, value), ), - ReolinkNVRSwitchEntityDescription( + ReolinkHostSwitchEntityDescription( key="buzzer", cmd_key="GetBuzzerAlarmV20", translation_key="hub_ringtone_on_event", @@ -306,56 +304,6 @@ class ReolinkChimeSwitchEntityDescription( ), ) -# Can be removed in HA 2025.4.0 -DEPRECATED_NVR_SWITCHES = [ - ReolinkNVRSwitchEntityDescription( - key="email", - cmd_key="GetEmail", - translation_key="email", - entity_category=EntityCategory.CONFIG, - supported=lambda api: api.is_hub, - value=lambda api: api.email_enabled(), - method=lambda api, value: api.set_email(None, value), - ), - ReolinkNVRSwitchEntityDescription( - key="ftp_upload", - cmd_key="GetFtp", - translation_key="ftp_upload", - entity_category=EntityCategory.CONFIG, - supported=lambda api: api.is_hub, - value=lambda api: api.ftp_enabled(), - method=lambda api, value: api.set_ftp(None, value), - ), - ReolinkNVRSwitchEntityDescription( - key="push_notifications", - cmd_key="GetPush", - translation_key="push_notifications", - entity_category=EntityCategory.CONFIG, - supported=lambda api: api.is_hub, - value=lambda api: api.push_enabled(), - method=lambda api, value: api.set_push(None, value), - ), - ReolinkNVRSwitchEntityDescription( - key="record", - cmd_key="GetRec", - translation_key="record", - entity_category=EntityCategory.CONFIG, - supported=lambda api: api.is_hub, - value=lambda api: api.recording_enabled(), - method=lambda api, value: api.set_recording(None, value), - ), - ReolinkNVRSwitchEntityDescription( - key="buzzer", - cmd_key="GetBuzzerAlarmV20", - translation_key="hub_ringtone_on_event", - icon="mdi:room-service", - entity_category=EntityCategory.CONFIG, - supported=lambda api: api.is_hub, - value=lambda api: api.buzzer_enabled(), - method=lambda api, value: api.set_buzzer(None, value), - ), -] - async def async_setup_entry( hass: HomeAssistant, @@ -372,8 +320,8 @@ async def async_setup_entry( if entity_description.supported(reolink_data.host.api, channel) ] entities.extend( - ReolinkNVRSwitchEntity(reolink_data, entity_description) - for entity_description in NVR_SWITCH_ENTITIES + ReolinkHostSwitchEntity(reolink_data, entity_description) + for entity_description in HOST_SWITCH_ENTITIES if entity_description.supported(reolink_data.host.api) ) entities.extend( @@ -389,34 +337,6 @@ async def async_setup_entry( if chime.channel is None ) - # Can be removed in HA 2025.4.0 - depricated_dict = {} - for desc in DEPRECATED_NVR_SWITCHES: - if not desc.supported(reolink_data.host.api): - continue - depricated_dict[f"{reolink_data.host.unique_id}_{desc.key}"] = desc - - entity_reg = er.async_get(hass) - reg_entities = er.async_entries_for_config_entry(entity_reg, config_entry.entry_id) - for entity in reg_entities: - # Can be removed in HA 2025.4.0 - if entity.domain == "switch" and entity.unique_id in depricated_dict: - if entity.disabled: - entity_reg.async_remove(entity.entity_id) - continue - - ir.async_create_issue( - hass, - DOMAIN, - "hub_switch_deprecated", - is_fixable=False, - severity=ir.IssueSeverity.WARNING, - translation_key="hub_switch_deprecated", - ) - entities.append( - ReolinkNVRSwitchEntity(reolink_data, depricated_dict[entity.unique_id]) - ) - async_add_entities(entities) @@ -453,15 +373,15 @@ async def async_turn_off(self, **kwargs: Any) -> None: self.async_write_ha_state() -class ReolinkNVRSwitchEntity(ReolinkHostCoordinatorEntity, SwitchEntity): - """Switch entity class for Reolink NVR features.""" +class ReolinkHostSwitchEntity(ReolinkHostCoordinatorEntity, SwitchEntity): + """Switch entity class for Reolink host features.""" - entity_description: ReolinkNVRSwitchEntityDescription + entity_description: ReolinkHostSwitchEntityDescription def __init__( self, reolink_data: ReolinkData, - entity_description: ReolinkNVRSwitchEntityDescription, + entity_description: ReolinkHostSwitchEntityDescription, ) -> None: """Initialize Reolink switch entity.""" self.entity_description = entity_description diff --git a/homeassistant/components/shelly/manifest.json b/homeassistant/components/shelly/manifest.json index 7c3292f5dea3a..5f1f767271b46 100644 --- a/homeassistant/components/shelly/manifest.json +++ b/homeassistant/components/shelly/manifest.json @@ -9,7 +9,7 @@ "iot_class": "local_push", "loggers": ["aioshelly"], "quality_scale": "silver", - "requirements": ["aioshelly==13.10.0"], + "requirements": ["aioshelly==13.11.0"], "zeroconf": [ { "type": "_http._tcp.local.", diff --git a/homeassistant/components/slack/strings.json b/homeassistant/components/slack/strings.json index 13b48644ffd78..960ae3cccbc6a 100644 --- a/homeassistant/components/slack/strings.json +++ b/homeassistant/components/slack/strings.json @@ -5,14 +5,14 @@ "description": "Refer to the documentation on getting your Slack API key.", "data": { "api_key": "[%key:common::config_flow::data::api_key%]", - "default_channel": "Default Channel", + "default_channel": "Default channel", "icon": "Icon", "username": "[%key:common::config_flow::data::username%]" }, "data_description": { "api_key": "The Slack API token to use for sending Slack messages.", "default_channel": "The channel to post to if no channel is specified when sending a message.", - "icon": "Use one of the Slack emojis as an Icon for the supplied username.", + "icon": "Use one of the Slack emojis as an icon for the supplied username.", "username": "Home Assistant will post to Slack using the username specified." } } diff --git a/homeassistant/components/smartthings/icons.json b/homeassistant/components/smartthings/icons.json index c7c531785b516..aad9182576d41 100644 --- a/homeassistant/components/smartthings/icons.json +++ b/homeassistant/components/smartthings/icons.json @@ -31,6 +31,17 @@ "default": "mdi:stop" } }, + "climate": { + "air_conditioner": { + "state_attributes": { + "fan_mode": { + "state": { + "turbo": "mdi:wind-power" + } + } + } + } + }, "number": { "washer_rinse_cycles": { "default": "mdi:waves-arrow-up" diff --git a/homeassistant/components/smartthings/sensor.py b/homeassistant/components/smartthings/sensor.py index d3e2ab09a3fdf..42581a2807e58 100644 --- a/homeassistant/components/smartthings/sensor.py +++ b/homeassistant/components/smartthings/sensor.py @@ -1151,8 +1151,11 @@ async def async_setup_entry( ) and ( not description.exists_fn - or description.exists_fn( - device.status[MAIN][capability][attribute] + or ( + component == MAIN + and description.exists_fn( + device.status[MAIN][capability][attribute] + ) ) ) and ( diff --git a/homeassistant/components/smartthings/strings.json b/homeassistant/components/smartthings/strings.json index 244324bb1b4c0..fb6b84651865e 100644 --- a/homeassistant/components/smartthings/strings.json +++ b/homeassistant/components/smartthings/strings.json @@ -89,6 +89,11 @@ "long_wind": "Long wind", "smart": "Smart" } + }, + "fan_mode": { + "state": { + "turbo": "Turbo" + } } } } diff --git a/homeassistant/components/squeezebox/switch.py b/homeassistant/components/squeezebox/switch.py index 33926c53e649c..f8512124068a4 100644 --- a/homeassistant/components/squeezebox/switch.py +++ b/homeassistant/components/squeezebox/switch.py @@ -22,6 +22,8 @@ _LOGGER = logging.getLogger(__name__) +PARALLEL_UPDATES = 1 + async def async_setup_entry( hass: HomeAssistant, diff --git a/homeassistant/components/tibber/manifest.json b/homeassistant/components/tibber/manifest.json index 34f1e8fe1f908..0844915daa4b5 100644 --- a/homeassistant/components/tibber/manifest.json +++ b/homeassistant/components/tibber/manifest.json @@ -7,5 +7,5 @@ "documentation": "https://www.home-assistant.io/integrations/tibber", "iot_class": "cloud_polling", "loggers": ["tibber"], - "requirements": ["pyTibber==0.32.1"] + "requirements": ["pyTibber==0.32.2"] } diff --git a/homeassistant/components/websocket_api/commands.py b/homeassistant/components/websocket_api/commands.py index d69a8c35c4f90..a15d63b31e657 100644 --- a/homeassistant/components/websocket_api/commands.py +++ b/homeassistant/components/websocket_api/commands.py @@ -473,6 +473,10 @@ def handle_subscribe_entities( serialized_states = [] for state in states: + if entity_ids and state.entity_id not in entity_ids: + continue + if entity_filter and not entity_filter(state.entity_id): + continue try: serialized_states.append(state.as_compressed_state_json) except (ValueError, TypeError): diff --git a/homeassistant/components/workday/calendar.py b/homeassistant/components/workday/calendar.py index 82f2942d1f933..e631ebb6e6a32 100644 --- a/homeassistant/components/workday/calendar.py +++ b/homeassistant/components/workday/calendar.py @@ -10,6 +10,7 @@ from homeassistant.const import CONF_NAME from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback +from homeassistant.util import dt as dt_util from . import WorkdayConfigEntry from .const import CONF_EXCLUDES, CONF_OFFSET, CONF_WORKDAYS @@ -87,11 +88,12 @@ def update_data(self, now: datetime) -> None: @property def event(self) -> CalendarEvent | None: """Return the next upcoming event.""" - return ( - sorted(self.event_list, key=lambda e: e.start)[0] - if self.event_list - else None + sorted_list: list[CalendarEvent] | None = ( + sorted(self.event_list, key=lambda e: e.start) if self.event_list else None ) + if not sorted_list: + return None + return [d for d in sorted_list if d.start >= dt_util.utcnow().date()][0] async def async_get_events( self, hass: HomeAssistant, start_date: datetime, end_date: datetime diff --git a/homeassistant/components/zwave_js/light.py b/homeassistant/components/zwave_js/light.py index 9b7c022241003..a5d54cf80c111 100644 --- a/homeassistant/components/zwave_js/light.py +++ b/homeassistant/components/zwave_js/light.py @@ -612,10 +612,7 @@ async def async_turn_on(self, **kwargs: Any) -> None: # If brightness gets set, preserve the color and mix it with the new brightness if self.color_mode == ColorMode.HS: scale = brightness / 255 - if ( - self._last_on_color is not None - and None not in self._last_on_color.values() - ): + if self._last_on_color is not None: # Changed brightness from 0 to >0 old_brightness = max(self._last_on_color.values()) new_scale = brightness / old_brightness @@ -634,8 +631,9 @@ async def async_turn_on(self, **kwargs: Any) -> None: elif current_brightness is not None: scale = current_brightness / 255 - # Reset last color until turning off again + # Reset last color and brightness until turning off again self._last_on_color = None + self._last_brightness = None if new_colors is None: new_colors = self._get_new_colors( @@ -651,8 +649,10 @@ async def async_turn_on(self, **kwargs: Any) -> None: async def async_turn_off(self, **kwargs: Any) -> None: """Turn the light off.""" - # Remember last color and brightness to restore it when turning on - self._last_brightness = self.brightness + # Remember last color and brightness to restore it when turning on, + # only if we're sure the light is turned on to avoid overwriting good values + if self._last_brightness is None: + self._last_brightness = self.brightness if self._current_color and isinstance(self._current_color.value, dict): red = self._current_color.value.get(COLOR_SWITCH_COMBINED_RED) green = self._current_color.value.get(COLOR_SWITCH_COMBINED_GREEN) @@ -666,7 +666,8 @@ async def async_turn_off(self, **kwargs: Any) -> None: if blue is not None: last_color[ColorComponent.BLUE] = blue - if last_color: + # Only store the last color if we're aware of it, i.e. ignore off light + if last_color and max(last_color.values()) > 0: self._last_on_color = last_color if self._target_brightness: diff --git a/requirements_all.txt b/requirements_all.txt index bd7d10b0b120a..b9a377b524fee 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -384,7 +384,7 @@ aioruuvigateway==0.1.0 aiosenz==1.0.0 # homeassistant.components.shelly -aioshelly==13.10.0 +aioshelly==13.11.0 # homeassistant.components.skybell aioskybell==22.7.0 @@ -1670,7 +1670,7 @@ orvibo==1.1.2 ourgroceries==1.5.4 # homeassistant.components.ovo_energy -ovoenergy==2.0.1 +ovoenergy==3.0.1 # homeassistant.components.p1_monitor p1monitor==3.2.0 @@ -1845,7 +1845,7 @@ pyRFXtrx==0.31.1 pySDCP==1 # homeassistant.components.tibber -pyTibber==0.32.1 +pyTibber==0.32.2 # homeassistant.components.dlink pyW215==0.8.0 @@ -2710,7 +2710,7 @@ renault-api==0.4.1 renson-endura-delta==1.7.2 # homeassistant.components.reolink -reolink-aio==0.16.0 +reolink-aio==0.16.1 # homeassistant.components.idteck_prox rfk101py==0.0.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 41fee2f799b72..403439864ac53 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -366,7 +366,7 @@ aioruuvigateway==0.1.0 aiosenz==1.0.0 # homeassistant.components.shelly -aioshelly==13.10.0 +aioshelly==13.11.0 # homeassistant.components.skybell aioskybell==22.7.0 @@ -1420,7 +1420,7 @@ oralb-ble==0.17.6 ourgroceries==1.5.4 # homeassistant.components.ovo_energy -ovoenergy==2.0.1 +ovoenergy==3.0.1 # homeassistant.components.p1_monitor p1monitor==3.2.0 @@ -1556,7 +1556,7 @@ pyHomee==1.3.8 pyRFXtrx==0.31.1 # homeassistant.components.tibber -pyTibber==0.32.1 +pyTibber==0.32.2 # homeassistant.components.dlink pyW215==0.8.0 @@ -2256,7 +2256,7 @@ renault-api==0.4.1 renson-endura-delta==1.7.2 # homeassistant.components.reolink -reolink-aio==0.16.0 +reolink-aio==0.16.1 # homeassistant.components.rflink rflink==0.0.67 diff --git a/tests/components/airthings_ble/test_config_flow.py b/tests/components/airthings_ble/test_config_flow.py index 2adc5498e7b85..42db22a99153c 100644 --- a/tests/components/airthings_ble/test_config_flow.py +++ b/tests/components/airthings_ble/test_config_flow.py @@ -136,7 +136,7 @@ async def test_user_setup(hass: HomeAssistant) -> None: schema = result["data_schema"].schema assert schema.get(CONF_ADDRESS).container == { - "cc:cc:cc:cc:cc:cc": "Airthings Wave Plus" + "cc:cc:cc:cc:cc:cc": "Airthings Wave Plus (123456)" } with patch( @@ -186,7 +186,7 @@ async def test_user_setup_replaces_ignored_device(hass: HomeAssistant) -> None: schema = result["data_schema"].schema assert schema.get(CONF_ADDRESS).container == { - "cc:cc:cc:cc:cc:cc": "Airthings Wave Plus" + "cc:cc:cc:cc:cc:cc": "Airthings Wave Plus (123456)" } with patch( diff --git a/tests/components/firefly_iii/snapshots/test_sensor.ambr b/tests/components/firefly_iii/snapshots/test_sensor.ambr index d381462e65a87..bccd54746ec67 100644 --- a/tests/components/firefly_iii/snapshots/test_sensor.ambr +++ b/tests/components/firefly_iii/snapshots/test_sensor.ambr @@ -39,9 +39,6 @@ # name: test_all_entities[sensor.firefly_iii_test_credit_card-state] StateSnapshot({ 'attributes': ReadOnlyDict({ - 'account_role': 'creditCard', - 'account_type': 'liability', - 'current_balance': '-250.00', 'device_class': 'monetary', 'friendly_name': 'Firefly III test Credit Card', 'icon': 'mdi:hand-coin', @@ -149,9 +146,6 @@ # name: test_all_entities[sensor.firefly_iii_test_my_checking_account-state] StateSnapshot({ 'attributes': ReadOnlyDict({ - 'account_role': 'defaultAsset', - 'account_type': 'asset', - 'current_balance': '123.45', 'device_class': 'monetary', 'friendly_name': 'Firefly III test My checking account', 'icon': 'mdi:account-cash', @@ -206,9 +200,6 @@ # name: test_all_entities[sensor.firefly_iii_test_savings_account-state] StateSnapshot({ 'attributes': ReadOnlyDict({ - 'account_role': 'savingsAsset', - 'account_type': 'expense', - 'current_balance': '5000.00', 'device_class': 'monetary', 'friendly_name': 'Firefly III test Savings Account', 'icon': 'mdi:cash-minus', diff --git a/tests/components/homeassistant_connect_zbt2/test_config_flow.py b/tests/components/homeassistant_connect_zbt2/test_config_flow.py index 62a34bc1d3555..dc32741165e50 100644 --- a/tests/components/homeassistant_connect_zbt2/test_config_flow.py +++ b/tests/components/homeassistant_connect_zbt2/test_config_flow.py @@ -328,10 +328,7 @@ async def test_options_flow( # Verify async_flash_silabs_firmware was called with ZBT-2's reset methods assert flash_mock.call_count == 1 - assert flash_mock.mock_calls[0].kwargs["bootloader_reset_methods"] == [ - "rts_dtr", - "baudrate", - ] + assert flash_mock.mock_calls[0].kwargs["bootloader_reset_methods"] == ["rts_dtr"] async def test_duplicate_discovery(hass: HomeAssistant) -> None: diff --git a/tests/components/matter/conftest.py b/tests/components/matter/conftest.py index dca29cd7abd63..9b82f2ac30559 100644 --- a/tests/components/matter/conftest.py +++ b/tests/components/matter/conftest.py @@ -121,6 +121,7 @@ async def integration_fixture( "smoke_detector", "solar_power", "switch_unit", + "tado_smart_radiator_thermostat_x", "temperature_sensor", "thermostat", "vacuum_cleaner", diff --git a/tests/components/matter/fixtures/nodes/tado_smart_radiator_thermostat_x.json b/tests/components/matter/fixtures/nodes/tado_smart_radiator_thermostat_x.json new file mode 100644 index 0000000000000..9111ffd03fe66 --- /dev/null +++ b/tests/components/matter/fixtures/nodes/tado_smart_radiator_thermostat_x.json @@ -0,0 +1,198 @@ +{ + "node_id": 12, + "date_commissioned": "2024-11-30T14:42:32.255793", + "last_interview": "2025-09-02T11:11:02.931246", + "interview_version": 6, + "available": true, + "is_bridge": false, + "attributes": { + "0/29/0": [ + { + "0": 22, + "1": 1 + } + ], + "0/29/1": [29, 31, 40, 48, 49, 51, 60, 62, 63], + "0/29/2": [], + "0/29/3": [1], + "0/29/65532": 0, + "0/29/65533": 1, + "0/29/65528": [], + "0/29/65529": [], + "0/29/65531": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533], + "0/31/0": [ + { + "1": 5, + "2": 2, + "3": [112233], + "4": null, + "254": 4 + } + ], + "0/31/1": [], + "0/31/2": 4, + "0/31/3": 3, + "0/31/4": 4, + "0/31/65532": 0, + "0/31/65533": 1, + "0/31/65528": [], + "0/31/65529": [], + "0/31/65531": [0, 1, 2, 3, 4, 65528, 65529, 65531, 65532, 65533], + "0/40/0": 1, + "0/40/1": "tado\u00b0 GmbH", + "0/40/2": 4942, + "0/40/3": "Smart Radiator Thermostat X", + "0/40/4": 1, + "0/40/5": "", + "0/40/6": "**REDACTED**", + "0/40/7": 1, + "0/40/8": "VA04", + "0/40/9": 64, + "0/40/10": "1.0", + "0/40/18": "86A085E50D5A98E9", + "0/40/19": { + "0": 3, + "1": 3 + }, + "0/40/65532": 0, + "0/40/65533": 1, + "0/40/65528": [], + "0/40/65529": [], + "0/40/65531": [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 18, 19, 65528, 65529, 65531, 65532, + 65533 + ], + "0/48/0": 0, + "0/48/1": { + "0": 60, + "1": 900 + }, + "0/48/2": 0, + "0/48/3": 0, + "0/48/4": true, + "0/48/65532": 0, + "0/48/65533": 1, + "0/48/65528": [1, 3, 5], + "0/48/65529": [0, 2, 4], + "0/48/65531": [0, 1, 2, 3, 4, 65528, 65529, 65531, 65532, 65533], + "0/49/0": 1, + "0/49/1": [ + { + "0": "DghqP9mExis=", + "1": true + } + ], + "0/49/2": 10, + "0/49/3": 20, + "0/49/4": true, + "0/49/5": 0, + "0/49/6": "DghqP9mExis=", + "0/49/7": null, + "0/49/65532": 2, + "0/49/65533": 1, + "0/49/65528": [1, 5, 7], + "0/49/65529": [0, 3, 4, 6, 8], + "0/49/65531": [0, 1, 2, 3, 4, 5, 6, 7, 65528, 65529, 65531, 65532, 65533], + "0/51/0": [ + { + "0": "ieee802154", + "1": true, + "2": null, + "3": null, + "4": "JgVorK4gwNo=", + "5": [], + "6": [ + "/cSCg76PeeDU8k9/8VDoCg==", + "/oAAAAAAAAAkBWisriDA2g==", + "/YyzDI0GAAEI590S93bZ+g==" + ], + "7": 4 + } + ], + "0/51/1": 23, + "0/51/2": 110, + "0/51/3": 6840, + "0/51/4": 1, + "0/51/8": false, + "0/51/65532": 0, + "0/51/65533": 1, + "0/51/65528": [], + "0/51/65529": [0], + "0/51/65531": [0, 1, 2, 3, 4, 8, 65528, 65529, 65531, 65532, 65533], + "0/60/0": 0, + "0/60/1": null, + "0/60/2": null, + "0/60/65532": 0, + "0/60/65533": 1, + "0/60/65528": [], + "0/60/65529": [0, 1, 2], + "0/60/65531": [0, 1, 2, 65528, 65529, 65531, 65532, 65533], + "0/62/0": [], + "0/62/1": [], + "0/62/2": 5, + "0/62/3": 5, + "0/62/4": [ + "FTABAQAkAgE3AycU3mS65o4n65AmFdZw72wYJgQxwoAuJAUANwYnFN5kuuaOJ+uQJhXWcO9sGCQHASQIATAJQQQdNLSJLh6Ew+9dc42ZSEaQD2i1mavRjPh7ERTyLn8CmfJWgG9s4LZKLdh1Qu5gz5wiKQtzQwLmvjEVyMbO7YwDNwo1ASkBGCQCYDAEFG7exdou0CWA9KDmSWy1OVdhMBKHMAUUbt7F2i7QJYD0oOZJbLU5V2EwEocYMAtAF3IcZnJT290miGeEgwDYwxCO383N3BO+F5ESozS503RetTDlxunlA1cPDTKdyPRksfD14zu5erZ51aPKHxa2Qhg=", + "FTABAQAkAgE3AycUi1H2tJ00+fUkFQEYJgRfkd0uJAUANwYnFItR9rSdNPn1JBUBGCQHASQIATAJQQS9bdXZ/ocAnGmFJBkbm6+buMcdLgy3kQnyiIJ0gPArOweblS5eFfXnRSBWP7QcV7Nd7yiAUNncF+0kMrbpjEX+Nwo1ASkBGCQCYDAEFON8FiGqis2G9n3okV7J/BquBFbUMAUU43wWIaqKzYb2feiRXsn8Gq4EVtQYMAtAVYvBt/DVrSHJdjHZ7Spdtn3amDLOsTNzjsQcBOyESjCH43ZsgKQXmgqSXh+DS4qBNJm0eVo+Vn2gbhOlqubYMBg=", + "FTABAQEkAgE3AyQUARgmBIAigScmBYAlTTo3BiQUARgkBwEkCAEwCUEEUVnmOqdwGAsJNKvBP6t8dNPIV8vb+7vMEdmLTlDtli9YsaJCIhfOAGWRQROt8++O953j/fnjmO6BiAKctAnrxTcKNQEpARgkAmAwBBQrF7Zs6XmGG6lbxviD1v3sViKTrDAFFCsXtmzpeYYbqVvG+IPW/exWIpOsGDALQOe8gq02WhNZYr3kUdGqSKmcl1yFgBY80ebOduJb4lzLWgCq527c8xUZjxx4fFsP9A/K8GqHwQ3mZ2+5/riGunsY", + "FTABAQEkAgE3AyyEAlVTLAcGR29vZ2xlLAELTWF0dGVyIFJvb3QnFAEAAAD+////GCYEf9JDKSYFf5Rb5TcGLIQCVVMsBwZHb29nbGUsAQtNYXR0ZXIgUm9vdCcUAQAAAP7///8YJAcBJAgBMAlBBFs332VJwg3I1yKmuKy2YKinZM57r2xsIk9+6ENJaErX2An/ZQAz0VJ9zx+6rGqcOti0HtrJCfe1x2D9VCyJI3U3CjUBKQEkAgEYJAJgMAQUcsIB91cZE7NIygDKe0X0d0ZoyX4wBRRywgH3VxkTs0jKAMp7RfR3RmjJfhgwC0BlFksWat/xjBVhCozpG9cD6cH2d7cRzhM1BRUt8NoVERZ1rFWRzueGhRzdnv2tKWZ0vryyo6Mgm83nswnbVSxvGA==", + "FTABAQAkAgE3AyYU4K5SDiYVI+Px/RgmBFfPHS8kBQA3BiYU4K5SDiYVI+Px/RgkBwEkCAEwCUEE/TWWQD6IXIqrlp/p0JaU1cWtFS88ERh82o2TP6qME9opV5HUntiUCAhRLHnIWtYZ4pubaOWUFoIp61NEP7tuUDcKNQEpARgkAmAwBBQ6xz8FGl9kRhSgC0R+nqgacfJGiDAFFDrHPwUaX2RGFKALRH6eqBpx8kaIGDALQLo8R2G//5ZeXJcE5MQ3YbJ0AJl0Ik97fKD6i/Kx2aGK2oumz3pyAsWd4gVWQxShlFdhoBhv27/HxvP3C9U++k0Y" + ], + "0/62/5": 4, + "0/62/65532": 0, + "0/62/65533": 1, + "0/62/65528": [1, 3, 5, 8], + "0/62/65529": [0, 2, 4, 6, 7, 9, 10, 11], + "0/62/65531": [0, 1, 2, 3, 4, 5, 65528, 65529, 65531, 65532, 65533], + "0/63/0": [], + "0/63/1": [], + "0/63/2": 4, + "0/63/3": 3, + "0/63/65532": 0, + "0/63/65533": 1, + "0/63/65528": [2, 5], + "0/63/65529": [0, 1, 3, 4], + "0/63/65531": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533], + "1/3/0": 0, + "1/3/1": 4, + "1/3/65532": 0, + "1/3/65533": 4, + "1/3/65528": [], + "1/3/65529": [0, 64], + "1/3/65531": [0, 1, 65528, 65529, 65531, 65532, 65533], + "1/29/0": [ + { + "0": 769, + "1": 2 + } + ], + "1/29/1": [3, 29, 513, 1029], + "1/29/2": [], + "1/29/3": [], + "1/29/65532": 0, + "1/29/65533": 1, + "1/29/65528": [], + "1/29/65529": [], + "1/29/65531": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533], + "1/513/0": 2090, + "1/513/3": 500, + "1/513/4": 3000, + "1/513/18": 1800, + "1/513/27": 2, + "1/513/28": 0, + "1/513/65532": 1, + "1/513/65533": 5, + "1/513/65528": [], + "1/513/65529": [0], + "1/513/65531": [0, 3, 4, 18, 27, 28, 65528, 65529, 65531, 65532, 65533], + "1/1029/0": 7492, + "1/1029/1": 0, + "1/1029/2": 10000, + "1/1029/65532": 0, + "1/1029/65533": 3, + "1/1029/65528": [], + "1/1029/65529": [], + "1/1029/65531": [0, 1, 2, 65528, 65529, 65531, 65532, 65533] + }, + "attribute_subscriptions": [] +} diff --git a/tests/components/matter/snapshots/test_button.ambr b/tests/components/matter/snapshots/test_button.ambr index 39c8f66dfd950..c16f66a5e88bf 100644 --- a/tests/components/matter/snapshots/test_button.ambr +++ b/tests/components/matter/snapshots/test_button.ambr @@ -2282,6 +2282,55 @@ 'state': 'unknown', }) # --- +# name: test_buttons[tado_smart_radiator_thermostat_x][button.smart_radiator_thermostat_x_identify-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': , + 'entity_id': 'button.smart_radiator_thermostat_x_identify', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Identify', + 'platform': 'matter', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '00000000000004D2-000000000000000C-MatterNodeDevice-1-IdentifyButton-3-1', + 'unit_of_measurement': None, + }) +# --- +# name: test_buttons[tado_smart_radiator_thermostat_x][button.smart_radiator_thermostat_x_identify-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'identify', + 'friendly_name': 'Smart Radiator Thermostat X Identify', + }), + 'context': , + 'entity_id': 'button.smart_radiator_thermostat_x_identify', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- # name: test_buttons[temperature_sensor][button.mock_temperature_sensor_identify-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ diff --git a/tests/components/matter/snapshots/test_climate.ambr b/tests/components/matter/snapshots/test_climate.ambr index 07a5a69d801aa..f0745bfe50ca6 100644 --- a/tests/components/matter/snapshots/test_climate.ambr +++ b/tests/components/matter/snapshots/test_climate.ambr @@ -199,6 +199,71 @@ 'state': 'off', }) # --- +# name: test_climates[tado_smart_radiator_thermostat_x][climate.smart_radiator_thermostat_x-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'hvac_modes': list([ + , + , + ]), + 'max_temp': 30.0, + 'min_temp': 5.0, + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'climate', + 'entity_category': None, + 'entity_id': 'climate.smart_radiator_thermostat_x', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': None, + 'platform': 'matter', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': , + 'translation_key': None, + 'unique_id': '00000000000004D2-000000000000000C-MatterNodeDevice-1-MatterThermostat-513-0', + 'unit_of_measurement': None, + }) +# --- +# name: test_climates[tado_smart_radiator_thermostat_x][climate.smart_radiator_thermostat_x-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'current_humidity': 74.92, + 'current_temperature': 20.9, + 'friendly_name': 'Smart Radiator Thermostat X', + 'hvac_modes': list([ + , + , + ]), + 'max_temp': 30.0, + 'min_temp': 5.0, + 'supported_features': , + 'temperature': 18.0, + }), + 'context': , + 'entity_id': 'climate.smart_radiator_thermostat_x', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- # name: test_climates[thermostat][climate.longan_link_hvac-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ diff --git a/tests/components/matter/snapshots/test_sensor.ambr b/tests/components/matter/snapshots/test_sensor.ambr index 911ea0049952f..1f3fc5b0a3569 100644 --- a/tests/components/matter/snapshots/test_sensor.ambr +++ b/tests/components/matter/snapshots/test_sensor.ambr @@ -6791,6 +6791,115 @@ 'state': '234.899', }) # --- +# name: test_sensors[tado_smart_radiator_thermostat_x][sensor.smart_radiator_thermostat_x_humidity-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.smart_radiator_thermostat_x_humidity', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Humidity', + 'platform': 'matter', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '00000000000004D2-000000000000000C-MatterNodeDevice-1-HumiditySensor-1029-0', + 'unit_of_measurement': '%', + }) +# --- +# name: test_sensors[tado_smart_radiator_thermostat_x][sensor.smart_radiator_thermostat_x_humidity-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'humidity', + 'friendly_name': 'Smart Radiator Thermostat X Humidity', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.smart_radiator_thermostat_x_humidity', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '74.92', + }) +# --- +# name: test_sensors[tado_smart_radiator_thermostat_x][sensor.smart_radiator_thermostat_x_temperature-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.smart_radiator_thermostat_x_temperature', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 1, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Temperature', + 'platform': 'matter', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '00000000000004D2-000000000000000C-MatterNodeDevice-1-ThermostatLocalTemperature-513-0', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[tado_smart_radiator_thermostat_x][sensor.smart_radiator_thermostat_x_temperature-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'temperature', + 'friendly_name': 'Smart Radiator Thermostat X Temperature', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.smart_radiator_thermostat_x_temperature', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '20.9', + }) +# --- # name: test_sensors[temperature_sensor][sensor.mock_temperature_sensor_temperature-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ diff --git a/tests/components/matter/test_climate.py b/tests/components/matter/test_climate.py index a887ce1b5df6e..4e9afb4e6969d 100644 --- a/tests/components/matter/test_climate.py +++ b/tests/components/matter/test_climate.py @@ -162,6 +162,59 @@ async def test_thermostat_base( assert state.attributes["temperature"] == 20 +@pytest.mark.parametrize("node_fixture", ["thermostat"]) +async def test_thermostat_humidity( + hass: HomeAssistant, + matter_client: MagicMock, + matter_node: MatterNode, +) -> None: + """Test thermostat humidity attribute and state updates.""" + # test entity attributes + state = hass.states.get("climate.longan_link_hvac") + assert state + + measured_value = clusters.RelativeHumidityMeasurement.Attributes.MeasuredValue + + # test current humidity update from device + set_node_attribute( + matter_node, + 1, + measured_value.cluster_id, + measured_value.attribute_id, + 1234, + ) + await trigger_subscription_callback(hass, matter_client) + state = hass.states.get("climate.longan_link_hvac") + assert state + assert state.attributes["current_humidity"] == 12.34 + + # test current humidity update from device with zero value + set_node_attribute( + matter_node, + 1, + measured_value.cluster_id, + measured_value.attribute_id, + 0, + ) + await trigger_subscription_callback(hass, matter_client) + state = hass.states.get("climate.longan_link_hvac") + assert state + assert state.attributes["current_humidity"] == 0.0 + + # test current humidity update from device with None value + set_node_attribute( + matter_node, + 1, + measured_value.cluster_id, + measured_value.attribute_id, + None, + ) + await trigger_subscription_callback(hass, matter_client) + state = hass.states.get("climate.longan_link_hvac") + assert state + assert "current_humidity" not in state.attributes + + @pytest.mark.parametrize("node_fixture", ["thermostat"]) async def test_thermostat_service_calls( hass: HomeAssistant, diff --git a/tests/components/nordpool/conftest.py b/tests/components/nordpool/conftest.py index ca1e2a05a0b48..2f5318d515c70 100644 --- a/tests/components/nordpool/conftest.py +++ b/tests/components/nordpool/conftest.py @@ -47,7 +47,7 @@ async def get_data_from_library( "GET", url=API + "/DayAheadPrices", params={ - "date": "2024-11-05", + "date": "2025-10-01", "market": "DayAhead", "deliveryArea": "SE3,SE4", "currency": "SEK", @@ -58,7 +58,7 @@ async def get_data_from_library( "GET", url=API + "/DayAheadPrices", params={ - "date": "2024-11-05", + "date": "2025-10-01", "market": "DayAhead", "deliveryArea": "SE3", "currency": "EUR", @@ -69,7 +69,7 @@ async def get_data_from_library( "GET", url=API + "/DayAheadPrices", params={ - "date": "2024-11-04", + "date": "2025-09-30", "market": "DayAhead", "deliveryArea": "SE3,SE4", "currency": "SEK", @@ -80,7 +80,7 @@ async def get_data_from_library( "GET", url=API + "/DayAheadPrices", params={ - "date": "2024-11-06", + "date": "2025-10-02", "market": "DayAhead", "deliveryArea": "SE3,SE4", "currency": "SEK", diff --git a/tests/components/nordpool/fixtures/delivery_period_nl.json b/tests/components/nordpool/fixtures/delivery_period_nl.json index cd326e05d01c4..2c99e5614a297 100644 --- a/tests/components/nordpool/fixtures/delivery_period_nl.json +++ b/tests/components/nordpool/fixtures/delivery_period_nl.json @@ -1,213 +1,717 @@ { - "deliveryDateCET": "2024-11-05", + "deliveryDateCET": "2025-10-01", "version": 2, - "updatedAt": "2024-11-04T11:58:10.7711584Z", + "updatedAt": "2025-09-30T11:08:13.1885499Z", "deliveryAreas": ["NL"], "market": "DayAhead", "multiAreaEntries": [ { - "deliveryStart": "2024-11-04T23:00:00Z", - "deliveryEnd": "2024-11-05T00:00:00Z", + "deliveryStart": "2025-09-30T22:00:00Z", + "deliveryEnd": "2025-09-30T22:15:00Z", "entryPerArea": { - "NL": 83.63 + "NL": 102.55 } }, { - "deliveryStart": "2024-11-05T00:00:00Z", - "deliveryEnd": "2024-11-05T01:00:00Z", + "deliveryStart": "2025-09-30T22:15:00Z", + "deliveryEnd": "2025-09-30T22:30:00Z", "entryPerArea": { - "NL": 94.0 + "NL": 92.17 } }, { - "deliveryStart": "2024-11-05T01:00:00Z", - "deliveryEnd": "2024-11-05T02:00:00Z", + "deliveryStart": "2025-09-30T22:30:00Z", + "deliveryEnd": "2025-09-30T22:45:00Z", "entryPerArea": { - "NL": 90.68 + "NL": 82.69 } }, { - "deliveryStart": "2024-11-05T02:00:00Z", - "deliveryEnd": "2024-11-05T03:00:00Z", + "deliveryStart": "2025-09-30T22:45:00Z", + "deliveryEnd": "2025-09-30T23:00:00Z", "entryPerArea": { - "NL": 91.3 + "NL": 81.86 } }, { - "deliveryStart": "2024-11-05T03:00:00Z", - "deliveryEnd": "2024-11-05T04:00:00Z", + "deliveryStart": "2025-09-30T23:00:00Z", + "deliveryEnd": "2025-09-30T23:15:00Z", "entryPerArea": { - "NL": 94.0 + "NL": 89.54 } }, { - "deliveryStart": "2024-11-05T04:00:00Z", - "deliveryEnd": "2024-11-05T05:00:00Z", + "deliveryStart": "2025-09-30T23:15:00Z", + "deliveryEnd": "2025-09-30T23:30:00Z", "entryPerArea": { - "NL": 96.09 + "NL": 84.93 } }, { - "deliveryStart": "2024-11-05T05:00:00Z", - "deliveryEnd": "2024-11-05T06:00:00Z", + "deliveryStart": "2025-09-30T23:30:00Z", + "deliveryEnd": "2025-09-30T23:45:00Z", "entryPerArea": { - "NL": 106.0 + "NL": 83.56 } }, { - "deliveryStart": "2024-11-05T06:00:00Z", - "deliveryEnd": "2024-11-05T07:00:00Z", + "deliveryStart": "2025-09-30T23:45:00Z", + "deliveryEnd": "2025-10-01T00:00:00Z", "entryPerArea": { - "NL": 135.99 + "NL": 81.69 } }, { - "deliveryStart": "2024-11-05T07:00:00Z", - "deliveryEnd": "2024-11-05T08:00:00Z", + "deliveryStart": "2025-10-01T00:00:00Z", + "deliveryEnd": "2025-10-01T00:15:00Z", "entryPerArea": { - "NL": 136.21 + "NL": 81.87 } }, { - "deliveryStart": "2024-11-05T08:00:00Z", - "deliveryEnd": "2024-11-05T09:00:00Z", + "deliveryStart": "2025-10-01T00:15:00Z", + "deliveryEnd": "2025-10-01T00:30:00Z", "entryPerArea": { - "NL": 118.23 + "NL": 81.51 } }, { - "deliveryStart": "2024-11-05T09:00:00Z", - "deliveryEnd": "2024-11-05T10:00:00Z", + "deliveryStart": "2025-10-01T00:30:00Z", + "deliveryEnd": "2025-10-01T00:45:00Z", "entryPerArea": { - "NL": 105.87 + "NL": 77.42 } }, { - "deliveryStart": "2024-11-05T10:00:00Z", - "deliveryEnd": "2024-11-05T11:00:00Z", + "deliveryStart": "2025-10-01T00:45:00Z", + "deliveryEnd": "2025-10-01T01:00:00Z", "entryPerArea": { - "NL": 95.28 + "NL": 76.45 } }, { - "deliveryStart": "2024-11-05T11:00:00Z", - "deliveryEnd": "2024-11-05T12:00:00Z", + "deliveryStart": "2025-10-01T01:00:00Z", + "deliveryEnd": "2025-10-01T01:15:00Z", "entryPerArea": { - "NL": 94.92 + "NL": 79.32 } }, { - "deliveryStart": "2024-11-05T12:00:00Z", - "deliveryEnd": "2024-11-05T13:00:00Z", + "deliveryStart": "2025-10-01T01:15:00Z", + "deliveryEnd": "2025-10-01T01:30:00Z", "entryPerArea": { - "NL": 99.25 + "NL": 79.24 } }, { - "deliveryStart": "2024-11-05T13:00:00Z", - "deliveryEnd": "2024-11-05T14:00:00Z", + "deliveryStart": "2025-10-01T01:30:00Z", + "deliveryEnd": "2025-10-01T01:45:00Z", "entryPerArea": { - "NL": 107.98 + "NL": 80.05 } }, { - "deliveryStart": "2024-11-05T14:00:00Z", - "deliveryEnd": "2024-11-05T15:00:00Z", + "deliveryStart": "2025-10-01T01:45:00Z", + "deliveryEnd": "2025-10-01T02:00:00Z", "entryPerArea": { - "NL": 149.86 + "NL": 79.52 } }, { - "deliveryStart": "2024-11-05T15:00:00Z", - "deliveryEnd": "2024-11-05T16:00:00Z", + "deliveryStart": "2025-10-01T02:00:00Z", + "deliveryEnd": "2025-10-01T02:15:00Z", "entryPerArea": { - "NL": 303.24 + "NL": 79.94 } }, { - "deliveryStart": "2024-11-05T16:00:00Z", - "deliveryEnd": "2024-11-05T17:00:00Z", + "deliveryStart": "2025-10-01T02:15:00Z", + "deliveryEnd": "2025-10-01T02:30:00Z", "entryPerArea": { - "NL": 472.99 + "NL": 85.02 } }, { - "deliveryStart": "2024-11-05T17:00:00Z", - "deliveryEnd": "2024-11-05T18:00:00Z", + "deliveryStart": "2025-10-01T02:30:00Z", + "deliveryEnd": "2025-10-01T02:45:00Z", "entryPerArea": { - "NL": 431.02 + "NL": 83.89 } }, { - "deliveryStart": "2024-11-05T18:00:00Z", - "deliveryEnd": "2024-11-05T19:00:00Z", + "deliveryStart": "2025-10-01T02:45:00Z", + "deliveryEnd": "2025-10-01T03:00:00Z", "entryPerArea": { - "NL": 320.33 + "NL": 75.83 } }, { - "deliveryStart": "2024-11-05T19:00:00Z", - "deliveryEnd": "2024-11-05T20:00:00Z", + "deliveryStart": "2025-10-01T03:00:00Z", + "deliveryEnd": "2025-10-01T03:15:00Z", "entryPerArea": { - "NL": 169.7 + "NL": 75.01 } }, { - "deliveryStart": "2024-11-05T20:00:00Z", - "deliveryEnd": "2024-11-05T21:00:00Z", + "deliveryStart": "2025-10-01T03:15:00Z", + "deliveryEnd": "2025-10-01T03:30:00Z", "entryPerArea": { - "NL": 129.9 + "NL": 80.88 } }, { - "deliveryStart": "2024-11-05T21:00:00Z", - "deliveryEnd": "2024-11-05T22:00:00Z", + "deliveryStart": "2025-10-01T03:30:00Z", + "deliveryEnd": "2025-10-01T03:45:00Z", "entryPerArea": { - "NL": 117.77 + "NL": 88.18 } }, { - "deliveryStart": "2024-11-05T22:00:00Z", - "deliveryEnd": "2024-11-05T23:00:00Z", + "deliveryStart": "2025-10-01T03:45:00Z", + "deliveryEnd": "2025-10-01T04:00:00Z", "entryPerArea": { - "NL": 110.03 + "NL": 97.34 + } + }, + { + "deliveryStart": "2025-10-01T04:00:00Z", + "deliveryEnd": "2025-10-01T04:15:00Z", + "entryPerArea": { + "NL": 87.65 + } + }, + { + "deliveryStart": "2025-10-01T04:15:00Z", + "deliveryEnd": "2025-10-01T04:30:00Z", + "entryPerArea": { + "NL": 107.93 + } + }, + { + "deliveryStart": "2025-10-01T04:30:00Z", + "deliveryEnd": "2025-10-01T04:45:00Z", + "entryPerArea": { + "NL": 123.95 + } + }, + { + "deliveryStart": "2025-10-01T04:45:00Z", + "deliveryEnd": "2025-10-01T05:00:00Z", + "entryPerArea": { + "NL": 143.66 + } + }, + { + "deliveryStart": "2025-10-01T05:00:00Z", + "deliveryEnd": "2025-10-01T05:15:00Z", + "entryPerArea": { + "NL": 150.66 + } + }, + { + "deliveryStart": "2025-10-01T05:15:00Z", + "deliveryEnd": "2025-10-01T05:30:00Z", + "entryPerArea": { + "NL": 171.48 + } + }, + { + "deliveryStart": "2025-10-01T05:30:00Z", + "deliveryEnd": "2025-10-01T05:45:00Z", + "entryPerArea": { + "NL": 172.01 + } + }, + { + "deliveryStart": "2025-10-01T05:45:00Z", + "deliveryEnd": "2025-10-01T06:00:00Z", + "entryPerArea": { + "NL": 163.35 + } + }, + { + "deliveryStart": "2025-10-01T06:00:00Z", + "deliveryEnd": "2025-10-01T06:15:00Z", + "entryPerArea": { + "NL": 198.33 + } + }, + { + "deliveryStart": "2025-10-01T06:15:00Z", + "deliveryEnd": "2025-10-01T06:30:00Z", + "entryPerArea": { + "NL": 142.86 + } + }, + { + "deliveryStart": "2025-10-01T06:30:00Z", + "deliveryEnd": "2025-10-01T06:45:00Z", + "entryPerArea": { + "NL": 117.23 + } + }, + { + "deliveryStart": "2025-10-01T06:45:00Z", + "deliveryEnd": "2025-10-01T07:00:00Z", + "entryPerArea": { + "NL": 95.25 + } + }, + { + "deliveryStart": "2025-10-01T07:00:00Z", + "deliveryEnd": "2025-10-01T07:15:00Z", + "entryPerArea": { + "NL": 139.01 + } + }, + { + "deliveryStart": "2025-10-01T07:15:00Z", + "deliveryEnd": "2025-10-01T07:30:00Z", + "entryPerArea": { + "NL": 105.01 + } + }, + { + "deliveryStart": "2025-10-01T07:30:00Z", + "deliveryEnd": "2025-10-01T07:45:00Z", + "entryPerArea": { + "NL": 93.48 + } + }, + { + "deliveryStart": "2025-10-01T07:45:00Z", + "deliveryEnd": "2025-10-01T08:00:00Z", + "entryPerArea": { + "NL": 79.96 + } + }, + { + "deliveryStart": "2025-10-01T08:00:00Z", + "deliveryEnd": "2025-10-01T08:15:00Z", + "entryPerArea": { + "NL": 102.82 + } + }, + { + "deliveryStart": "2025-10-01T08:15:00Z", + "deliveryEnd": "2025-10-01T08:30:00Z", + "entryPerArea": { + "NL": 89.23 + } + }, + { + "deliveryStart": "2025-10-01T08:30:00Z", + "deliveryEnd": "2025-10-01T08:45:00Z", + "entryPerArea": { + "NL": 78.16 + } + }, + { + "deliveryStart": "2025-10-01T08:45:00Z", + "deliveryEnd": "2025-10-01T09:00:00Z", + "entryPerArea": { + "NL": 63.7 + } + }, + { + "deliveryStart": "2025-10-01T09:00:00Z", + "deliveryEnd": "2025-10-01T09:15:00Z", + "entryPerArea": { + "NL": 79.97 + } + }, + { + "deliveryStart": "2025-10-01T09:15:00Z", + "deliveryEnd": "2025-10-01T09:30:00Z", + "entryPerArea": { + "NL": 68.06 + } + }, + { + "deliveryStart": "2025-10-01T09:30:00Z", + "deliveryEnd": "2025-10-01T09:45:00Z", + "entryPerArea": { + "NL": 61.13 + } + }, + { + "deliveryStart": "2025-10-01T09:45:00Z", + "deliveryEnd": "2025-10-01T10:00:00Z", + "entryPerArea": { + "NL": 56.19 + } + }, + { + "deliveryStart": "2025-10-01T10:00:00Z", + "deliveryEnd": "2025-10-01T10:15:00Z", + "entryPerArea": { + "NL": 61.69 + } + }, + { + "deliveryStart": "2025-10-01T10:15:00Z", + "deliveryEnd": "2025-10-01T10:30:00Z", + "entryPerArea": { + "NL": 57.42 + } + }, + { + "deliveryStart": "2025-10-01T10:30:00Z", + "deliveryEnd": "2025-10-01T10:45:00Z", + "entryPerArea": { + "NL": 57.86 + } + }, + { + "deliveryStart": "2025-10-01T10:45:00Z", + "deliveryEnd": "2025-10-01T11:00:00Z", + "entryPerArea": { + "NL": 57.42 + } + }, + { + "deliveryStart": "2025-10-01T11:00:00Z", + "deliveryEnd": "2025-10-01T11:15:00Z", + "entryPerArea": { + "NL": 57.09 + } + }, + { + "deliveryStart": "2025-10-01T11:15:00Z", + "deliveryEnd": "2025-10-01T11:30:00Z", + "entryPerArea": { + "NL": 58.78 + } + }, + { + "deliveryStart": "2025-10-01T11:30:00Z", + "deliveryEnd": "2025-10-01T11:45:00Z", + "entryPerArea": { + "NL": 60.07 + } + }, + { + "deliveryStart": "2025-10-01T11:45:00Z", + "deliveryEnd": "2025-10-01T12:00:00Z", + "entryPerArea": { + "NL": 61.14 + } + }, + { + "deliveryStart": "2025-10-01T12:00:00Z", + "deliveryEnd": "2025-10-01T12:15:00Z", + "entryPerArea": { + "NL": 54.35 + } + }, + { + "deliveryStart": "2025-10-01T12:15:00Z", + "deliveryEnd": "2025-10-01T12:30:00Z", + "entryPerArea": { + "NL": 60.62 + } + }, + { + "deliveryStart": "2025-10-01T12:30:00Z", + "deliveryEnd": "2025-10-01T12:45:00Z", + "entryPerArea": { + "NL": 64.4 + } + }, + { + "deliveryStart": "2025-10-01T12:45:00Z", + "deliveryEnd": "2025-10-01T13:00:00Z", + "entryPerArea": { + "NL": 71.9 + } + }, + { + "deliveryStart": "2025-10-01T13:00:00Z", + "deliveryEnd": "2025-10-01T13:15:00Z", + "entryPerArea": { + "NL": 57.55 + } + }, + { + "deliveryStart": "2025-10-01T13:15:00Z", + "deliveryEnd": "2025-10-01T13:30:00Z", + "entryPerArea": { + "NL": 66.28 + } + }, + { + "deliveryStart": "2025-10-01T13:30:00Z", + "deliveryEnd": "2025-10-01T13:45:00Z", + "entryPerArea": { + "NL": 77.91 + } + }, + { + "deliveryStart": "2025-10-01T13:45:00Z", + "deliveryEnd": "2025-10-01T14:00:00Z", + "entryPerArea": { + "NL": 88.62 + } + }, + { + "deliveryStart": "2025-10-01T14:00:00Z", + "deliveryEnd": "2025-10-01T14:15:00Z", + "entryPerArea": { + "NL": 55.07 + } + }, + { + "deliveryStart": "2025-10-01T14:15:00Z", + "deliveryEnd": "2025-10-01T14:30:00Z", + "entryPerArea": { + "NL": 80.77 + } + }, + { + "deliveryStart": "2025-10-01T14:30:00Z", + "deliveryEnd": "2025-10-01T14:45:00Z", + "entryPerArea": { + "NL": 95.16 + } + }, + { + "deliveryStart": "2025-10-01T14:45:00Z", + "deliveryEnd": "2025-10-01T15:00:00Z", + "entryPerArea": { + "NL": 109.0 + } + }, + { + "deliveryStart": "2025-10-01T15:00:00Z", + "deliveryEnd": "2025-10-01T15:15:00Z", + "entryPerArea": { + "NL": 76.45 + } + }, + { + "deliveryStart": "2025-10-01T15:15:00Z", + "deliveryEnd": "2025-10-01T15:30:00Z", + "entryPerArea": { + "NL": 106.42 + } + }, + { + "deliveryStart": "2025-10-01T15:30:00Z", + "deliveryEnd": "2025-10-01T15:45:00Z", + "entryPerArea": { + "NL": 139.35 + } + }, + { + "deliveryStart": "2025-10-01T15:45:00Z", + "deliveryEnd": "2025-10-01T16:00:00Z", + "entryPerArea": { + "NL": 190.18 + } + }, + { + "deliveryStart": "2025-10-01T16:00:00Z", + "deliveryEnd": "2025-10-01T16:15:00Z", + "entryPerArea": { + "NL": 141.68 + } + }, + { + "deliveryStart": "2025-10-01T16:15:00Z", + "deliveryEnd": "2025-10-01T16:30:00Z", + "entryPerArea": { + "NL": 192.84 + } + }, + { + "deliveryStart": "2025-10-01T16:30:00Z", + "deliveryEnd": "2025-10-01T16:45:00Z", + "entryPerArea": { + "NL": 285.0 + } + }, + { + "deliveryStart": "2025-10-01T16:45:00Z", + "deliveryEnd": "2025-10-01T17:00:00Z", + "entryPerArea": { + "NL": 381.0 + } + }, + { + "deliveryStart": "2025-10-01T17:00:00Z", + "deliveryEnd": "2025-10-01T17:15:00Z", + "entryPerArea": { + "NL": 408.5 + } + }, + { + "deliveryStart": "2025-10-01T17:15:00Z", + "deliveryEnd": "2025-10-01T17:30:00Z", + "entryPerArea": { + "NL": 376.39 + } + }, + { + "deliveryStart": "2025-10-01T17:30:00Z", + "deliveryEnd": "2025-10-01T17:45:00Z", + "entryPerArea": { + "NL": 321.94 + } + }, + { + "deliveryStart": "2025-10-01T17:45:00Z", + "deliveryEnd": "2025-10-01T18:00:00Z", + "entryPerArea": { + "NL": 253.14 + } + }, + { + "deliveryStart": "2025-10-01T18:00:00Z", + "deliveryEnd": "2025-10-01T18:15:00Z", + "entryPerArea": { + "NL": 217.5 + } + }, + { + "deliveryStart": "2025-10-01T18:15:00Z", + "deliveryEnd": "2025-10-01T18:30:00Z", + "entryPerArea": { + "NL": 154.56 + } + }, + { + "deliveryStart": "2025-10-01T18:30:00Z", + "deliveryEnd": "2025-10-01T18:45:00Z", + "entryPerArea": { + "NL": 123.11 + } + }, + { + "deliveryStart": "2025-10-01T18:45:00Z", + "deliveryEnd": "2025-10-01T19:00:00Z", + "entryPerArea": { + "NL": 104.83 + } + }, + { + "deliveryStart": "2025-10-01T19:00:00Z", + "deliveryEnd": "2025-10-01T19:15:00Z", + "entryPerArea": { + "NL": 125.76 + } + }, + { + "deliveryStart": "2025-10-01T19:15:00Z", + "deliveryEnd": "2025-10-01T19:30:00Z", + "entryPerArea": { + "NL": 115.82 + } + }, + { + "deliveryStart": "2025-10-01T19:30:00Z", + "deliveryEnd": "2025-10-01T19:45:00Z", + "entryPerArea": { + "NL": 97.54 + } + }, + { + "deliveryStart": "2025-10-01T19:45:00Z", + "deliveryEnd": "2025-10-01T20:00:00Z", + "entryPerArea": { + "NL": 87.96 + } + }, + { + "deliveryStart": "2025-10-01T20:00:00Z", + "deliveryEnd": "2025-10-01T20:15:00Z", + "entryPerArea": { + "NL": 106.69 + } + }, + { + "deliveryStart": "2025-10-01T20:15:00Z", + "deliveryEnd": "2025-10-01T20:30:00Z", + "entryPerArea": { + "NL": 98.76 + } + }, + { + "deliveryStart": "2025-10-01T20:30:00Z", + "deliveryEnd": "2025-10-01T20:45:00Z", + "entryPerArea": { + "NL": 95.32 + } + }, + { + "deliveryStart": "2025-10-01T20:45:00Z", + "deliveryEnd": "2025-10-01T21:00:00Z", + "entryPerArea": { + "NL": 88.02 + } + }, + { + "deliveryStart": "2025-10-01T21:00:00Z", + "deliveryEnd": "2025-10-01T21:15:00Z", + "entryPerArea": { + "NL": 93.53 + } + }, + { + "deliveryStart": "2025-10-01T21:15:00Z", + "deliveryEnd": "2025-10-01T21:30:00Z", + "entryPerArea": { + "NL": 88.75 + } + }, + { + "deliveryStart": "2025-10-01T21:30:00Z", + "deliveryEnd": "2025-10-01T21:45:00Z", + "entryPerArea": { + "NL": 90.62 + } + }, + { + "deliveryStart": "2025-10-01T21:45:00Z", + "deliveryEnd": "2025-10-01T22:00:00Z", + "entryPerArea": { + "NL": 82.6 } } ], "blockPriceAggregates": [ { "blockName": "Off-peak 1", - "deliveryStart": "2024-11-04T23:00:00Z", - "deliveryEnd": "2024-11-05T07:00:00Z", + "deliveryStart": "2025-09-30T22:00:00Z", + "deliveryEnd": "2025-10-01T06:00:00Z", "averagePricePerArea": { "NL": { - "average": 98.96, - "min": 83.63, - "max": 135.99 + "average": 97.54, + "min": 75.01, + "max": 172.01 } } }, { "blockName": "Peak", - "deliveryStart": "2024-11-05T07:00:00Z", - "deliveryEnd": "2024-11-05T19:00:00Z", + "deliveryStart": "2025-10-01T06:00:00Z", + "deliveryEnd": "2025-10-01T18:00:00Z", "averagePricePerArea": { "NL": { - "average": 202.93, - "min": 94.92, - "max": 472.99 + "average": 120.76, + "min": 54.35, + "max": 408.5 } } }, { "blockName": "Off-peak 2", - "deliveryStart": "2024-11-05T19:00:00Z", - "deliveryEnd": "2024-11-05T23:00:00Z", + "deliveryStart": "2025-10-01T18:00:00Z", + "deliveryEnd": "2025-10-01T22:00:00Z", "averagePricePerArea": { "NL": { - "average": 131.85, - "min": 110.03, - "max": 169.7 + "average": 110.71, + "min": 82.6, + "max": 217.5 } } } @@ -223,7 +727,7 @@ "areaAverages": [ { "areaCode": "NL", - "price": 156.43 + "price": 111.34 } ] } diff --git a/tests/components/nordpool/fixtures/delivery_period_today.json b/tests/components/nordpool/fixtures/delivery_period_today.json index df48c32a9a97f..ecd7b3868021a 100644 --- a/tests/components/nordpool/fixtures/delivery_period_today.json +++ b/tests/components/nordpool/fixtures/delivery_period_today.json @@ -1,258 +1,834 @@ { - "deliveryDateCET": "2024-11-05", + "deliveryDateCET": "2025-10-01", "version": 3, - "updatedAt": "2024-11-04T12:15:03.9456464Z", + "updatedAt": "2025-09-30T12:08:16.4448023Z", "deliveryAreas": ["SE3", "SE4"], "market": "DayAhead", "multiAreaEntries": [ { - "deliveryStart": "2024-11-04T23:00:00Z", - "deliveryEnd": "2024-11-05T00:00:00Z", + "deliveryStart": "2025-09-30T22:00:00Z", + "deliveryEnd": "2025-09-30T22:15:00Z", "entryPerArea": { - "SE3": 250.73, - "SE4": 283.79 + "SE3": 556.68, + "SE4": 642.22 } }, { - "deliveryStart": "2024-11-05T00:00:00Z", - "deliveryEnd": "2024-11-05T01:00:00Z", + "deliveryStart": "2025-09-30T22:15:00Z", + "deliveryEnd": "2025-09-30T22:30:00Z", "entryPerArea": { - "SE3": 76.36, - "SE4": 81.36 + "SE3": 519.88, + "SE4": 600.12 } }, { - "deliveryStart": "2024-11-05T01:00:00Z", - "deliveryEnd": "2024-11-05T02:00:00Z", + "deliveryStart": "2025-09-30T22:30:00Z", + "deliveryEnd": "2025-09-30T22:45:00Z", "entryPerArea": { - "SE3": 73.92, - "SE4": 79.15 + "SE3": 508.28, + "SE4": 586.3 } }, { - "deliveryStart": "2024-11-05T02:00:00Z", - "deliveryEnd": "2024-11-05T03:00:00Z", + "deliveryStart": "2025-09-30T22:45:00Z", + "deliveryEnd": "2025-09-30T23:00:00Z", "entryPerArea": { - "SE3": 61.69, - "SE4": 65.19 + "SE3": 509.93, + "SE4": 589.62 } }, { - "deliveryStart": "2024-11-05T03:00:00Z", - "deliveryEnd": "2024-11-05T04:00:00Z", + "deliveryStart": "2025-09-30T23:00:00Z", + "deliveryEnd": "2025-09-30T23:15:00Z", "entryPerArea": { - "SE3": 64.6, - "SE4": 68.44 + "SE3": 501.64, + "SE4": 577.24 } }, { - "deliveryStart": "2024-11-05T04:00:00Z", - "deliveryEnd": "2024-11-05T05:00:00Z", + "deliveryStart": "2025-09-30T23:15:00Z", + "deliveryEnd": "2025-09-30T23:30:00Z", "entryPerArea": { - "SE3": 453.27, - "SE4": 516.71 + "SE3": 509.05, + "SE4": 585.42 } }, { - "deliveryStart": "2024-11-05T05:00:00Z", - "deliveryEnd": "2024-11-05T06:00:00Z", + "deliveryStart": "2025-09-30T23:30:00Z", + "deliveryEnd": "2025-09-30T23:45:00Z", "entryPerArea": { - "SE3": 996.28, - "SE4": 1240.85 + "SE3": 491.03, + "SE4": 567.18 } }, { - "deliveryStart": "2024-11-05T06:00:00Z", - "deliveryEnd": "2024-11-05T07:00:00Z", + "deliveryStart": "2025-09-30T23:45:00Z", + "deliveryEnd": "2025-10-01T00:00:00Z", "entryPerArea": { - "SE3": 1406.14, - "SE4": 1648.25 + "SE3": 442.07, + "SE4": 517.45 } }, { - "deliveryStart": "2024-11-05T07:00:00Z", - "deliveryEnd": "2024-11-05T08:00:00Z", + "deliveryStart": "2025-10-01T00:00:00Z", + "deliveryEnd": "2025-10-01T00:15:00Z", "entryPerArea": { - "SE3": 1346.54, - "SE4": 1570.5 + "SE3": 504.08, + "SE4": 580.55 } }, { - "deliveryStart": "2024-11-05T08:00:00Z", - "deliveryEnd": "2024-11-05T09:00:00Z", + "deliveryStart": "2025-10-01T00:15:00Z", + "deliveryEnd": "2025-10-01T00:30:00Z", "entryPerArea": { - "SE3": 1150.28, - "SE4": 1345.37 + "SE3": 504.85, + "SE4": 581.55 } }, { - "deliveryStart": "2024-11-05T09:00:00Z", - "deliveryEnd": "2024-11-05T10:00:00Z", + "deliveryStart": "2025-10-01T00:30:00Z", + "deliveryEnd": "2025-10-01T00:45:00Z", "entryPerArea": { - "SE3": 1031.32, - "SE4": 1206.51 + "SE3": 504.3, + "SE4": 580.78 } }, { - "deliveryStart": "2024-11-05T10:00:00Z", - "deliveryEnd": "2024-11-05T11:00:00Z", + "deliveryStart": "2025-10-01T00:45:00Z", + "deliveryEnd": "2025-10-01T01:00:00Z", "entryPerArea": { - "SE3": 927.37, - "SE4": 1085.8 + "SE3": 506.29, + "SE4": 583.1 } }, { - "deliveryStart": "2024-11-05T11:00:00Z", - "deliveryEnd": "2024-11-05T12:00:00Z", + "deliveryStart": "2025-10-01T01:00:00Z", + "deliveryEnd": "2025-10-01T01:15:00Z", "entryPerArea": { - "SE3": 925.05, - "SE4": 1081.72 + "SE3": 442.07, + "SE4": 515.46 } }, { - "deliveryStart": "2024-11-05T12:00:00Z", - "deliveryEnd": "2024-11-05T13:00:00Z", + "deliveryStart": "2025-10-01T01:15:00Z", + "deliveryEnd": "2025-10-01T01:30:00Z", "entryPerArea": { - "SE3": 949.49, - "SE4": 1130.38 + "SE3": 441.96, + "SE4": 517.23 } }, { - "deliveryStart": "2024-11-05T13:00:00Z", - "deliveryEnd": "2024-11-05T14:00:00Z", + "deliveryStart": "2025-10-01T01:30:00Z", + "deliveryEnd": "2025-10-01T01:45:00Z", "entryPerArea": { - "SE3": 1042.03, - "SE4": 1256.91 + "SE3": 442.07, + "SE4": 516.23 } }, { - "deliveryStart": "2024-11-05T14:00:00Z", - "deliveryEnd": "2024-11-05T15:00:00Z", + "deliveryStart": "2025-10-01T01:45:00Z", + "deliveryEnd": "2025-10-01T02:00:00Z", "entryPerArea": { - "SE3": 1258.89, - "SE4": 1765.82 + "SE3": 442.07, + "SE4": 516.23 } }, { - "deliveryStart": "2024-11-05T15:00:00Z", - "deliveryEnd": "2024-11-05T16:00:00Z", + "deliveryStart": "2025-10-01T02:00:00Z", + "deliveryEnd": "2025-10-01T02:15:00Z", "entryPerArea": { - "SE3": 1816.45, - "SE4": 2522.55 + "SE3": 441.96, + "SE4": 517.34 } }, { - "deliveryStart": "2024-11-05T16:00:00Z", - "deliveryEnd": "2024-11-05T17:00:00Z", + "deliveryStart": "2025-10-01T02:15:00Z", + "deliveryEnd": "2025-10-01T02:30:00Z", "entryPerArea": { - "SE3": 2512.65, - "SE4": 3533.03 + "SE3": 483.3, + "SE4": 559.11 } }, { - "deliveryStart": "2024-11-05T17:00:00Z", - "deliveryEnd": "2024-11-05T18:00:00Z", + "deliveryStart": "2025-10-01T02:30:00Z", + "deliveryEnd": "2025-10-01T02:45:00Z", "entryPerArea": { - "SE3": 1819.83, - "SE4": 2524.06 + "SE3": 484.29, + "SE4": 559.0 } }, { - "deliveryStart": "2024-11-05T18:00:00Z", - "deliveryEnd": "2024-11-05T19:00:00Z", + "deliveryStart": "2025-10-01T02:45:00Z", + "deliveryEnd": "2025-10-01T03:00:00Z", "entryPerArea": { - "SE3": 1011.77, + "SE3": 574.7, + "SE4": 659.35 + } + }, + { + "deliveryStart": "2025-10-01T03:00:00Z", + "deliveryEnd": "2025-10-01T03:15:00Z", + "entryPerArea": { + "SE3": 543.31, + "SE4": 631.95 + } + }, + { + "deliveryStart": "2025-10-01T03:15:00Z", + "deliveryEnd": "2025-10-01T03:30:00Z", + "entryPerArea": { + "SE3": 578.01, + "SE4": 671.18 + } + }, + { + "deliveryStart": "2025-10-01T03:30:00Z", + "deliveryEnd": "2025-10-01T03:45:00Z", + "entryPerArea": { + "SE3": 774.96, + "SE4": 893.1 + } + }, + { + "deliveryStart": "2025-10-01T03:45:00Z", + "deliveryEnd": "2025-10-01T04:00:00Z", + "entryPerArea": { + "SE3": 787.0, + "SE4": 909.79 + } + }, + { + "deliveryStart": "2025-10-01T04:00:00Z", + "deliveryEnd": "2025-10-01T04:15:00Z", + "entryPerArea": { + "SE3": 902.38, + "SE4": 1041.86 + } + }, + { + "deliveryStart": "2025-10-01T04:15:00Z", + "deliveryEnd": "2025-10-01T04:30:00Z", + "entryPerArea": { + "SE3": 1079.32, + "SE4": 1254.17 + } + }, + { + "deliveryStart": "2025-10-01T04:30:00Z", + "deliveryEnd": "2025-10-01T04:45:00Z", + "entryPerArea": { + "SE3": 1222.67, + "SE4": 1421.93 + } + }, + { + "deliveryStart": "2025-10-01T04:45:00Z", + "deliveryEnd": "2025-10-01T05:00:00Z", + "entryPerArea": { + "SE3": 1394.63, + "SE4": 1623.08 + } + }, + { + "deliveryStart": "2025-10-01T05:00:00Z", + "deliveryEnd": "2025-10-01T05:15:00Z", + "entryPerArea": { + "SE3": 1529.36, + "SE4": 1787.86 + } + }, + { + "deliveryStart": "2025-10-01T05:15:00Z", + "deliveryEnd": "2025-10-01T05:30:00Z", + "entryPerArea": { + "SE3": 1724.53, + "SE4": 2015.75 + } + }, + { + "deliveryStart": "2025-10-01T05:30:00Z", + "deliveryEnd": "2025-10-01T05:45:00Z", + "entryPerArea": { + "SE3": 1809.96, + "SE4": 2029.34 + } + }, + { + "deliveryStart": "2025-10-01T05:45:00Z", + "deliveryEnd": "2025-10-01T06:00:00Z", + "entryPerArea": { + "SE3": 1713.04, + "SE4": 1920.15 + } + }, + { + "deliveryStart": "2025-10-01T06:00:00Z", + "deliveryEnd": "2025-10-01T06:15:00Z", + "entryPerArea": { + "SE3": 1925.9, + "SE4": 2162.63 + } + }, + { + "deliveryStart": "2025-10-01T06:15:00Z", + "deliveryEnd": "2025-10-01T06:30:00Z", + "entryPerArea": { + "SE3": 1440.06, + "SE4": 1614.01 + } + }, + { + "deliveryStart": "2025-10-01T06:30:00Z", + "deliveryEnd": "2025-10-01T06:45:00Z", + "entryPerArea": { + "SE3": 1183.32, + "SE4": 1319.37 + } + }, + { + "deliveryStart": "2025-10-01T06:45:00Z", + "deliveryEnd": "2025-10-01T07:00:00Z", + "entryPerArea": { + "SE3": 962.95, + "SE4": 1068.71 + } + }, + { + "deliveryStart": "2025-10-01T07:00:00Z", + "deliveryEnd": "2025-10-01T07:15:00Z", + "entryPerArea": { + "SE3": 1402.04, + "SE4": 1569.92 + } + }, + { + "deliveryStart": "2025-10-01T07:15:00Z", + "deliveryEnd": "2025-10-01T07:30:00Z", + "entryPerArea": { + "SE3": 1060.65, + "SE4": 1178.46 + } + }, + { + "deliveryStart": "2025-10-01T07:30:00Z", + "deliveryEnd": "2025-10-01T07:45:00Z", + "entryPerArea": { + "SE3": 949.13, + "SE4": 1050.59 + } + }, + { + "deliveryStart": "2025-10-01T07:45:00Z", + "deliveryEnd": "2025-10-01T08:00:00Z", + "entryPerArea": { + "SE3": 841.82, + "SE4": 938.3 + } + }, + { + "deliveryStart": "2025-10-01T08:00:00Z", + "deliveryEnd": "2025-10-01T08:15:00Z", + "entryPerArea": { + "SE3": 1037.44, + "SE4": 1141.44 + } + }, + { + "deliveryStart": "2025-10-01T08:15:00Z", + "deliveryEnd": "2025-10-01T08:30:00Z", + "entryPerArea": { + "SE3": 950.13, + "SE4": 1041.64 + } + }, + { + "deliveryStart": "2025-10-01T08:30:00Z", + "deliveryEnd": "2025-10-01T08:45:00Z", + "entryPerArea": { + "SE3": 826.13, + "SE4": 905.04 + } + }, + { + "deliveryStart": "2025-10-01T08:45:00Z", + "deliveryEnd": "2025-10-01T09:00:00Z", + "entryPerArea": { + "SE3": 684.55, + "SE4": 754.62 + } + }, + { + "deliveryStart": "2025-10-01T09:00:00Z", + "deliveryEnd": "2025-10-01T09:15:00Z", + "entryPerArea": { + "SE3": 861.6, + "SE4": 936.09 + } + }, + { + "deliveryStart": "2025-10-01T09:15:00Z", + "deliveryEnd": "2025-10-01T09:30:00Z", + "entryPerArea": { + "SE3": 722.79, + "SE4": 799.6 + } + }, + { + "deliveryStart": "2025-10-01T09:30:00Z", + "deliveryEnd": "2025-10-01T09:45:00Z", + "entryPerArea": { + "SE3": 640.57, + "SE4": 718.59 + } + }, + { + "deliveryStart": "2025-10-01T09:45:00Z", + "deliveryEnd": "2025-10-01T10:00:00Z", + "entryPerArea": { + "SE3": 607.74, + "SE4": 683.12 + } + }, + { + "deliveryStart": "2025-10-01T10:00:00Z", + "deliveryEnd": "2025-10-01T10:15:00Z", + "entryPerArea": { + "SE3": 674.05, + "SE4": 752.41 + } + }, + { + "deliveryStart": "2025-10-01T10:15:00Z", + "deliveryEnd": "2025-10-01T10:30:00Z", + "entryPerArea": { + "SE3": 638.58, + "SE4": 717.49 + } + }, + { + "deliveryStart": "2025-10-01T10:30:00Z", + "deliveryEnd": "2025-10-01T10:45:00Z", + "entryPerArea": { + "SE3": 638.47, + "SE4": 719.81 + } + }, + { + "deliveryStart": "2025-10-01T10:45:00Z", + "deliveryEnd": "2025-10-01T11:00:00Z", + "entryPerArea": { + "SE3": 634.82, + "SE4": 717.16 + } + }, + { + "deliveryStart": "2025-10-01T11:00:00Z", + "deliveryEnd": "2025-10-01T11:15:00Z", + "entryPerArea": { + "SE3": 637.36, + "SE4": 721.58 + } + }, + { + "deliveryStart": "2025-10-01T11:15:00Z", + "deliveryEnd": "2025-10-01T11:30:00Z", + "entryPerArea": { + "SE3": 660.68, + "SE4": 746.33 + } + }, + { + "deliveryStart": "2025-10-01T11:30:00Z", + "deliveryEnd": "2025-10-01T11:45:00Z", + "entryPerArea": { + "SE3": 679.14, + "SE4": 766.45 + } + }, + { + "deliveryStart": "2025-10-01T11:45:00Z", + "deliveryEnd": "2025-10-01T12:00:00Z", + "entryPerArea": { + "SE3": 694.61, + "SE4": 782.91 + } + }, + { + "deliveryStart": "2025-10-01T12:00:00Z", + "deliveryEnd": "2025-10-01T12:15:00Z", + "entryPerArea": { + "SE3": 622.33, + "SE4": 708.87 + } + }, + { + "deliveryStart": "2025-10-01T12:15:00Z", + "deliveryEnd": "2025-10-01T12:30:00Z", + "entryPerArea": { + "SE3": 685.44, + "SE4": 775.84 + } + }, + { + "deliveryStart": "2025-10-01T12:30:00Z", + "deliveryEnd": "2025-10-01T12:45:00Z", + "entryPerArea": { + "SE3": 732.85, + "SE4": 826.57 + } + }, + { + "deliveryStart": "2025-10-01T12:45:00Z", + "deliveryEnd": "2025-10-01T13:00:00Z", + "entryPerArea": { + "SE3": 801.92, + "SE4": 901.28 + } + }, + { + "deliveryStart": "2025-10-01T13:00:00Z", + "deliveryEnd": "2025-10-01T13:15:00Z", + "entryPerArea": { + "SE3": 629.4, + "SE4": 717.93 + } + }, + { + "deliveryStart": "2025-10-01T13:15:00Z", + "deliveryEnd": "2025-10-01T13:30:00Z", + "entryPerArea": { + "SE3": 729.53, + "SE4": 825.46 + } + }, + { + "deliveryStart": "2025-10-01T13:30:00Z", + "deliveryEnd": "2025-10-01T13:45:00Z", + "entryPerArea": { + "SE3": 884.81, + "SE4": 983.95 + } + }, + { + "deliveryStart": "2025-10-01T13:45:00Z", + "deliveryEnd": "2025-10-01T14:00:00Z", + "entryPerArea": { + "SE3": 984.94, + "SE4": 1089.71 + } + }, + { + "deliveryStart": "2025-10-01T14:00:00Z", + "deliveryEnd": "2025-10-01T14:15:00Z", + "entryPerArea": { + "SE3": 615.26, + "SE4": 703.12 + } + }, + { + "deliveryStart": "2025-10-01T14:15:00Z", + "deliveryEnd": "2025-10-01T14:30:00Z", + "entryPerArea": { + "SE3": 902.94, + "SE4": 1002.74 + } + }, + { + "deliveryStart": "2025-10-01T14:30:00Z", + "deliveryEnd": "2025-10-01T14:45:00Z", + "entryPerArea": { + "SE3": 1043.85, + "SE4": 1158.35 + } + }, + { + "deliveryStart": "2025-10-01T14:45:00Z", + "deliveryEnd": "2025-10-01T15:00:00Z", + "entryPerArea": { + "SE3": 1075.12, + "SE4": 1194.15 + } + }, + { + "deliveryStart": "2025-10-01T15:00:00Z", + "deliveryEnd": "2025-10-01T15:15:00Z", + "entryPerArea": { + "SE3": 980.52, + "SE4": 1089.38 + } + }, + { + "deliveryStart": "2025-10-01T15:15:00Z", + "deliveryEnd": "2025-10-01T15:30:00Z", + "entryPerArea": { + "SE3": 1162.66, + "SE4": 1300.14 + } + }, + { + "deliveryStart": "2025-10-01T15:30:00Z", + "deliveryEnd": "2025-10-01T15:45:00Z", + "entryPerArea": { + "SE3": 1453.87, + "SE4": 1628.6 + } + }, + { + "deliveryStart": "2025-10-01T15:45:00Z", + "deliveryEnd": "2025-10-01T16:00:00Z", + "entryPerArea": { + "SE3": 1955.96, + "SE4": 2193.35 + } + }, + { + "deliveryStart": "2025-10-01T16:00:00Z", + "deliveryEnd": "2025-10-01T16:15:00Z", + "entryPerArea": { + "SE3": 1423.48, + "SE4": 1623.74 + } + }, + { + "deliveryStart": "2025-10-01T16:15:00Z", + "deliveryEnd": "2025-10-01T16:30:00Z", + "entryPerArea": { + "SE3": 1900.04, + "SE4": 2199.98 + } + }, + { + "deliveryStart": "2025-10-01T16:30:00Z", + "deliveryEnd": "2025-10-01T16:45:00Z", + "entryPerArea": { + "SE3": 2611.11, + "SE4": 3031.08 + } + }, + { + "deliveryStart": "2025-10-01T16:45:00Z", + "deliveryEnd": "2025-10-01T17:00:00Z", + "entryPerArea": { + "SE3": 3467.41, + "SE4": 4029.51 + } + }, + { + "deliveryStart": "2025-10-01T17:00:00Z", + "deliveryEnd": "2025-10-01T17:15:00Z", + "entryPerArea": { + "SE3": 3828.03, + "SE4": 4442.74 + } + }, + { + "deliveryStart": "2025-10-01T17:15:00Z", + "deliveryEnd": "2025-10-01T17:30:00Z", + "entryPerArea": { + "SE3": 3429.83, + "SE4": 3982.21 + } + }, + { + "deliveryStart": "2025-10-01T17:30:00Z", + "deliveryEnd": "2025-10-01T17:45:00Z", + "entryPerArea": { + "SE3": 2934.38, + "SE4": 3405.74 + } + }, + { + "deliveryStart": "2025-10-01T17:45:00Z", + "deliveryEnd": "2025-10-01T18:00:00Z", + "entryPerArea": { + "SE3": 2308.07, + "SE4": 2677.64 + } + }, + { + "deliveryStart": "2025-10-01T18:00:00Z", + "deliveryEnd": "2025-10-01T18:15:00Z", + "entryPerArea": { + "SE3": 1997.96, "SE4": 0.0 } }, { - "deliveryStart": "2024-11-05T19:00:00Z", - "deliveryEnd": "2024-11-05T20:00:00Z", + "deliveryStart": "2025-10-01T18:15:00Z", + "deliveryEnd": "2025-10-01T18:30:00Z", + "entryPerArea": { + "SE3": 1424.03, + "SE4": 1646.17 + } + }, + { + "deliveryStart": "2025-10-01T18:30:00Z", + "deliveryEnd": "2025-10-01T18:45:00Z", + "entryPerArea": { + "SE3": 1216.81, + "SE4": 1388.11 + } + }, + { + "deliveryStart": "2025-10-01T18:45:00Z", + "deliveryEnd": "2025-10-01T19:00:00Z", + "entryPerArea": { + "SE3": 1070.15, + "SE4": 1204.65 + } + }, + { + "deliveryStart": "2025-10-01T19:00:00Z", + "deliveryEnd": "2025-10-01T19:15:00Z", + "entryPerArea": { + "SE3": 1218.14, + "SE4": 1405.02 + } + }, + { + "deliveryStart": "2025-10-01T19:15:00Z", + "deliveryEnd": "2025-10-01T19:30:00Z", + "entryPerArea": { + "SE3": 1135.8, + "SE4": 1309.42 + } + }, + { + "deliveryStart": "2025-10-01T19:30:00Z", + "deliveryEnd": "2025-10-01T19:45:00Z", + "entryPerArea": { + "SE3": 959.96, + "SE4": 1115.69 + } + }, + { + "deliveryStart": "2025-10-01T19:45:00Z", + "deliveryEnd": "2025-10-01T20:00:00Z", + "entryPerArea": { + "SE3": 913.66, + "SE4": 1064.52 + } + }, + { + "deliveryStart": "2025-10-01T20:00:00Z", + "deliveryEnd": "2025-10-01T20:15:00Z", + "entryPerArea": { + "SE3": 1001.63, + "SE4": 1161.22 + } + }, + { + "deliveryStart": "2025-10-01T20:15:00Z", + "deliveryEnd": "2025-10-01T20:30:00Z", + "entryPerArea": { + "SE3": 933.0, + "SE4": 1083.08 + } + }, + { + "deliveryStart": "2025-10-01T20:30:00Z", + "deliveryEnd": "2025-10-01T20:45:00Z", + "entryPerArea": { + "SE3": 874.53, + "SE4": 1017.66 + } + }, + { + "deliveryStart": "2025-10-01T20:45:00Z", + "deliveryEnd": "2025-10-01T21:00:00Z", + "entryPerArea": { + "SE3": 821.71, + "SE4": 955.32 + } + }, + { + "deliveryStart": "2025-10-01T21:00:00Z", + "deliveryEnd": "2025-10-01T21:15:00Z", "entryPerArea": { - "SE3": 835.53, - "SE4": 1112.57 + "SE3": 860.5, + "SE4": 997.32 } }, { - "deliveryStart": "2024-11-05T20:00:00Z", - "deliveryEnd": "2024-11-05T21:00:00Z", + "deliveryStart": "2025-10-01T21:15:00Z", + "deliveryEnd": "2025-10-01T21:30:00Z", "entryPerArea": { - "SE3": 796.19, - "SE4": 1051.69 + "SE3": 840.16, + "SE4": 977.87 } }, { - "deliveryStart": "2024-11-05T21:00:00Z", - "deliveryEnd": "2024-11-05T22:00:00Z", + "deliveryStart": "2025-10-01T21:30:00Z", + "deliveryEnd": "2025-10-01T21:45:00Z", "entryPerArea": { - "SE3": 522.3, - "SE4": 662.44 + "SE3": 820.05, + "SE4": 954.66 } }, { - "deliveryStart": "2024-11-05T22:00:00Z", - "deliveryEnd": "2024-11-05T23:00:00Z", + "deliveryStart": "2025-10-01T21:45:00Z", + "deliveryEnd": "2025-10-01T22:00:00Z", "entryPerArea": { - "SE3": 289.14, - "SE4": 349.21 + "SE3": 785.68, + "SE4": 912.22 } } ], "blockPriceAggregates": [ { "blockName": "Off-peak 1", - "deliveryStart": "2024-11-04T23:00:00Z", - "deliveryEnd": "2024-11-05T07:00:00Z", + "deliveryStart": "2025-09-30T22:00:00Z", + "deliveryEnd": "2025-10-01T06:00:00Z", "averagePricePerArea": { "SE3": { - "average": 422.87, - "min": 61.69, - "max": 1406.14 + "average": 745.93, + "min": 441.96, + "max": 1809.96 }, "SE4": { - "average": 497.97, - "min": 65.19, - "max": 1648.25 + "average": 860.99, + "min": 515.46, + "max": 2029.34 } } }, { "blockName": "Peak", - "deliveryStart": "2024-11-05T07:00:00Z", - "deliveryEnd": "2024-11-05T19:00:00Z", + "deliveryStart": "2025-10-01T06:00:00Z", + "deliveryEnd": "2025-10-01T18:00:00Z", "averagePricePerArea": { "SE3": { - "average": 1315.97, - "min": 925.05, - "max": 2512.65 + "average": 1219.13, + "min": 607.74, + "max": 3828.03 }, "SE4": { - "average": 1735.59, - "min": 1081.72, - "max": 3533.03 + "average": 1381.22, + "min": 683.12, + "max": 4442.74 } } }, { "blockName": "Off-peak 2", - "deliveryStart": "2024-11-05T19:00:00Z", - "deliveryEnd": "2024-11-05T23:00:00Z", + "deliveryStart": "2025-10-01T18:00:00Z", + "deliveryEnd": "2025-10-01T22:00:00Z", "averagePricePerArea": { "SE3": { - "average": 610.79, - "min": 289.14, - "max": 835.53 + "average": 1054.61, + "min": 785.68, + "max": 1997.96 }, "SE4": { - "average": 793.98, - "min": 349.21, - "max": 1112.57 + "average": 1219.07, + "min": 912.22, + "max": 2312.16 } } } ], "currency": "SEK", - "exchangeRate": 11.6402, + "exchangeRate": 11.05186, "areaStates": [ { "state": "Final", @@ -262,11 +838,11 @@ "areaAverages": [ { "areaCode": "SE3", - "price": 900.74 + "price": 1033.98 }, { "areaCode": "SE4", - "price": 1166.12 + "price": 1180.78 } ] } diff --git a/tests/components/nordpool/fixtures/delivery_period_tomorrow.json b/tests/components/nordpool/fixtures/delivery_period_tomorrow.json index abaa24e93ede6..0e64088d33bfe 100644 --- a/tests/components/nordpool/fixtures/delivery_period_tomorrow.json +++ b/tests/components/nordpool/fixtures/delivery_period_tomorrow.json @@ -1,258 +1,834 @@ { - "deliveryDateCET": "2024-11-06", + "deliveryDateCET": "2025-10-02", "version": 3, - "updatedAt": "2024-11-05T12:12:51.9853434Z", + "updatedAt": "2025-10-01T11:25:06.1484362Z", "deliveryAreas": ["SE3", "SE4"], "market": "DayAhead", "multiAreaEntries": [ { - "deliveryStart": "2024-11-05T23:00:00Z", - "deliveryEnd": "2024-11-06T00:00:00Z", + "deliveryStart": "2025-10-01T22:00:00Z", + "deliveryEnd": "2025-10-01T22:15:00Z", "entryPerArea": { - "SE3": 126.66, - "SE4": 275.6 + "SE3": 933.22, + "SE4": 1062.32 } }, { - "deliveryStart": "2024-11-06T00:00:00Z", - "deliveryEnd": "2024-11-06T01:00:00Z", + "deliveryStart": "2025-10-01T22:15:00Z", + "deliveryEnd": "2025-10-01T22:30:00Z", "entryPerArea": { - "SE3": 74.06, - "SE4": 157.34 + "SE3": 854.22, + "SE4": 971.95 } }, { - "deliveryStart": "2024-11-06T01:00:00Z", - "deliveryEnd": "2024-11-06T02:00:00Z", + "deliveryStart": "2025-10-01T22:30:00Z", + "deliveryEnd": "2025-10-01T22:45:00Z", "entryPerArea": { - "SE3": 78.38, - "SE4": 165.62 + "SE3": 809.54, + "SE4": 919.1 } }, { - "deliveryStart": "2024-11-06T02:00:00Z", - "deliveryEnd": "2024-11-06T03:00:00Z", + "deliveryStart": "2025-10-01T22:45:00Z", + "deliveryEnd": "2025-10-01T23:00:00Z", "entryPerArea": { - "SE3": 92.37, - "SE4": 196.17 + "SE3": 811.74, + "SE4": 922.63 } }, { - "deliveryStart": "2024-11-06T03:00:00Z", - "deliveryEnd": "2024-11-06T04:00:00Z", + "deliveryStart": "2025-10-01T23:00:00Z", + "deliveryEnd": "2025-10-01T23:15:00Z", "entryPerArea": { - "SE3": 99.14, - "SE4": 190.58 + "SE3": 835.13, + "SE4": 950.99 } }, { - "deliveryStart": "2024-11-06T04:00:00Z", - "deliveryEnd": "2024-11-06T05:00:00Z", + "deliveryStart": "2025-10-01T23:15:00Z", + "deliveryEnd": "2025-10-01T23:30:00Z", "entryPerArea": { - "SE3": 447.51, - "SE4": 932.93 + "SE3": 828.85, + "SE4": 942.82 } }, { - "deliveryStart": "2024-11-06T05:00:00Z", - "deliveryEnd": "2024-11-06T06:00:00Z", + "deliveryStart": "2025-10-01T23:30:00Z", + "deliveryEnd": "2025-10-01T23:45:00Z", "entryPerArea": { - "SE3": 641.47, - "SE4": 1284.69 + "SE3": 796.63, + "SE4": 903.54 } }, { - "deliveryStart": "2024-11-06T06:00:00Z", - "deliveryEnd": "2024-11-06T07:00:00Z", + "deliveryStart": "2025-10-01T23:45:00Z", + "deliveryEnd": "2025-10-02T00:00:00Z", "entryPerArea": { - "SE3": 1820.5, - "SE4": 2449.96 + "SE3": 706.7, + "SE4": 799.61 } }, { - "deliveryStart": "2024-11-06T07:00:00Z", - "deliveryEnd": "2024-11-06T08:00:00Z", + "deliveryStart": "2025-10-02T00:00:00Z", + "deliveryEnd": "2025-10-02T00:15:00Z", "entryPerArea": { - "SE3": 1723.0, - "SE4": 2244.22 + "SE3": 695.23, + "SE4": 786.81 } }, { - "deliveryStart": "2024-11-06T08:00:00Z", - "deliveryEnd": "2024-11-06T09:00:00Z", + "deliveryStart": "2025-10-02T00:15:00Z", + "deliveryEnd": "2025-10-02T00:30:00Z", "entryPerArea": { - "SE3": 1298.57, - "SE4": 1643.45 + "SE3": 695.12, + "SE4": 783.83 } }, { - "deliveryStart": "2024-11-06T09:00:00Z", - "deliveryEnd": "2024-11-06T10:00:00Z", + "deliveryStart": "2025-10-02T00:30:00Z", + "deliveryEnd": "2025-10-02T00:45:00Z", "entryPerArea": { - "SE3": 1099.25, - "SE4": 1507.23 + "SE3": 684.86, + "SE4": 771.8 } }, { - "deliveryStart": "2024-11-06T10:00:00Z", - "deliveryEnd": "2024-11-06T11:00:00Z", + "deliveryStart": "2025-10-02T00:45:00Z", + "deliveryEnd": "2025-10-02T01:00:00Z", "entryPerArea": { - "SE3": 903.31, - "SE4": 1362.84 + "SE3": 673.05, + "SE4": 758.78 } }, { - "deliveryStart": "2024-11-06T11:00:00Z", - "deliveryEnd": "2024-11-06T12:00:00Z", + "deliveryStart": "2025-10-02T01:00:00Z", + "deliveryEnd": "2025-10-02T01:15:00Z", "entryPerArea": { - "SE3": 959.99, - "SE4": 1376.13 + "SE3": 695.01, + "SE4": 791.22 } }, { - "deliveryStart": "2024-11-06T12:00:00Z", - "deliveryEnd": "2024-11-06T13:00:00Z", + "deliveryStart": "2025-10-02T01:15:00Z", + "deliveryEnd": "2025-10-02T01:30:00Z", "entryPerArea": { - "SE3": 1186.61, - "SE4": 1449.96 + "SE3": 693.35, + "SE4": 789.12 } }, { - "deliveryStart": "2024-11-06T13:00:00Z", - "deliveryEnd": "2024-11-06T14:00:00Z", + "deliveryStart": "2025-10-02T01:30:00Z", + "deliveryEnd": "2025-10-02T01:45:00Z", "entryPerArea": { - "SE3": 1307.67, - "SE4": 1608.35 + "SE3": 702.4, + "SE4": 799.61 } }, { - "deliveryStart": "2024-11-06T14:00:00Z", - "deliveryEnd": "2024-11-06T15:00:00Z", + "deliveryStart": "2025-10-02T01:45:00Z", + "deliveryEnd": "2025-10-02T02:00:00Z", "entryPerArea": { - "SE3": 1385.46, - "SE4": 2110.8 + "SE3": 749.4, + "SE4": 853.45 } }, { - "deliveryStart": "2024-11-06T15:00:00Z", - "deliveryEnd": "2024-11-06T16:00:00Z", + "deliveryStart": "2025-10-02T02:00:00Z", + "deliveryEnd": "2025-10-02T02:15:00Z", "entryPerArea": { - "SE3": 1366.8, - "SE4": 3031.25 + "SE3": 796.85, + "SE4": 907.4 } }, { - "deliveryStart": "2024-11-06T16:00:00Z", - "deliveryEnd": "2024-11-06T17:00:00Z", + "deliveryStart": "2025-10-02T02:15:00Z", + "deliveryEnd": "2025-10-02T02:30:00Z", "entryPerArea": { - "SE3": 2366.57, - "SE4": 5511.77 + "SE3": 811.19, + "SE4": 924.07 } }, { - "deliveryStart": "2024-11-06T17:00:00Z", - "deliveryEnd": "2024-11-06T18:00:00Z", + "deliveryStart": "2025-10-02T02:30:00Z", + "deliveryEnd": "2025-10-02T02:45:00Z", "entryPerArea": { - "SE3": 1481.92, - "SE4": 3351.64 + "SE3": 803.8, + "SE4": 916.23 } }, { - "deliveryStart": "2024-11-06T18:00:00Z", - "deliveryEnd": "2024-11-06T19:00:00Z", + "deliveryStart": "2025-10-02T02:45:00Z", + "deliveryEnd": "2025-10-02T03:00:00Z", "entryPerArea": { - "SE3": 1082.69, - "SE4": 2484.95 + "SE3": 839.11, + "SE4": 953.3 } }, { - "deliveryStart": "2024-11-06T19:00:00Z", - "deliveryEnd": "2024-11-06T20:00:00Z", + "deliveryStart": "2025-10-02T03:00:00Z", + "deliveryEnd": "2025-10-02T03:15:00Z", "entryPerArea": { - "SE3": 716.82, - "SE4": 1624.33 + "SE3": 825.2, + "SE4": 943.15 } }, { - "deliveryStart": "2024-11-06T20:00:00Z", - "deliveryEnd": "2024-11-06T21:00:00Z", + "deliveryStart": "2025-10-02T03:15:00Z", + "deliveryEnd": "2025-10-02T03:30:00Z", "entryPerArea": { - "SE3": 583.16, - "SE4": 1306.27 + "SE3": 838.78, + "SE4": 958.93 } }, { - "deliveryStart": "2024-11-06T21:00:00Z", - "deliveryEnd": "2024-11-06T22:00:00Z", + "deliveryStart": "2025-10-02T03:30:00Z", + "deliveryEnd": "2025-10-02T03:45:00Z", "entryPerArea": { - "SE3": 523.09, - "SE4": 1142.99 + "SE3": 906.19, + "SE4": 1030.65 } }, { - "deliveryStart": "2024-11-06T22:00:00Z", - "deliveryEnd": "2024-11-06T23:00:00Z", + "deliveryStart": "2025-10-02T03:45:00Z", + "deliveryEnd": "2025-10-02T04:00:00Z", "entryPerArea": { - "SE3": 250.64, - "SE4": 539.42 + "SE3": 1057.79, + "SE4": 1195.82 + } + }, + { + "deliveryStart": "2025-10-02T04:00:00Z", + "deliveryEnd": "2025-10-02T04:15:00Z", + "entryPerArea": { + "SE3": 912.15, + "SE4": 1040.8 + } + }, + { + "deliveryStart": "2025-10-02T04:15:00Z", + "deliveryEnd": "2025-10-02T04:30:00Z", + "entryPerArea": { + "SE3": 1131.28, + "SE4": 1283.43 + } + }, + { + "deliveryStart": "2025-10-02T04:30:00Z", + "deliveryEnd": "2025-10-02T04:45:00Z", + "entryPerArea": { + "SE3": 1294.68, + "SE4": 1468.91 + } + }, + { + "deliveryStart": "2025-10-02T04:45:00Z", + "deliveryEnd": "2025-10-02T05:00:00Z", + "entryPerArea": { + "SE3": 1625.8, + "SE4": 1845.81 + } + }, + { + "deliveryStart": "2025-10-02T05:00:00Z", + "deliveryEnd": "2025-10-02T05:15:00Z", + "entryPerArea": { + "SE3": 1649.31, + "SE4": 1946.77 + } + }, + { + "deliveryStart": "2025-10-02T05:15:00Z", + "deliveryEnd": "2025-10-02T05:30:00Z", + "entryPerArea": { + "SE3": 1831.25, + "SE4": 2182.34 + } + }, + { + "deliveryStart": "2025-10-02T05:30:00Z", + "deliveryEnd": "2025-10-02T05:45:00Z", + "entryPerArea": { + "SE3": 1743.31, + "SE4": 2063.4 + } + }, + { + "deliveryStart": "2025-10-02T05:45:00Z", + "deliveryEnd": "2025-10-02T06:00:00Z", + "entryPerArea": { + "SE3": 1545.04, + "SE4": 1803.33 + } + }, + { + "deliveryStart": "2025-10-02T06:00:00Z", + "deliveryEnd": "2025-10-02T06:15:00Z", + "entryPerArea": { + "SE3": 1783.47, + "SE4": 2080.72 + } + }, + { + "deliveryStart": "2025-10-02T06:15:00Z", + "deliveryEnd": "2025-10-02T06:30:00Z", + "entryPerArea": { + "SE3": 1470.89, + "SE4": 1675.23 + } + }, + { + "deliveryStart": "2025-10-02T06:30:00Z", + "deliveryEnd": "2025-10-02T06:45:00Z", + "entryPerArea": { + "SE3": 1191.08, + "SE4": 1288.06 + } + }, + { + "deliveryStart": "2025-10-02T06:45:00Z", + "deliveryEnd": "2025-10-02T07:00:00Z", + "entryPerArea": { + "SE3": 1012.22, + "SE4": 1112.19 + } + }, + { + "deliveryStart": "2025-10-02T07:00:00Z", + "deliveryEnd": "2025-10-02T07:15:00Z", + "entryPerArea": { + "SE3": 1278.69, + "SE4": 1375.67 + } + }, + { + "deliveryStart": "2025-10-02T07:15:00Z", + "deliveryEnd": "2025-10-02T07:30:00Z", + "entryPerArea": { + "SE3": 1170.12, + "SE4": 1258.61 + } + }, + { + "deliveryStart": "2025-10-02T07:30:00Z", + "deliveryEnd": "2025-10-02T07:45:00Z", + "entryPerArea": { + "SE3": 937.09, + "SE4": 1021.93 + } + }, + { + "deliveryStart": "2025-10-02T07:45:00Z", + "deliveryEnd": "2025-10-02T08:00:00Z", + "entryPerArea": { + "SE3": 815.94, + "SE4": 900.67 + } + }, + { + "deliveryStart": "2025-10-02T08:00:00Z", + "deliveryEnd": "2025-10-02T08:15:00Z", + "entryPerArea": { + "SE3": 1044.66, + "SE4": 1135.25 + } + }, + { + "deliveryStart": "2025-10-02T08:15:00Z", + "deliveryEnd": "2025-10-02T08:30:00Z", + "entryPerArea": { + "SE3": 1020.61, + "SE4": 1112.74 + } + }, + { + "deliveryStart": "2025-10-02T08:30:00Z", + "deliveryEnd": "2025-10-02T08:45:00Z", + "entryPerArea": { + "SE3": 866.14, + "SE4": 953.53 + } + }, + { + "deliveryStart": "2025-10-02T08:45:00Z", + "deliveryEnd": "2025-10-02T09:00:00Z", + "entryPerArea": { + "SE3": 774.34, + "SE4": 860.18 + } + }, + { + "deliveryStart": "2025-10-02T09:00:00Z", + "deliveryEnd": "2025-10-02T09:15:00Z", + "entryPerArea": { + "SE3": 928.26, + "SE4": 1020.39 + } + }, + { + "deliveryStart": "2025-10-02T09:15:00Z", + "deliveryEnd": "2025-10-02T09:30:00Z", + "entryPerArea": { + "SE3": 834.47, + "SE4": 922.96 + } + }, + { + "deliveryStart": "2025-10-02T09:30:00Z", + "deliveryEnd": "2025-10-02T09:45:00Z", + "entryPerArea": { + "SE3": 712.33, + "SE4": 794.64 + } + }, + { + "deliveryStart": "2025-10-02T09:45:00Z", + "deliveryEnd": "2025-10-02T10:00:00Z", + "entryPerArea": { + "SE3": 646.46, + "SE4": 725.9 + } + }, + { + "deliveryStart": "2025-10-02T10:00:00Z", + "deliveryEnd": "2025-10-02T10:15:00Z", + "entryPerArea": { + "SE3": 692.91, + "SE4": 773.9 + } + }, + { + "deliveryStart": "2025-10-02T10:15:00Z", + "deliveryEnd": "2025-10-02T10:30:00Z", + "entryPerArea": { + "SE3": 627.59, + "SE4": 706.59 + } + }, + { + "deliveryStart": "2025-10-02T10:30:00Z", + "deliveryEnd": "2025-10-02T10:45:00Z", + "entryPerArea": { + "SE3": 630.02, + "SE4": 708.14 + } + }, + { + "deliveryStart": "2025-10-02T10:45:00Z", + "deliveryEnd": "2025-10-02T11:00:00Z", + "entryPerArea": { + "SE3": 625.94, + "SE4": 703.61 + } + }, + { + "deliveryStart": "2025-10-02T11:00:00Z", + "deliveryEnd": "2025-10-02T11:15:00Z", + "entryPerArea": { + "SE3": 563.38, + "SE4": 635.76 + } + }, + { + "deliveryStart": "2025-10-02T11:15:00Z", + "deliveryEnd": "2025-10-02T11:30:00Z", + "entryPerArea": { + "SE3": 588.42, + "SE4": 663.12 + } + }, + { + "deliveryStart": "2025-10-02T11:30:00Z", + "deliveryEnd": "2025-10-02T11:45:00Z", + "entryPerArea": { + "SE3": 597.03, + "SE4": 672.83 + } + }, + { + "deliveryStart": "2025-10-02T11:45:00Z", + "deliveryEnd": "2025-10-02T12:00:00Z", + "entryPerArea": { + "SE3": 608.61, + "SE4": 685.19 + } + }, + { + "deliveryStart": "2025-10-02T12:00:00Z", + "deliveryEnd": "2025-10-02T12:15:00Z", + "entryPerArea": { + "SE3": 599.24, + "SE4": 676.91 + } + }, + { + "deliveryStart": "2025-10-02T12:15:00Z", + "deliveryEnd": "2025-10-02T12:30:00Z", + "entryPerArea": { + "SE3": 649.77, + "SE4": 729.54 + } + }, + { + "deliveryStart": "2025-10-02T12:30:00Z", + "deliveryEnd": "2025-10-02T12:45:00Z", + "entryPerArea": { + "SE3": 728.22, + "SE4": 821.23 + } + }, + { + "deliveryStart": "2025-10-02T12:45:00Z", + "deliveryEnd": "2025-10-02T13:00:00Z", + "entryPerArea": { + "SE3": 803.91, + "SE4": 909.06 + } + }, + { + "deliveryStart": "2025-10-02T13:00:00Z", + "deliveryEnd": "2025-10-02T13:15:00Z", + "entryPerArea": { + "SE3": 594.38, + "SE4": 679.23 + } + }, + { + "deliveryStart": "2025-10-02T13:15:00Z", + "deliveryEnd": "2025-10-02T13:30:00Z", + "entryPerArea": { + "SE3": 738.48, + "SE4": 825.09 + } + }, + { + "deliveryStart": "2025-10-02T13:30:00Z", + "deliveryEnd": "2025-10-02T13:45:00Z", + "entryPerArea": { + "SE3": 873.53, + "SE4": 962.02 + } + }, + { + "deliveryStart": "2025-10-02T13:45:00Z", + "deliveryEnd": "2025-10-02T14:00:00Z", + "entryPerArea": { + "SE3": 994.57, + "SE4": 1083.5 + } + }, + { + "deliveryStart": "2025-10-02T14:00:00Z", + "deliveryEnd": "2025-10-02T14:15:00Z", + "entryPerArea": { + "SE3": 733.52, + "SE4": 813.18 + } + }, + { + "deliveryStart": "2025-10-02T14:15:00Z", + "deliveryEnd": "2025-10-02T14:30:00Z", + "entryPerArea": { + "SE3": 864.59, + "SE4": 944.04 + } + }, + { + "deliveryStart": "2025-10-02T14:30:00Z", + "deliveryEnd": "2025-10-02T14:45:00Z", + "entryPerArea": { + "SE3": 1032.08, + "SE4": 1113.18 + } + }, + { + "deliveryStart": "2025-10-02T14:45:00Z", + "deliveryEnd": "2025-10-02T15:00:00Z", + "entryPerArea": { + "SE3": 1153.01, + "SE4": 1241.61 + } + }, + { + "deliveryStart": "2025-10-02T15:00:00Z", + "deliveryEnd": "2025-10-02T15:15:00Z", + "entryPerArea": { + "SE3": 1271.18, + "SE4": 1017.41 + } + }, + { + "deliveryStart": "2025-10-02T15:15:00Z", + "deliveryEnd": "2025-10-02T15:30:00Z", + "entryPerArea": { + "SE3": 1375.23, + "SE4": 1093.1 + } + }, + { + "deliveryStart": "2025-10-02T15:30:00Z", + "deliveryEnd": "2025-10-02T15:45:00Z", + "entryPerArea": { + "SE3": 1544.82, + "SE4": 1244.81 + } + }, + { + "deliveryStart": "2025-10-02T15:45:00Z", + "deliveryEnd": "2025-10-02T16:00:00Z", + "entryPerArea": { + "SE3": 2412.17, + "SE4": 1960.12 + } + }, + { + "deliveryStart": "2025-10-02T16:00:00Z", + "deliveryEnd": "2025-10-02T16:15:00Z", + "entryPerArea": { + "SE3": 1677.66, + "SE4": 1334.3 + } + }, + { + "deliveryStart": "2025-10-02T16:15:00Z", + "deliveryEnd": "2025-10-02T16:30:00Z", + "entryPerArea": { + "SE3": 2010.55, + "SE4": 1606.61 + } + }, + { + "deliveryStart": "2025-10-02T16:30:00Z", + "deliveryEnd": "2025-10-02T16:45:00Z", + "entryPerArea": { + "SE3": 2524.38, + "SE4": 2013.53 + } + }, + { + "deliveryStart": "2025-10-02T16:45:00Z", + "deliveryEnd": "2025-10-02T17:00:00Z", + "entryPerArea": { + "SE3": 3288.35, + "SE4": 2617.73 + } + }, + { + "deliveryStart": "2025-10-02T17:00:00Z", + "deliveryEnd": "2025-10-02T17:15:00Z", + "entryPerArea": { + "SE3": 3065.69, + "SE4": 2472.19 + } + }, + { + "deliveryStart": "2025-10-02T17:15:00Z", + "deliveryEnd": "2025-10-02T17:30:00Z", + "entryPerArea": { + "SE3": 2824.72, + "SE4": 2276.46 + } + }, + { + "deliveryStart": "2025-10-02T17:30:00Z", + "deliveryEnd": "2025-10-02T17:45:00Z", + "entryPerArea": { + "SE3": 2279.66, + "SE4": 1835.44 + } + }, + { + "deliveryStart": "2025-10-02T17:45:00Z", + "deliveryEnd": "2025-10-02T18:00:00Z", + "entryPerArea": { + "SE3": 1723.78, + "SE4": 1385.38 + } + }, + { + "deliveryStart": "2025-10-02T18:00:00Z", + "deliveryEnd": "2025-10-02T18:15:00Z", + "entryPerArea": { + "SE3": 1935.08, + "SE4": 1532.57 + } + }, + { + "deliveryStart": "2025-10-02T18:15:00Z", + "deliveryEnd": "2025-10-02T18:30:00Z", + "entryPerArea": { + "SE3": 1568.54, + "SE4": 1240.18 + } + }, + { + "deliveryStart": "2025-10-02T18:30:00Z", + "deliveryEnd": "2025-10-02T18:45:00Z", + "entryPerArea": { + "SE3": 1430.51, + "SE4": 1115.61 + } + }, + { + "deliveryStart": "2025-10-02T18:45:00Z", + "deliveryEnd": "2025-10-02T19:00:00Z", + "entryPerArea": { + "SE3": 1377.66, + "SE4": 1075.12 + } + }, + { + "deliveryStart": "2025-10-02T19:00:00Z", + "deliveryEnd": "2025-10-02T19:15:00Z", + "entryPerArea": { + "SE3": 1408.44, + "SE4": 1108.66 + } + }, + { + "deliveryStart": "2025-10-02T19:15:00Z", + "deliveryEnd": "2025-10-02T19:30:00Z", + "entryPerArea": { + "SE3": 1326.79, + "SE4": 1049.74 + } + }, + { + "deliveryStart": "2025-10-02T19:30:00Z", + "deliveryEnd": "2025-10-02T19:45:00Z", + "entryPerArea": { + "SE3": 1210.94, + "SE4": 951.1 + } + }, + { + "deliveryStart": "2025-10-02T19:45:00Z", + "deliveryEnd": "2025-10-02T20:00:00Z", + "entryPerArea": { + "SE3": 1293.58, + "SE4": 1026.79 + } + }, + { + "deliveryStart": "2025-10-02T20:00:00Z", + "deliveryEnd": "2025-10-02T20:15:00Z", + "entryPerArea": { + "SE3": 1385.71, + "SE4": 1091.0 + } + }, + { + "deliveryStart": "2025-10-02T20:15:00Z", + "deliveryEnd": "2025-10-02T20:30:00Z", + "entryPerArea": { + "SE3": 1341.47, + "SE4": 1104.13 + } + }, + { + "deliveryStart": "2025-10-02T20:30:00Z", + "deliveryEnd": "2025-10-02T20:45:00Z", + "entryPerArea": { + "SE3": 1284.98, + "SE4": 1024.36 + } + }, + { + "deliveryStart": "2025-10-02T20:45:00Z", + "deliveryEnd": "2025-10-02T21:00:00Z", + "entryPerArea": { + "SE3": 1071.47, + "SE4": 892.51 + } + }, + { + "deliveryStart": "2025-10-02T21:00:00Z", + "deliveryEnd": "2025-10-02T21:15:00Z", + "entryPerArea": { + "SE3": 1218.0, + "SE4": 1123.99 + } + }, + { + "deliveryStart": "2025-10-02T21:15:00Z", + "deliveryEnd": "2025-10-02T21:30:00Z", + "entryPerArea": { + "SE3": 1112.3, + "SE4": 1001.63 + } + }, + { + "deliveryStart": "2025-10-02T21:30:00Z", + "deliveryEnd": "2025-10-02T21:45:00Z", + "entryPerArea": { + "SE3": 873.64, + "SE4": 806.67 + } + }, + { + "deliveryStart": "2025-10-02T21:45:00Z", + "deliveryEnd": "2025-10-02T22:00:00Z", + "entryPerArea": { + "SE3": 646.9, + "SE4": 591.84 } } ], "blockPriceAggregates": [ { "blockName": "Off-peak 1", - "deliveryStart": "2024-11-05T23:00:00Z", - "deliveryEnd": "2024-11-06T07:00:00Z", + "deliveryStart": "2025-10-01T22:00:00Z", + "deliveryEnd": "2025-10-02T06:00:00Z", "averagePricePerArea": { "SE3": { - "average": 422.51, - "min": 74.06, - "max": 1820.5 + "average": 961.76, + "min": 673.05, + "max": 1831.25 }, "SE4": { - "average": 706.61, - "min": 157.34, - "max": 2449.96 + "average": 1102.25, + "min": 758.78, + "max": 2182.34 } } }, { "blockName": "Peak", - "deliveryStart": "2024-11-06T07:00:00Z", - "deliveryEnd": "2024-11-06T19:00:00Z", + "deliveryStart": "2025-10-02T06:00:00Z", + "deliveryEnd": "2025-10-02T18:00:00Z", "averagePricePerArea": { "SE3": { - "average": 1346.82, - "min": 903.31, - "max": 2366.57 + "average": 1191.34, + "min": 563.38, + "max": 3288.35 }, "SE4": { - "average": 2306.88, - "min": 1362.84, - "max": 5511.77 + "average": 1155.07, + "min": 635.76, + "max": 2617.73 } } }, { "blockName": "Off-peak 2", - "deliveryStart": "2024-11-06T19:00:00Z", - "deliveryEnd": "2024-11-06T23:00:00Z", + "deliveryStart": "2025-10-02T18:00:00Z", + "deliveryEnd": "2025-10-02T22:00:00Z", "averagePricePerArea": { "SE3": { - "average": 518.43, - "min": 250.64, - "max": 716.82 + "average": 1280.38, + "min": 646.9, + "max": 1935.08 }, "SE4": { - "average": 1153.25, - "min": 539.42, - "max": 1624.33 + "average": 1045.99, + "min": 591.84, + "max": 1532.57 } } } ], "currency": "SEK", - "exchangeRate": 11.66314, + "exchangeRate": 11.03362, "areaStates": [ { "state": "Final", @@ -262,11 +838,11 @@ "areaAverages": [ { "areaCode": "SE3", - "price": 900.65 + "price": 1129.65 }, { "areaCode": "SE4", - "price": 1581.19 + "price": 1119.28 } ] } diff --git a/tests/components/nordpool/fixtures/delivery_period_yesterday.json b/tests/components/nordpool/fixtures/delivery_period_yesterday.json index bc79aeb99f07b..16af0a569345a 100644 --- a/tests/components/nordpool/fixtures/delivery_period_yesterday.json +++ b/tests/components/nordpool/fixtures/delivery_period_yesterday.json @@ -1,258 +1,258 @@ { - "deliveryDateCET": "2024-11-04", + "deliveryDateCET": "2025-09-30", "version": 3, - "updatedAt": "2024-11-04T08:09:11.1931991Z", + "updatedAt": "2025-09-29T11:17:12.3019385Z", "deliveryAreas": ["SE3", "SE4"], "market": "DayAhead", "multiAreaEntries": [ { - "deliveryStart": "2024-11-03T23:00:00Z", - "deliveryEnd": "2024-11-04T00:00:00Z", + "deliveryStart": "2025-09-29T22:00:00Z", + "deliveryEnd": "2025-09-29T23:00:00Z", "entryPerArea": { - "SE3": 66.13, - "SE4": 78.59 + "SE3": 278.63, + "SE4": 354.65 } }, { - "deliveryStart": "2024-11-04T00:00:00Z", - "deliveryEnd": "2024-11-04T01:00:00Z", + "deliveryStart": "2025-09-29T23:00:00Z", + "deliveryEnd": "2025-09-30T00:00:00Z", "entryPerArea": { - "SE3": 72.54, - "SE4": 86.51 + "SE3": 261.85, + "SE4": 336.89 } }, { - "deliveryStart": "2024-11-04T01:00:00Z", - "deliveryEnd": "2024-11-04T02:00:00Z", + "deliveryStart": "2025-09-30T00:00:00Z", + "deliveryEnd": "2025-09-30T01:00:00Z", "entryPerArea": { - "SE3": 73.12, - "SE4": 84.88 + "SE3": 242.43, + "SE4": 313.16 } }, { - "deliveryStart": "2024-11-04T02:00:00Z", - "deliveryEnd": "2024-11-04T03:00:00Z", + "deliveryStart": "2025-09-30T01:00:00Z", + "deliveryEnd": "2025-09-30T02:00:00Z", "entryPerArea": { - "SE3": 171.97, - "SE4": 217.26 + "SE3": 322.65, + "SE4": 401.0 } }, { - "deliveryStart": "2024-11-04T03:00:00Z", - "deliveryEnd": "2024-11-04T04:00:00Z", + "deliveryStart": "2025-09-30T02:00:00Z", + "deliveryEnd": "2025-09-30T03:00:00Z", "entryPerArea": { - "SE3": 181.05, - "SE4": 227.74 + "SE3": 243.2, + "SE4": 311.51 } }, { - "deliveryStart": "2024-11-04T04:00:00Z", - "deliveryEnd": "2024-11-04T05:00:00Z", + "deliveryStart": "2025-09-30T03:00:00Z", + "deliveryEnd": "2025-09-30T04:00:00Z", "entryPerArea": { - "SE3": 360.71, - "SE4": 414.61 + "SE3": 596.53, + "SE4": 695.52 } }, { - "deliveryStart": "2024-11-04T05:00:00Z", - "deliveryEnd": "2024-11-04T06:00:00Z", + "deliveryStart": "2025-09-30T04:00:00Z", + "deliveryEnd": "2025-09-30T05:00:00Z", "entryPerArea": { - "SE3": 917.83, - "SE4": 1439.33 + "SE3": 899.77, + "SE4": 1047.52 } }, { - "deliveryStart": "2024-11-04T06:00:00Z", - "deliveryEnd": "2024-11-04T07:00:00Z", + "deliveryStart": "2025-09-30T05:00:00Z", + "deliveryEnd": "2025-09-30T06:00:00Z", "entryPerArea": { - "SE3": 1426.17, - "SE4": 1695.95 + "SE3": 1909.0, + "SE4": 2247.98 } }, { - "deliveryStart": "2024-11-04T07:00:00Z", - "deliveryEnd": "2024-11-04T08:00:00Z", + "deliveryStart": "2025-09-30T06:00:00Z", + "deliveryEnd": "2025-09-30T07:00:00Z", "entryPerArea": { - "SE3": 1350.96, - "SE4": 1605.13 + "SE3": 1432.52, + "SE4": 1681.24 } }, { - "deliveryStart": "2024-11-04T08:00:00Z", - "deliveryEnd": "2024-11-04T09:00:00Z", + "deliveryStart": "2025-09-30T07:00:00Z", + "deliveryEnd": "2025-09-30T08:00:00Z", "entryPerArea": { - "SE3": 1195.06, - "SE4": 1393.46 + "SE3": 1127.52, + "SE4": 1304.96 } }, { - "deliveryStart": "2024-11-04T09:00:00Z", - "deliveryEnd": "2024-11-04T10:00:00Z", + "deliveryStart": "2025-09-30T08:00:00Z", + "deliveryEnd": "2025-09-30T09:00:00Z", "entryPerArea": { - "SE3": 992.35, - "SE4": 1126.71 + "SE3": 966.75, + "SE4": 1073.34 } }, { - "deliveryStart": "2024-11-04T10:00:00Z", - "deliveryEnd": "2024-11-04T11:00:00Z", + "deliveryStart": "2025-09-30T09:00:00Z", + "deliveryEnd": "2025-09-30T10:00:00Z", "entryPerArea": { - "SE3": 976.63, - "SE4": 1107.97 + "SE3": 882.55, + "SE4": 1003.93 } }, { - "deliveryStart": "2024-11-04T11:00:00Z", - "deliveryEnd": "2024-11-04T12:00:00Z", + "deliveryStart": "2025-09-30T10:00:00Z", + "deliveryEnd": "2025-09-30T11:00:00Z", "entryPerArea": { - "SE3": 952.76, - "SE4": 1085.73 + "SE3": 841.72, + "SE4": 947.44 } }, { - "deliveryStart": "2024-11-04T12:00:00Z", - "deliveryEnd": "2024-11-04T13:00:00Z", + "deliveryStart": "2025-09-30T11:00:00Z", + "deliveryEnd": "2025-09-30T12:00:00Z", "entryPerArea": { - "SE3": 1029.37, - "SE4": 1177.71 + "SE3": 821.53, + "SE4": 927.24 } }, { - "deliveryStart": "2024-11-04T13:00:00Z", - "deliveryEnd": "2024-11-04T14:00:00Z", + "deliveryStart": "2025-09-30T12:00:00Z", + "deliveryEnd": "2025-09-30T13:00:00Z", "entryPerArea": { - "SE3": 1043.35, - "SE4": 1194.59 + "SE3": 864.35, + "SE4": 970.5 } }, { - "deliveryStart": "2024-11-04T14:00:00Z", - "deliveryEnd": "2024-11-04T15:00:00Z", + "deliveryStart": "2025-09-30T13:00:00Z", + "deliveryEnd": "2025-09-30T14:00:00Z", "entryPerArea": { - "SE3": 1359.57, - "SE4": 1561.12 + "SE3": 931.88, + "SE4": 1046.64 } }, { - "deliveryStart": "2024-11-04T15:00:00Z", - "deliveryEnd": "2024-11-04T16:00:00Z", + "deliveryStart": "2025-09-30T14:00:00Z", + "deliveryEnd": "2025-09-30T15:00:00Z", "entryPerArea": { - "SE3": 1848.35, - "SE4": 2145.84 + "SE3": 1039.13, + "SE4": 1165.04 } }, { - "deliveryStart": "2024-11-04T16:00:00Z", - "deliveryEnd": "2024-11-04T17:00:00Z", + "deliveryStart": "2025-09-30T15:00:00Z", + "deliveryEnd": "2025-09-30T16:00:00Z", "entryPerArea": { - "SE3": 2812.53, - "SE4": 3313.53 + "SE3": 1296.57, + "SE4": 1520.91 } }, { - "deliveryStart": "2024-11-04T17:00:00Z", - "deliveryEnd": "2024-11-04T18:00:00Z", + "deliveryStart": "2025-09-30T16:00:00Z", + "deliveryEnd": "2025-09-30T17:00:00Z", "entryPerArea": { - "SE3": 2351.69, - "SE4": 2751.87 + "SE3": 2652.18, + "SE4": 3083.2 } }, { - "deliveryStart": "2024-11-04T18:00:00Z", - "deliveryEnd": "2024-11-04T19:00:00Z", + "deliveryStart": "2025-09-30T17:00:00Z", + "deliveryEnd": "2025-09-30T18:00:00Z", "entryPerArea": { - "SE3": 1553.08, - "SE4": 1842.77 + "SE3": 2135.98, + "SE4": 2552.32 } }, { - "deliveryStart": "2024-11-04T19:00:00Z", - "deliveryEnd": "2024-11-04T20:00:00Z", + "deliveryStart": "2025-09-30T18:00:00Z", + "deliveryEnd": "2025-09-30T19:00:00Z", "entryPerArea": { - "SE3": 1165.02, - "SE4": 1398.35 + "SE3": 1109.76, + "SE4": 1305.73 } }, { - "deliveryStart": "2024-11-04T20:00:00Z", - "deliveryEnd": "2024-11-04T21:00:00Z", + "deliveryStart": "2025-09-30T19:00:00Z", + "deliveryEnd": "2025-09-30T20:00:00Z", "entryPerArea": { - "SE3": 1007.48, - "SE4": 1172.35 + "SE3": 973.81, + "SE4": 1130.83 } }, { - "deliveryStart": "2024-11-04T21:00:00Z", - "deliveryEnd": "2024-11-04T22:00:00Z", + "deliveryStart": "2025-09-30T20:00:00Z", + "deliveryEnd": "2025-09-30T21:00:00Z", "entryPerArea": { - "SE3": 792.09, - "SE4": 920.28 + "SE3": 872.18, + "SE4": 1019.05 } }, { - "deliveryStart": "2024-11-04T22:00:00Z", - "deliveryEnd": "2024-11-04T23:00:00Z", + "deliveryStart": "2025-09-30T21:00:00Z", + "deliveryEnd": "2025-09-30T22:00:00Z", "entryPerArea": { - "SE3": 465.38, - "SE4": 528.83 + "SE3": 697.17, + "SE4": 812.37 } } ], "blockPriceAggregates": [ { "blockName": "Off-peak 1", - "deliveryStart": "2024-11-03T23:00:00Z", - "deliveryEnd": "2024-11-04T07:00:00Z", + "deliveryStart": "2025-09-29T22:00:00Z", + "deliveryEnd": "2025-09-30T06:00:00Z", "averagePricePerArea": { "SE3": { - "average": 408.69, - "min": 66.13, - "max": 1426.17 + "average": 594.26, + "min": 242.43, + "max": 1909.0 }, "SE4": { - "average": 530.61, - "min": 78.59, - "max": 1695.95 + "average": 713.53, + "min": 311.51, + "max": 2247.98 } } }, { "blockName": "Peak", - "deliveryStart": "2024-11-04T07:00:00Z", - "deliveryEnd": "2024-11-04T19:00:00Z", + "deliveryStart": "2025-09-30T06:00:00Z", + "deliveryEnd": "2025-09-30T18:00:00Z", "averagePricePerArea": { "SE3": { - "average": 1455.48, - "min": 952.76, - "max": 2812.53 + "average": 1249.39, + "min": 821.53, + "max": 2652.18 }, "SE4": { - "average": 1692.2, - "min": 1085.73, - "max": 3313.53 + "average": 1439.73, + "min": 927.24, + "max": 3083.2 } } }, { "blockName": "Off-peak 2", - "deliveryStart": "2024-11-04T19:00:00Z", - "deliveryEnd": "2024-11-04T23:00:00Z", + "deliveryStart": "2025-09-30T18:00:00Z", + "deliveryEnd": "2025-09-30T22:00:00Z", "averagePricePerArea": { "SE3": { - "average": 857.49, - "min": 465.38, - "max": 1165.02 + "average": 913.23, + "min": 697.17, + "max": 1109.76 }, "SE4": { - "average": 1004.95, - "min": 528.83, - "max": 1398.35 + "average": 1067.0, + "min": 812.37, + "max": 1305.73 } } } ], "currency": "SEK", - "exchangeRate": 11.64318, + "exchangeRate": 11.03467, "areaStates": [ { "state": "Final", @@ -262,11 +262,11 @@ "areaAverages": [ { "areaCode": "SE3", - "price": 1006.88 + "price": 974.99 }, { "areaCode": "SE4", - "price": 1190.46 + "price": 1135.54 } ] } diff --git a/tests/components/nordpool/fixtures/indices_15.json b/tests/components/nordpool/fixtures/indices_15.json index 63af9840098bc..0af23104104b8 100644 --- a/tests/components/nordpool/fixtures/indices_15.json +++ b/tests/components/nordpool/fixtures/indices_15.json @@ -1,688 +1,688 @@ { - "deliveryDateCET": "2025-07-06", - "version": 2, - "updatedAt": "2025-07-05T10:56:42.3755929Z", + "deliveryDateCET": "2025-10-01", + "version": 3, + "updatedAt": "2025-09-30T12:08:18.4894194Z", "market": "DayAhead", "indexNames": ["SE3"], "currency": "SEK", "resolutionInMinutes": 15, "areaStates": [ { - "state": "Preliminary", + "state": "Final", "areas": ["SE3"] } ], "multiIndexEntries": [ { - "deliveryStart": "2025-07-05T22:00:00Z", - "deliveryEnd": "2025-07-05T22:15:00Z", + "deliveryStart": "2025-09-30T22:00:00Z", + "deliveryEnd": "2025-09-30T22:15:00Z", "entryPerArea": { - "SE3": 43.57 + "SE3": 556.68 } }, { - "deliveryStart": "2025-07-05T22:15:00Z", - "deliveryEnd": "2025-07-05T22:30:00Z", + "deliveryStart": "2025-09-30T22:15:00Z", + "deliveryEnd": "2025-09-30T22:30:00Z", "entryPerArea": { - "SE3": 43.57 + "SE3": 519.88 } }, { - "deliveryStart": "2025-07-05T22:30:00Z", - "deliveryEnd": "2025-07-05T22:45:00Z", + "deliveryStart": "2025-09-30T22:30:00Z", + "deliveryEnd": "2025-09-30T22:45:00Z", "entryPerArea": { - "SE3": 43.57 + "SE3": 508.28 } }, { - "deliveryStart": "2025-07-05T22:45:00Z", - "deliveryEnd": "2025-07-05T23:00:00Z", + "deliveryStart": "2025-09-30T22:45:00Z", + "deliveryEnd": "2025-09-30T23:00:00Z", "entryPerArea": { - "SE3": 43.57 + "SE3": 509.93 } }, { - "deliveryStart": "2025-07-05T23:00:00Z", - "deliveryEnd": "2025-07-05T23:15:00Z", + "deliveryStart": "2025-09-30T23:00:00Z", + "deliveryEnd": "2025-09-30T23:15:00Z", "entryPerArea": { - "SE3": 36.47 + "SE3": 501.64 } }, { - "deliveryStart": "2025-07-05T23:15:00Z", - "deliveryEnd": "2025-07-05T23:30:00Z", + "deliveryStart": "2025-09-30T23:15:00Z", + "deliveryEnd": "2025-09-30T23:30:00Z", "entryPerArea": { - "SE3": 36.47 + "SE3": 509.05 } }, { - "deliveryStart": "2025-07-05T23:30:00Z", - "deliveryEnd": "2025-07-05T23:45:00Z", + "deliveryStart": "2025-09-30T23:30:00Z", + "deliveryEnd": "2025-09-30T23:45:00Z", "entryPerArea": { - "SE3": 36.47 + "SE3": 491.03 } }, { - "deliveryStart": "2025-07-05T23:45:00Z", - "deliveryEnd": "2025-07-06T00:00:00Z", + "deliveryStart": "2025-09-30T23:45:00Z", + "deliveryEnd": "2025-10-01T00:00:00Z", "entryPerArea": { - "SE3": 36.47 + "SE3": 442.07 } }, { - "deliveryStart": "2025-07-06T00:00:00Z", - "deliveryEnd": "2025-07-06T00:15:00Z", + "deliveryStart": "2025-10-01T00:00:00Z", + "deliveryEnd": "2025-10-01T00:15:00Z", "entryPerArea": { - "SE3": 35.57 + "SE3": 504.08 } }, { - "deliveryStart": "2025-07-06T00:15:00Z", - "deliveryEnd": "2025-07-06T00:30:00Z", + "deliveryStart": "2025-10-01T00:15:00Z", + "deliveryEnd": "2025-10-01T00:30:00Z", "entryPerArea": { - "SE3": 35.57 + "SE3": 504.85 } }, { - "deliveryStart": "2025-07-06T00:30:00Z", - "deliveryEnd": "2025-07-06T00:45:00Z", + "deliveryStart": "2025-10-01T00:30:00Z", + "deliveryEnd": "2025-10-01T00:45:00Z", "entryPerArea": { - "SE3": 35.57 + "SE3": 504.3 } }, { - "deliveryStart": "2025-07-06T00:45:00Z", - "deliveryEnd": "2025-07-06T01:00:00Z", + "deliveryStart": "2025-10-01T00:45:00Z", + "deliveryEnd": "2025-10-01T01:00:00Z", "entryPerArea": { - "SE3": 35.57 + "SE3": 506.29 } }, { - "deliveryStart": "2025-07-06T01:00:00Z", - "deliveryEnd": "2025-07-06T01:15:00Z", + "deliveryStart": "2025-10-01T01:00:00Z", + "deliveryEnd": "2025-10-01T01:15:00Z", "entryPerArea": { - "SE3": 30.73 + "SE3": 442.07 } }, { - "deliveryStart": "2025-07-06T01:15:00Z", - "deliveryEnd": "2025-07-06T01:30:00Z", + "deliveryStart": "2025-10-01T01:15:00Z", + "deliveryEnd": "2025-10-01T01:30:00Z", "entryPerArea": { - "SE3": 30.73 + "SE3": 441.96 } }, { - "deliveryStart": "2025-07-06T01:30:00Z", - "deliveryEnd": "2025-07-06T01:45:00Z", + "deliveryStart": "2025-10-01T01:30:00Z", + "deliveryEnd": "2025-10-01T01:45:00Z", "entryPerArea": { - "SE3": 30.73 + "SE3": 442.07 } }, { - "deliveryStart": "2025-07-06T01:45:00Z", - "deliveryEnd": "2025-07-06T02:00:00Z", + "deliveryStart": "2025-10-01T01:45:00Z", + "deliveryEnd": "2025-10-01T02:00:00Z", "entryPerArea": { - "SE3": 30.73 + "SE3": 442.07 } }, { - "deliveryStart": "2025-07-06T02:00:00Z", - "deliveryEnd": "2025-07-06T02:15:00Z", + "deliveryStart": "2025-10-01T02:00:00Z", + "deliveryEnd": "2025-10-01T02:15:00Z", "entryPerArea": { - "SE3": 32.42 + "SE3": 441.96 } }, { - "deliveryStart": "2025-07-06T02:15:00Z", - "deliveryEnd": "2025-07-06T02:30:00Z", + "deliveryStart": "2025-10-01T02:15:00Z", + "deliveryEnd": "2025-10-01T02:30:00Z", "entryPerArea": { - "SE3": 32.42 + "SE3": 483.3 } }, { - "deliveryStart": "2025-07-06T02:30:00Z", - "deliveryEnd": "2025-07-06T02:45:00Z", + "deliveryStart": "2025-10-01T02:30:00Z", + "deliveryEnd": "2025-10-01T02:45:00Z", "entryPerArea": { - "SE3": 32.42 + "SE3": 484.29 } }, { - "deliveryStart": "2025-07-06T02:45:00Z", - "deliveryEnd": "2025-07-06T03:00:00Z", + "deliveryStart": "2025-10-01T02:45:00Z", + "deliveryEnd": "2025-10-01T03:00:00Z", "entryPerArea": { - "SE3": 32.42 + "SE3": 574.7 } }, { - "deliveryStart": "2025-07-06T03:00:00Z", - "deliveryEnd": "2025-07-06T03:15:00Z", + "deliveryStart": "2025-10-01T03:00:00Z", + "deliveryEnd": "2025-10-01T03:15:00Z", "entryPerArea": { - "SE3": 38.73 + "SE3": 543.31 } }, { - "deliveryStart": "2025-07-06T03:15:00Z", - "deliveryEnd": "2025-07-06T03:30:00Z", + "deliveryStart": "2025-10-01T03:15:00Z", + "deliveryEnd": "2025-10-01T03:30:00Z", "entryPerArea": { - "SE3": 38.73 + "SE3": 578.01 } }, { - "deliveryStart": "2025-07-06T03:30:00Z", - "deliveryEnd": "2025-07-06T03:45:00Z", + "deliveryStart": "2025-10-01T03:30:00Z", + "deliveryEnd": "2025-10-01T03:45:00Z", "entryPerArea": { - "SE3": 38.73 + "SE3": 774.96 } }, { - "deliveryStart": "2025-07-06T03:45:00Z", - "deliveryEnd": "2025-07-06T04:00:00Z", + "deliveryStart": "2025-10-01T03:45:00Z", + "deliveryEnd": "2025-10-01T04:00:00Z", "entryPerArea": { - "SE3": 38.73 + "SE3": 787.0 } }, { - "deliveryStart": "2025-07-06T04:00:00Z", - "deliveryEnd": "2025-07-06T04:15:00Z", + "deliveryStart": "2025-10-01T04:00:00Z", + "deliveryEnd": "2025-10-01T04:15:00Z", "entryPerArea": { - "SE3": 42.78 + "SE3": 902.38 } }, { - "deliveryStart": "2025-07-06T04:15:00Z", - "deliveryEnd": "2025-07-06T04:30:00Z", + "deliveryStart": "2025-10-01T04:15:00Z", + "deliveryEnd": "2025-10-01T04:30:00Z", "entryPerArea": { - "SE3": 42.78 + "SE3": 1079.32 } }, { - "deliveryStart": "2025-07-06T04:30:00Z", - "deliveryEnd": "2025-07-06T04:45:00Z", + "deliveryStart": "2025-10-01T04:30:00Z", + "deliveryEnd": "2025-10-01T04:45:00Z", "entryPerArea": { - "SE3": 42.78 + "SE3": 1222.67 } }, { - "deliveryStart": "2025-07-06T04:45:00Z", - "deliveryEnd": "2025-07-06T05:00:00Z", + "deliveryStart": "2025-10-01T04:45:00Z", + "deliveryEnd": "2025-10-01T05:00:00Z", "entryPerArea": { - "SE3": 42.78 + "SE3": 1394.63 } }, { - "deliveryStart": "2025-07-06T05:00:00Z", - "deliveryEnd": "2025-07-06T05:15:00Z", + "deliveryStart": "2025-10-01T05:00:00Z", + "deliveryEnd": "2025-10-01T05:15:00Z", "entryPerArea": { - "SE3": 54.71 + "SE3": 1529.36 } }, { - "deliveryStart": "2025-07-06T05:15:00Z", - "deliveryEnd": "2025-07-06T05:30:00Z", + "deliveryStart": "2025-10-01T05:15:00Z", + "deliveryEnd": "2025-10-01T05:30:00Z", "entryPerArea": { - "SE3": 54.71 + "SE3": 1724.53 } }, { - "deliveryStart": "2025-07-06T05:30:00Z", - "deliveryEnd": "2025-07-06T05:45:00Z", + "deliveryStart": "2025-10-01T05:30:00Z", + "deliveryEnd": "2025-10-01T05:45:00Z", "entryPerArea": { - "SE3": 54.71 + "SE3": 1809.96 } }, { - "deliveryStart": "2025-07-06T05:45:00Z", - "deliveryEnd": "2025-07-06T06:00:00Z", + "deliveryStart": "2025-10-01T05:45:00Z", + "deliveryEnd": "2025-10-01T06:00:00Z", "entryPerArea": { - "SE3": 54.71 + "SE3": 1713.04 } }, { - "deliveryStart": "2025-07-06T06:00:00Z", - "deliveryEnd": "2025-07-06T06:15:00Z", + "deliveryStart": "2025-10-01T06:00:00Z", + "deliveryEnd": "2025-10-01T06:15:00Z", "entryPerArea": { - "SE3": 83.87 + "SE3": 1925.9 } }, { - "deliveryStart": "2025-07-06T06:15:00Z", - "deliveryEnd": "2025-07-06T06:30:00Z", + "deliveryStart": "2025-10-01T06:15:00Z", + "deliveryEnd": "2025-10-01T06:30:00Z", "entryPerArea": { - "SE3": 83.87 + "SE3": 1440.06 } }, { - "deliveryStart": "2025-07-06T06:30:00Z", - "deliveryEnd": "2025-07-06T06:45:00Z", + "deliveryStart": "2025-10-01T06:30:00Z", + "deliveryEnd": "2025-10-01T06:45:00Z", "entryPerArea": { - "SE3": 83.87 + "SE3": 1183.32 } }, { - "deliveryStart": "2025-07-06T06:45:00Z", - "deliveryEnd": "2025-07-06T07:00:00Z", + "deliveryStart": "2025-10-01T06:45:00Z", + "deliveryEnd": "2025-10-01T07:00:00Z", "entryPerArea": { - "SE3": 83.87 + "SE3": 962.95 } }, { - "deliveryStart": "2025-07-06T07:00:00Z", - "deliveryEnd": "2025-07-06T07:15:00Z", + "deliveryStart": "2025-10-01T07:00:00Z", + "deliveryEnd": "2025-10-01T07:15:00Z", "entryPerArea": { - "SE3": 78.8 + "SE3": 1402.04 } }, { - "deliveryStart": "2025-07-06T07:15:00Z", - "deliveryEnd": "2025-07-06T07:30:00Z", + "deliveryStart": "2025-10-01T07:15:00Z", + "deliveryEnd": "2025-10-01T07:30:00Z", "entryPerArea": { - "SE3": 78.8 + "SE3": 1060.65 } }, { - "deliveryStart": "2025-07-06T07:30:00Z", - "deliveryEnd": "2025-07-06T07:45:00Z", + "deliveryStart": "2025-10-01T07:30:00Z", + "deliveryEnd": "2025-10-01T07:45:00Z", "entryPerArea": { - "SE3": 78.8 + "SE3": 949.13 } }, { - "deliveryStart": "2025-07-06T07:45:00Z", - "deliveryEnd": "2025-07-06T08:00:00Z", + "deliveryStart": "2025-10-01T07:45:00Z", + "deliveryEnd": "2025-10-01T08:00:00Z", "entryPerArea": { - "SE3": 78.8 + "SE3": 841.82 } }, { - "deliveryStart": "2025-07-06T08:00:00Z", - "deliveryEnd": "2025-07-06T08:15:00Z", + "deliveryStart": "2025-10-01T08:00:00Z", + "deliveryEnd": "2025-10-01T08:15:00Z", "entryPerArea": { - "SE3": 92.09 + "SE3": 1037.44 } }, { - "deliveryStart": "2025-07-06T08:15:00Z", - "deliveryEnd": "2025-07-06T08:30:00Z", + "deliveryStart": "2025-10-01T08:15:00Z", + "deliveryEnd": "2025-10-01T08:30:00Z", "entryPerArea": { - "SE3": 92.09 + "SE3": 950.13 } }, { - "deliveryStart": "2025-07-06T08:30:00Z", - "deliveryEnd": "2025-07-06T08:45:00Z", + "deliveryStart": "2025-10-01T08:30:00Z", + "deliveryEnd": "2025-10-01T08:45:00Z", "entryPerArea": { - "SE3": 92.09 + "SE3": 826.13 } }, { - "deliveryStart": "2025-07-06T08:45:00Z", - "deliveryEnd": "2025-07-06T09:00:00Z", + "deliveryStart": "2025-10-01T08:45:00Z", + "deliveryEnd": "2025-10-01T09:00:00Z", "entryPerArea": { - "SE3": 92.09 + "SE3": 684.55 } }, { - "deliveryStart": "2025-07-06T09:00:00Z", - "deliveryEnd": "2025-07-06T09:15:00Z", + "deliveryStart": "2025-10-01T09:00:00Z", + "deliveryEnd": "2025-10-01T09:15:00Z", "entryPerArea": { - "SE3": 104.92 + "SE3": 861.6 } }, { - "deliveryStart": "2025-07-06T09:15:00Z", - "deliveryEnd": "2025-07-06T09:30:00Z", + "deliveryStart": "2025-10-01T09:15:00Z", + "deliveryEnd": "2025-10-01T09:30:00Z", "entryPerArea": { - "SE3": 104.92 + "SE3": 722.79 } }, { - "deliveryStart": "2025-07-06T09:30:00Z", - "deliveryEnd": "2025-07-06T09:45:00Z", + "deliveryStart": "2025-10-01T09:30:00Z", + "deliveryEnd": "2025-10-01T09:45:00Z", "entryPerArea": { - "SE3": 104.92 + "SE3": 640.57 } }, { - "deliveryStart": "2025-07-06T09:45:00Z", - "deliveryEnd": "2025-07-06T10:00:00Z", + "deliveryStart": "2025-10-01T09:45:00Z", + "deliveryEnd": "2025-10-01T10:00:00Z", "entryPerArea": { - "SE3": 104.92 + "SE3": 607.74 } }, { - "deliveryStart": "2025-07-06T10:00:00Z", - "deliveryEnd": "2025-07-06T10:15:00Z", + "deliveryStart": "2025-10-01T10:00:00Z", + "deliveryEnd": "2025-10-01T10:15:00Z", "entryPerArea": { - "SE3": 72.5 + "SE3": 674.05 } }, { - "deliveryStart": "2025-07-06T10:15:00Z", - "deliveryEnd": "2025-07-06T10:30:00Z", + "deliveryStart": "2025-10-01T10:15:00Z", + "deliveryEnd": "2025-10-01T10:30:00Z", "entryPerArea": { - "SE3": 72.5 + "SE3": 638.58 } }, { - "deliveryStart": "2025-07-06T10:30:00Z", - "deliveryEnd": "2025-07-06T10:45:00Z", + "deliveryStart": "2025-10-01T10:30:00Z", + "deliveryEnd": "2025-10-01T10:45:00Z", "entryPerArea": { - "SE3": 72.5 + "SE3": 638.47 } }, { - "deliveryStart": "2025-07-06T10:45:00Z", - "deliveryEnd": "2025-07-06T11:00:00Z", + "deliveryStart": "2025-10-01T10:45:00Z", + "deliveryEnd": "2025-10-01T11:00:00Z", "entryPerArea": { - "SE3": 72.5 + "SE3": 634.82 } }, { - "deliveryStart": "2025-07-06T11:00:00Z", - "deliveryEnd": "2025-07-06T11:15:00Z", + "deliveryStart": "2025-10-01T11:00:00Z", + "deliveryEnd": "2025-10-01T11:15:00Z", "entryPerArea": { - "SE3": 63.49 + "SE3": 637.36 } }, { - "deliveryStart": "2025-07-06T11:15:00Z", - "deliveryEnd": "2025-07-06T11:30:00Z", + "deliveryStart": "2025-10-01T11:15:00Z", + "deliveryEnd": "2025-10-01T11:30:00Z", "entryPerArea": { - "SE3": 63.49 + "SE3": 660.68 } }, { - "deliveryStart": "2025-07-06T11:30:00Z", - "deliveryEnd": "2025-07-06T11:45:00Z", + "deliveryStart": "2025-10-01T11:30:00Z", + "deliveryEnd": "2025-10-01T11:45:00Z", "entryPerArea": { - "SE3": 63.49 + "SE3": 679.14 } }, { - "deliveryStart": "2025-07-06T11:45:00Z", - "deliveryEnd": "2025-07-06T12:00:00Z", + "deliveryStart": "2025-10-01T11:45:00Z", + "deliveryEnd": "2025-10-01T12:00:00Z", "entryPerArea": { - "SE3": 63.49 + "SE3": 694.61 } }, { - "deliveryStart": "2025-07-06T12:00:00Z", - "deliveryEnd": "2025-07-06T12:15:00Z", + "deliveryStart": "2025-10-01T12:00:00Z", + "deliveryEnd": "2025-10-01T12:15:00Z", "entryPerArea": { - "SE3": 91.64 + "SE3": 622.33 } }, { - "deliveryStart": "2025-07-06T12:15:00Z", - "deliveryEnd": "2025-07-06T12:30:00Z", + "deliveryStart": "2025-10-01T12:15:00Z", + "deliveryEnd": "2025-10-01T12:30:00Z", "entryPerArea": { - "SE3": 91.64 + "SE3": 685.44 } }, { - "deliveryStart": "2025-07-06T12:30:00Z", - "deliveryEnd": "2025-07-06T12:45:00Z", + "deliveryStart": "2025-10-01T12:30:00Z", + "deliveryEnd": "2025-10-01T12:45:00Z", "entryPerArea": { - "SE3": 91.64 + "SE3": 732.85 } }, { - "deliveryStart": "2025-07-06T12:45:00Z", - "deliveryEnd": "2025-07-06T13:00:00Z", + "deliveryStart": "2025-10-01T12:45:00Z", + "deliveryEnd": "2025-10-01T13:00:00Z", "entryPerArea": { - "SE3": 91.64 + "SE3": 801.92 } }, { - "deliveryStart": "2025-07-06T13:00:00Z", - "deliveryEnd": "2025-07-06T13:15:00Z", + "deliveryStart": "2025-10-01T13:00:00Z", + "deliveryEnd": "2025-10-01T13:15:00Z", "entryPerArea": { - "SE3": 111.79 + "SE3": 629.4 } }, { - "deliveryStart": "2025-07-06T13:15:00Z", - "deliveryEnd": "2025-07-06T13:30:00Z", + "deliveryStart": "2025-10-01T13:15:00Z", + "deliveryEnd": "2025-10-01T13:30:00Z", "entryPerArea": { - "SE3": 111.79 + "SE3": 729.53 } }, { - "deliveryStart": "2025-07-06T13:30:00Z", - "deliveryEnd": "2025-07-06T13:45:00Z", + "deliveryStart": "2025-10-01T13:30:00Z", + "deliveryEnd": "2025-10-01T13:45:00Z", "entryPerArea": { - "SE3": 111.79 + "SE3": 884.81 } }, { - "deliveryStart": "2025-07-06T13:45:00Z", - "deliveryEnd": "2025-07-06T14:00:00Z", + "deliveryStart": "2025-10-01T13:45:00Z", + "deliveryEnd": "2025-10-01T14:00:00Z", "entryPerArea": { - "SE3": 111.79 + "SE3": 984.94 } }, { - "deliveryStart": "2025-07-06T14:00:00Z", - "deliveryEnd": "2025-07-06T14:15:00Z", + "deliveryStart": "2025-10-01T14:00:00Z", + "deliveryEnd": "2025-10-01T14:15:00Z", "entryPerArea": { - "SE3": 234.04 + "SE3": 615.26 } }, { - "deliveryStart": "2025-07-06T14:15:00Z", - "deliveryEnd": "2025-07-06T14:30:00Z", + "deliveryStart": "2025-10-01T14:15:00Z", + "deliveryEnd": "2025-10-01T14:30:00Z", "entryPerArea": { - "SE3": 234.04 + "SE3": 902.94 } }, { - "deliveryStart": "2025-07-06T14:30:00Z", - "deliveryEnd": "2025-07-06T14:45:00Z", + "deliveryStart": "2025-10-01T14:30:00Z", + "deliveryEnd": "2025-10-01T14:45:00Z", "entryPerArea": { - "SE3": 234.04 + "SE3": 1043.85 } }, { - "deliveryStart": "2025-07-06T14:45:00Z", - "deliveryEnd": "2025-07-06T15:00:00Z", + "deliveryStart": "2025-10-01T14:45:00Z", + "deliveryEnd": "2025-10-01T15:00:00Z", "entryPerArea": { - "SE3": 234.04 + "SE3": 1075.12 } }, { - "deliveryStart": "2025-07-06T15:00:00Z", - "deliveryEnd": "2025-07-06T15:15:00Z", + "deliveryStart": "2025-10-01T15:00:00Z", + "deliveryEnd": "2025-10-01T15:15:00Z", "entryPerArea": { - "SE3": 435.33 + "SE3": 980.52 } }, { - "deliveryStart": "2025-07-06T15:15:00Z", - "deliveryEnd": "2025-07-06T15:30:00Z", + "deliveryStart": "2025-10-01T15:15:00Z", + "deliveryEnd": "2025-10-01T15:30:00Z", "entryPerArea": { - "SE3": 435.33 + "SE3": 1162.66 } }, { - "deliveryStart": "2025-07-06T15:30:00Z", - "deliveryEnd": "2025-07-06T15:45:00Z", + "deliveryStart": "2025-10-01T15:30:00Z", + "deliveryEnd": "2025-10-01T15:45:00Z", "entryPerArea": { - "SE3": 435.33 + "SE3": 1453.87 } }, { - "deliveryStart": "2025-07-06T15:45:00Z", - "deliveryEnd": "2025-07-06T16:00:00Z", + "deliveryStart": "2025-10-01T15:45:00Z", + "deliveryEnd": "2025-10-01T16:00:00Z", "entryPerArea": { - "SE3": 435.33 + "SE3": 1955.96 } }, { - "deliveryStart": "2025-07-06T16:00:00Z", - "deliveryEnd": "2025-07-06T16:15:00Z", + "deliveryStart": "2025-10-01T16:00:00Z", + "deliveryEnd": "2025-10-01T16:15:00Z", "entryPerArea": { - "SE3": 431.84 + "SE3": 1423.48 } }, { - "deliveryStart": "2025-07-06T16:15:00Z", - "deliveryEnd": "2025-07-06T16:30:00Z", + "deliveryStart": "2025-10-01T16:15:00Z", + "deliveryEnd": "2025-10-01T16:30:00Z", "entryPerArea": { - "SE3": 431.84 + "SE3": 1900.04 } }, { - "deliveryStart": "2025-07-06T16:30:00Z", - "deliveryEnd": "2025-07-06T16:45:00Z", + "deliveryStart": "2025-10-01T16:30:00Z", + "deliveryEnd": "2025-10-01T16:45:00Z", "entryPerArea": { - "SE3": 431.84 + "SE3": 2611.11 } }, { - "deliveryStart": "2025-07-06T16:45:00Z", - "deliveryEnd": "2025-07-06T17:00:00Z", + "deliveryStart": "2025-10-01T16:45:00Z", + "deliveryEnd": "2025-10-01T17:00:00Z", "entryPerArea": { - "SE3": 431.84 + "SE3": 3467.41 } }, { - "deliveryStart": "2025-07-06T17:00:00Z", - "deliveryEnd": "2025-07-06T17:15:00Z", + "deliveryStart": "2025-10-01T17:00:00Z", + "deliveryEnd": "2025-10-01T17:15:00Z", "entryPerArea": { - "SE3": 423.73 + "SE3": 3828.03 } }, { - "deliveryStart": "2025-07-06T17:15:00Z", - "deliveryEnd": "2025-07-06T17:30:00Z", + "deliveryStart": "2025-10-01T17:15:00Z", + "deliveryEnd": "2025-10-01T17:30:00Z", "entryPerArea": { - "SE3": 423.73 + "SE3": 3429.83 } }, { - "deliveryStart": "2025-07-06T17:30:00Z", - "deliveryEnd": "2025-07-06T17:45:00Z", + "deliveryStart": "2025-10-01T17:30:00Z", + "deliveryEnd": "2025-10-01T17:45:00Z", "entryPerArea": { - "SE3": 423.73 + "SE3": 2934.38 } }, { - "deliveryStart": "2025-07-06T17:45:00Z", - "deliveryEnd": "2025-07-06T18:00:00Z", + "deliveryStart": "2025-10-01T17:45:00Z", + "deliveryEnd": "2025-10-01T18:00:00Z", "entryPerArea": { - "SE3": 423.73 + "SE3": 2308.07 } }, { - "deliveryStart": "2025-07-06T18:00:00Z", - "deliveryEnd": "2025-07-06T18:15:00Z", + "deliveryStart": "2025-10-01T18:00:00Z", + "deliveryEnd": "2025-10-01T18:15:00Z", "entryPerArea": { - "SE3": 437.92 + "SE3": 1997.96 } }, { - "deliveryStart": "2025-07-06T18:15:00Z", - "deliveryEnd": "2025-07-06T18:30:00Z", + "deliveryStart": "2025-10-01T18:15:00Z", + "deliveryEnd": "2025-10-01T18:30:00Z", "entryPerArea": { - "SE3": 437.92 + "SE3": 1424.03 } }, { - "deliveryStart": "2025-07-06T18:30:00Z", - "deliveryEnd": "2025-07-06T18:45:00Z", + "deliveryStart": "2025-10-01T18:30:00Z", + "deliveryEnd": "2025-10-01T18:45:00Z", "entryPerArea": { - "SE3": 437.92 + "SE3": 1216.81 } }, { - "deliveryStart": "2025-07-06T18:45:00Z", - "deliveryEnd": "2025-07-06T19:00:00Z", + "deliveryStart": "2025-10-01T18:45:00Z", + "deliveryEnd": "2025-10-01T19:00:00Z", "entryPerArea": { - "SE3": 437.92 + "SE3": 1070.15 } }, { - "deliveryStart": "2025-07-06T19:00:00Z", - "deliveryEnd": "2025-07-06T19:15:00Z", + "deliveryStart": "2025-10-01T19:00:00Z", + "deliveryEnd": "2025-10-01T19:15:00Z", "entryPerArea": { - "SE3": 416.42 + "SE3": 1218.14 } }, { - "deliveryStart": "2025-07-06T19:15:00Z", - "deliveryEnd": "2025-07-06T19:30:00Z", + "deliveryStart": "2025-10-01T19:15:00Z", + "deliveryEnd": "2025-10-01T19:30:00Z", "entryPerArea": { - "SE3": 416.42 + "SE3": 1135.8 } }, { - "deliveryStart": "2025-07-06T19:30:00Z", - "deliveryEnd": "2025-07-06T19:45:00Z", + "deliveryStart": "2025-10-01T19:30:00Z", + "deliveryEnd": "2025-10-01T19:45:00Z", "entryPerArea": { - "SE3": 416.42 + "SE3": 959.96 } }, { - "deliveryStart": "2025-07-06T19:45:00Z", - "deliveryEnd": "2025-07-06T20:00:00Z", + "deliveryStart": "2025-10-01T19:45:00Z", + "deliveryEnd": "2025-10-01T20:00:00Z", "entryPerArea": { - "SE3": 416.42 + "SE3": 913.66 } }, { - "deliveryStart": "2025-07-06T20:00:00Z", - "deliveryEnd": "2025-07-06T20:15:00Z", + "deliveryStart": "2025-10-01T20:00:00Z", + "deliveryEnd": "2025-10-01T20:15:00Z", "entryPerArea": { - "SE3": 414.39 + "SE3": 1001.63 } }, { - "deliveryStart": "2025-07-06T20:15:00Z", - "deliveryEnd": "2025-07-06T20:30:00Z", + "deliveryStart": "2025-10-01T20:15:00Z", + "deliveryEnd": "2025-10-01T20:30:00Z", "entryPerArea": { - "SE3": 414.39 + "SE3": 933.0 } }, { - "deliveryStart": "2025-07-06T20:30:00Z", - "deliveryEnd": "2025-07-06T20:45:00Z", + "deliveryStart": "2025-10-01T20:30:00Z", + "deliveryEnd": "2025-10-01T20:45:00Z", "entryPerArea": { - "SE3": 414.39 + "SE3": 874.53 } }, { - "deliveryStart": "2025-07-06T20:45:00Z", - "deliveryEnd": "2025-07-06T21:00:00Z", + "deliveryStart": "2025-10-01T20:45:00Z", + "deliveryEnd": "2025-10-01T21:00:00Z", "entryPerArea": { - "SE3": 414.39 + "SE3": 821.71 } }, { - "deliveryStart": "2025-07-06T21:00:00Z", - "deliveryEnd": "2025-07-06T21:15:00Z", + "deliveryStart": "2025-10-01T21:00:00Z", + "deliveryEnd": "2025-10-01T21:15:00Z", "entryPerArea": { - "SE3": 396.38 + "SE3": 860.5 } }, { - "deliveryStart": "2025-07-06T21:15:00Z", - "deliveryEnd": "2025-07-06T21:30:00Z", + "deliveryStart": "2025-10-01T21:15:00Z", + "deliveryEnd": "2025-10-01T21:30:00Z", "entryPerArea": { - "SE3": 396.38 + "SE3": 840.16 } }, { - "deliveryStart": "2025-07-06T21:30:00Z", - "deliveryEnd": "2025-07-06T21:45:00Z", + "deliveryStart": "2025-10-01T21:30:00Z", + "deliveryEnd": "2025-10-01T21:45:00Z", "entryPerArea": { - "SE3": 396.38 + "SE3": 820.05 } }, { - "deliveryStart": "2025-07-06T21:45:00Z", - "deliveryEnd": "2025-07-06T22:00:00Z", + "deliveryStart": "2025-10-01T21:45:00Z", + "deliveryEnd": "2025-10-01T22:00:00Z", "entryPerArea": { - "SE3": 396.38 + "SE3": 785.68 } } ] diff --git a/tests/components/nordpool/fixtures/indices_60.json b/tests/components/nordpool/fixtures/indices_60.json index 97bbe554b13da..d9df6671d897e 100644 --- a/tests/components/nordpool/fixtures/indices_60.json +++ b/tests/components/nordpool/fixtures/indices_60.json @@ -1,184 +1,184 @@ { - "deliveryDateCET": "2025-07-06", - "version": 2, - "updatedAt": "2025-07-05T10:56:44.6936838Z", + "deliveryDateCET": "2025-10-01", + "version": 3, + "updatedAt": "2025-09-30T12:08:22.6180024Z", "market": "DayAhead", "indexNames": ["SE3"], "currency": "SEK", "resolutionInMinutes": 60, "areaStates": [ { - "state": "Preliminary", + "state": "Final", "areas": ["SE3"] } ], "multiIndexEntries": [ { - "deliveryStart": "2025-07-05T22:00:00Z", - "deliveryEnd": "2025-07-05T23:00:00Z", + "deliveryStart": "2025-09-30T22:00:00Z", + "deliveryEnd": "2025-09-30T23:00:00Z", "entryPerArea": { - "SE3": 43.57 + "SE3": 523.75 } }, { - "deliveryStart": "2025-07-05T23:00:00Z", - "deliveryEnd": "2025-07-06T00:00:00Z", + "deliveryStart": "2025-09-30T23:00:00Z", + "deliveryEnd": "2025-10-01T00:00:00Z", "entryPerArea": { - "SE3": 36.47 + "SE3": 485.95 } }, { - "deliveryStart": "2025-07-06T00:00:00Z", - "deliveryEnd": "2025-07-06T01:00:00Z", + "deliveryStart": "2025-10-01T00:00:00Z", + "deliveryEnd": "2025-10-01T01:00:00Z", "entryPerArea": { - "SE3": 35.57 + "SE3": 504.85 } }, { - "deliveryStart": "2025-07-06T01:00:00Z", - "deliveryEnd": "2025-07-06T02:00:00Z", + "deliveryStart": "2025-10-01T01:00:00Z", + "deliveryEnd": "2025-10-01T02:00:00Z", "entryPerArea": { - "SE3": 30.73 + "SE3": 442.07 } }, { - "deliveryStart": "2025-07-06T02:00:00Z", - "deliveryEnd": "2025-07-06T03:00:00Z", + "deliveryStart": "2025-10-01T02:00:00Z", + "deliveryEnd": "2025-10-01T03:00:00Z", "entryPerArea": { - "SE3": 32.42 + "SE3": 496.12 } }, { - "deliveryStart": "2025-07-06T03:00:00Z", - "deliveryEnd": "2025-07-06T04:00:00Z", + "deliveryStart": "2025-10-01T03:00:00Z", + "deliveryEnd": "2025-10-01T04:00:00Z", "entryPerArea": { - "SE3": 38.73 + "SE3": 670.85 } }, { - "deliveryStart": "2025-07-06T04:00:00Z", - "deliveryEnd": "2025-07-06T05:00:00Z", + "deliveryStart": "2025-10-01T04:00:00Z", + "deliveryEnd": "2025-10-01T05:00:00Z", "entryPerArea": { - "SE3": 42.78 + "SE3": 1149.72 } }, { - "deliveryStart": "2025-07-06T05:00:00Z", - "deliveryEnd": "2025-07-06T06:00:00Z", + "deliveryStart": "2025-10-01T05:00:00Z", + "deliveryEnd": "2025-10-01T06:00:00Z", "entryPerArea": { - "SE3": 54.71 + "SE3": 1694.25 } }, { - "deliveryStart": "2025-07-06T06:00:00Z", - "deliveryEnd": "2025-07-06T07:00:00Z", + "deliveryStart": "2025-10-01T06:00:00Z", + "deliveryEnd": "2025-10-01T07:00:00Z", "entryPerArea": { - "SE3": 83.87 + "SE3": 1378.06 } }, { - "deliveryStart": "2025-07-06T07:00:00Z", - "deliveryEnd": "2025-07-06T08:00:00Z", + "deliveryStart": "2025-10-01T07:00:00Z", + "deliveryEnd": "2025-10-01T08:00:00Z", "entryPerArea": { - "SE3": 78.8 + "SE3": 1063.41 } }, { - "deliveryStart": "2025-07-06T08:00:00Z", - "deliveryEnd": "2025-07-06T09:00:00Z", + "deliveryStart": "2025-10-01T08:00:00Z", + "deliveryEnd": "2025-10-01T09:00:00Z", "entryPerArea": { - "SE3": 92.09 + "SE3": 874.53 } }, { - "deliveryStart": "2025-07-06T09:00:00Z", - "deliveryEnd": "2025-07-06T10:00:00Z", + "deliveryStart": "2025-10-01T09:00:00Z", + "deliveryEnd": "2025-10-01T10:00:00Z", "entryPerArea": { - "SE3": 104.92 + "SE3": 708.2 } }, { - "deliveryStart": "2025-07-06T10:00:00Z", - "deliveryEnd": "2025-07-06T11:00:00Z", + "deliveryStart": "2025-10-01T10:00:00Z", + "deliveryEnd": "2025-10-01T11:00:00Z", "entryPerArea": { - "SE3": 72.5 + "SE3": 646.53 } }, { - "deliveryStart": "2025-07-06T11:00:00Z", - "deliveryEnd": "2025-07-06T12:00:00Z", + "deliveryStart": "2025-10-01T11:00:00Z", + "deliveryEnd": "2025-10-01T12:00:00Z", "entryPerArea": { - "SE3": 63.49 + "SE3": 667.97 } }, { - "deliveryStart": "2025-07-06T12:00:00Z", - "deliveryEnd": "2025-07-06T13:00:00Z", + "deliveryStart": "2025-10-01T12:00:00Z", + "deliveryEnd": "2025-10-01T13:00:00Z", "entryPerArea": { - "SE3": 91.64 + "SE3": 710.63 } }, { - "deliveryStart": "2025-07-06T13:00:00Z", - "deliveryEnd": "2025-07-06T14:00:00Z", + "deliveryStart": "2025-10-01T13:00:00Z", + "deliveryEnd": "2025-10-01T14:00:00Z", "entryPerArea": { - "SE3": 111.79 + "SE3": 807.23 } }, { - "deliveryStart": "2025-07-06T14:00:00Z", - "deliveryEnd": "2025-07-06T15:00:00Z", + "deliveryStart": "2025-10-01T14:00:00Z", + "deliveryEnd": "2025-10-01T15:00:00Z", "entryPerArea": { - "SE3": 234.04 + "SE3": 909.35 } }, { - "deliveryStart": "2025-07-06T15:00:00Z", - "deliveryEnd": "2025-07-06T16:00:00Z", + "deliveryStart": "2025-10-01T15:00:00Z", + "deliveryEnd": "2025-10-01T16:00:00Z", "entryPerArea": { - "SE3": 435.33 + "SE3": 1388.22 } }, { - "deliveryStart": "2025-07-06T16:00:00Z", - "deliveryEnd": "2025-07-06T17:00:00Z", + "deliveryStart": "2025-10-01T16:00:00Z", + "deliveryEnd": "2025-10-01T17:00:00Z", "entryPerArea": { - "SE3": 431.84 + "SE3": 2350.51 } }, { - "deliveryStart": "2025-07-06T17:00:00Z", - "deliveryEnd": "2025-07-06T18:00:00Z", + "deliveryStart": "2025-10-01T17:00:00Z", + "deliveryEnd": "2025-10-01T18:00:00Z", "entryPerArea": { - "SE3": 423.73 + "SE3": 3125.13 } }, { - "deliveryStart": "2025-07-06T18:00:00Z", - "deliveryEnd": "2025-07-06T19:00:00Z", + "deliveryStart": "2025-10-01T18:00:00Z", + "deliveryEnd": "2025-10-01T19:00:00Z", "entryPerArea": { - "SE3": 437.92 + "SE3": 1427.24 } }, { - "deliveryStart": "2025-07-06T19:00:00Z", - "deliveryEnd": "2025-07-06T20:00:00Z", + "deliveryStart": "2025-10-01T19:00:00Z", + "deliveryEnd": "2025-10-01T20:00:00Z", "entryPerArea": { - "SE3": 416.42 + "SE3": 1056.89 } }, { - "deliveryStart": "2025-07-06T20:00:00Z", - "deliveryEnd": "2025-07-06T21:00:00Z", + "deliveryStart": "2025-10-01T20:00:00Z", + "deliveryEnd": "2025-10-01T21:00:00Z", "entryPerArea": { - "SE3": 414.39 + "SE3": 907.69 } }, { - "deliveryStart": "2025-07-06T21:00:00Z", - "deliveryEnd": "2025-07-06T22:00:00Z", + "deliveryStart": "2025-10-01T21:00:00Z", + "deliveryEnd": "2025-10-01T22:00:00Z", "entryPerArea": { - "SE3": 396.38 + "SE3": 826.57 } } ] diff --git a/tests/components/nordpool/snapshots/test_diagnostics.ambr b/tests/components/nordpool/snapshots/test_diagnostics.ambr index d7f7c4041cd7f..a4434a1246a21 100644 --- a/tests/components/nordpool/snapshots/test_diagnostics.ambr +++ b/tests/components/nordpool/snapshots/test_diagnostics.ambr @@ -2,15 +2,15 @@ # name: test_diagnostics dict({ 'raw': dict({ - '2024-11-04': dict({ + '2025-09-30': dict({ 'areaAverages': list([ dict({ 'areaCode': 'SE3', - 'price': 1006.88, + 'price': 974.99, }), dict({ 'areaCode': 'SE4', - 'price': 1190.46, + 'price': 1135.54, }), ]), 'areaStates': list([ @@ -26,53 +26,53 @@ dict({ 'averagePricePerArea': dict({ 'SE3': dict({ - 'average': 408.69, - 'max': 1426.17, - 'min': 66.13, + 'average': 594.26, + 'max': 1909.0, + 'min': 242.43, }), 'SE4': dict({ - 'average': 530.61, - 'max': 1695.95, - 'min': 78.59, + 'average': 713.53, + 'max': 2247.98, + 'min': 311.51, }), }), 'blockName': 'Off-peak 1', - 'deliveryEnd': '2024-11-04T07:00:00Z', - 'deliveryStart': '2024-11-03T23:00:00Z', + 'deliveryEnd': '2025-09-30T06:00:00Z', + 'deliveryStart': '2025-09-29T22:00:00Z', }), dict({ 'averagePricePerArea': dict({ 'SE3': dict({ - 'average': 1455.48, - 'max': 2812.53, - 'min': 952.76, + 'average': 1249.39, + 'max': 2652.18, + 'min': 821.53, }), 'SE4': dict({ - 'average': 1692.2, - 'max': 3313.53, - 'min': 1085.73, + 'average': 1439.73, + 'max': 3083.2, + 'min': 927.24, }), }), 'blockName': 'Peak', - 'deliveryEnd': '2024-11-04T19:00:00Z', - 'deliveryStart': '2024-11-04T07:00:00Z', + 'deliveryEnd': '2025-09-30T18:00:00Z', + 'deliveryStart': '2025-09-30T06:00:00Z', }), dict({ 'averagePricePerArea': dict({ 'SE3': dict({ - 'average': 857.49, - 'max': 1165.02, - 'min': 465.38, + 'average': 913.23, + 'max': 1109.76, + 'min': 697.17, }), 'SE4': dict({ - 'average': 1004.95, - 'max': 1398.35, - 'min': 528.83, + 'average': 1067.0, + 'max': 1305.73, + 'min': 812.37, }), }), 'blockName': 'Off-peak 2', - 'deliveryEnd': '2024-11-04T23:00:00Z', - 'deliveryStart': '2024-11-04T19:00:00Z', + 'deliveryEnd': '2025-09-30T22:00:00Z', + 'deliveryStart': '2025-09-30T18:00:00Z', }), ]), 'currency': 'SEK', @@ -80,215 +80,215 @@ 'SE3', 'SE4', ]), - 'deliveryDateCET': '2024-11-04', - 'exchangeRate': 11.64318, + 'deliveryDateCET': '2025-09-30', + 'exchangeRate': 11.03467, 'market': 'DayAhead', 'multiAreaEntries': list([ dict({ - 'deliveryEnd': '2024-11-04T00:00:00Z', - 'deliveryStart': '2024-11-03T23:00:00Z', + 'deliveryEnd': '2025-09-29T23:00:00Z', + 'deliveryStart': '2025-09-29T22:00:00Z', 'entryPerArea': dict({ - 'SE3': 66.13, - 'SE4': 78.59, + 'SE3': 278.63, + 'SE4': 354.65, }), }), dict({ - 'deliveryEnd': '2024-11-04T01:00:00Z', - 'deliveryStart': '2024-11-04T00:00:00Z', + 'deliveryEnd': '2025-09-30T00:00:00Z', + 'deliveryStart': '2025-09-29T23:00:00Z', 'entryPerArea': dict({ - 'SE3': 72.54, - 'SE4': 86.51, + 'SE3': 261.85, + 'SE4': 336.89, }), }), dict({ - 'deliveryEnd': '2024-11-04T02:00:00Z', - 'deliveryStart': '2024-11-04T01:00:00Z', + 'deliveryEnd': '2025-09-30T01:00:00Z', + 'deliveryStart': '2025-09-30T00:00:00Z', 'entryPerArea': dict({ - 'SE3': 73.12, - 'SE4': 84.88, + 'SE3': 242.43, + 'SE4': 313.16, }), }), dict({ - 'deliveryEnd': '2024-11-04T03:00:00Z', - 'deliveryStart': '2024-11-04T02:00:00Z', + 'deliveryEnd': '2025-09-30T02:00:00Z', + 'deliveryStart': '2025-09-30T01:00:00Z', 'entryPerArea': dict({ - 'SE3': 171.97, - 'SE4': 217.26, + 'SE3': 322.65, + 'SE4': 401.0, }), }), dict({ - 'deliveryEnd': '2024-11-04T04:00:00Z', - 'deliveryStart': '2024-11-04T03:00:00Z', + 'deliveryEnd': '2025-09-30T03:00:00Z', + 'deliveryStart': '2025-09-30T02:00:00Z', 'entryPerArea': dict({ - 'SE3': 181.05, - 'SE4': 227.74, + 'SE3': 243.2, + 'SE4': 311.51, }), }), dict({ - 'deliveryEnd': '2024-11-04T05:00:00Z', - 'deliveryStart': '2024-11-04T04:00:00Z', + 'deliveryEnd': '2025-09-30T04:00:00Z', + 'deliveryStart': '2025-09-30T03:00:00Z', 'entryPerArea': dict({ - 'SE3': 360.71, - 'SE4': 414.61, + 'SE3': 596.53, + 'SE4': 695.52, }), }), dict({ - 'deliveryEnd': '2024-11-04T06:00:00Z', - 'deliveryStart': '2024-11-04T05:00:00Z', + 'deliveryEnd': '2025-09-30T05:00:00Z', + 'deliveryStart': '2025-09-30T04:00:00Z', 'entryPerArea': dict({ - 'SE3': 917.83, - 'SE4': 1439.33, + 'SE3': 899.77, + 'SE4': 1047.52, }), }), dict({ - 'deliveryEnd': '2024-11-04T07:00:00Z', - 'deliveryStart': '2024-11-04T06:00:00Z', + 'deliveryEnd': '2025-09-30T06:00:00Z', + 'deliveryStart': '2025-09-30T05:00:00Z', 'entryPerArea': dict({ - 'SE3': 1426.17, - 'SE4': 1695.95, + 'SE3': 1909.0, + 'SE4': 2247.98, }), }), dict({ - 'deliveryEnd': '2024-11-04T08:00:00Z', - 'deliveryStart': '2024-11-04T07:00:00Z', + 'deliveryEnd': '2025-09-30T07:00:00Z', + 'deliveryStart': '2025-09-30T06:00:00Z', 'entryPerArea': dict({ - 'SE3': 1350.96, - 'SE4': 1605.13, + 'SE3': 1432.52, + 'SE4': 1681.24, }), }), dict({ - 'deliveryEnd': '2024-11-04T09:00:00Z', - 'deliveryStart': '2024-11-04T08:00:00Z', + 'deliveryEnd': '2025-09-30T08:00:00Z', + 'deliveryStart': '2025-09-30T07:00:00Z', 'entryPerArea': dict({ - 'SE3': 1195.06, - 'SE4': 1393.46, + 'SE3': 1127.52, + 'SE4': 1304.96, }), }), dict({ - 'deliveryEnd': '2024-11-04T10:00:00Z', - 'deliveryStart': '2024-11-04T09:00:00Z', + 'deliveryEnd': '2025-09-30T09:00:00Z', + 'deliveryStart': '2025-09-30T08:00:00Z', 'entryPerArea': dict({ - 'SE3': 992.35, - 'SE4': 1126.71, + 'SE3': 966.75, + 'SE4': 1073.34, }), }), dict({ - 'deliveryEnd': '2024-11-04T11:00:00Z', - 'deliveryStart': '2024-11-04T10:00:00Z', + 'deliveryEnd': '2025-09-30T10:00:00Z', + 'deliveryStart': '2025-09-30T09:00:00Z', 'entryPerArea': dict({ - 'SE3': 976.63, - 'SE4': 1107.97, + 'SE3': 882.55, + 'SE4': 1003.93, }), }), dict({ - 'deliveryEnd': '2024-11-04T12:00:00Z', - 'deliveryStart': '2024-11-04T11:00:00Z', + 'deliveryEnd': '2025-09-30T11:00:00Z', + 'deliveryStart': '2025-09-30T10:00:00Z', 'entryPerArea': dict({ - 'SE3': 952.76, - 'SE4': 1085.73, + 'SE3': 841.72, + 'SE4': 947.44, }), }), dict({ - 'deliveryEnd': '2024-11-04T13:00:00Z', - 'deliveryStart': '2024-11-04T12:00:00Z', + 'deliveryEnd': '2025-09-30T12:00:00Z', + 'deliveryStart': '2025-09-30T11:00:00Z', 'entryPerArea': dict({ - 'SE3': 1029.37, - 'SE4': 1177.71, + 'SE3': 821.53, + 'SE4': 927.24, }), }), dict({ - 'deliveryEnd': '2024-11-04T14:00:00Z', - 'deliveryStart': '2024-11-04T13:00:00Z', + 'deliveryEnd': '2025-09-30T13:00:00Z', + 'deliveryStart': '2025-09-30T12:00:00Z', 'entryPerArea': dict({ - 'SE3': 1043.35, - 'SE4': 1194.59, + 'SE3': 864.35, + 'SE4': 970.5, }), }), dict({ - 'deliveryEnd': '2024-11-04T15:00:00Z', - 'deliveryStart': '2024-11-04T14:00:00Z', + 'deliveryEnd': '2025-09-30T14:00:00Z', + 'deliveryStart': '2025-09-30T13:00:00Z', 'entryPerArea': dict({ - 'SE3': 1359.57, - 'SE4': 1561.12, + 'SE3': 931.88, + 'SE4': 1046.64, }), }), dict({ - 'deliveryEnd': '2024-11-04T16:00:00Z', - 'deliveryStart': '2024-11-04T15:00:00Z', + 'deliveryEnd': '2025-09-30T15:00:00Z', + 'deliveryStart': '2025-09-30T14:00:00Z', 'entryPerArea': dict({ - 'SE3': 1848.35, - 'SE4': 2145.84, + 'SE3': 1039.13, + 'SE4': 1165.04, }), }), dict({ - 'deliveryEnd': '2024-11-04T17:00:00Z', - 'deliveryStart': '2024-11-04T16:00:00Z', + 'deliveryEnd': '2025-09-30T16:00:00Z', + 'deliveryStart': '2025-09-30T15:00:00Z', 'entryPerArea': dict({ - 'SE3': 2812.53, - 'SE4': 3313.53, + 'SE3': 1296.57, + 'SE4': 1520.91, }), }), dict({ - 'deliveryEnd': '2024-11-04T18:00:00Z', - 'deliveryStart': '2024-11-04T17:00:00Z', + 'deliveryEnd': '2025-09-30T17:00:00Z', + 'deliveryStart': '2025-09-30T16:00:00Z', 'entryPerArea': dict({ - 'SE3': 2351.69, - 'SE4': 2751.87, + 'SE3': 2652.18, + 'SE4': 3083.2, }), }), dict({ - 'deliveryEnd': '2024-11-04T19:00:00Z', - 'deliveryStart': '2024-11-04T18:00:00Z', + 'deliveryEnd': '2025-09-30T18:00:00Z', + 'deliveryStart': '2025-09-30T17:00:00Z', 'entryPerArea': dict({ - 'SE3': 1553.08, - 'SE4': 1842.77, + 'SE3': 2135.98, + 'SE4': 2552.32, }), }), dict({ - 'deliveryEnd': '2024-11-04T20:00:00Z', - 'deliveryStart': '2024-11-04T19:00:00Z', + 'deliveryEnd': '2025-09-30T19:00:00Z', + 'deliveryStart': '2025-09-30T18:00:00Z', 'entryPerArea': dict({ - 'SE3': 1165.02, - 'SE4': 1398.35, + 'SE3': 1109.76, + 'SE4': 1305.73, }), }), dict({ - 'deliveryEnd': '2024-11-04T21:00:00Z', - 'deliveryStart': '2024-11-04T20:00:00Z', + 'deliveryEnd': '2025-09-30T20:00:00Z', + 'deliveryStart': '2025-09-30T19:00:00Z', 'entryPerArea': dict({ - 'SE3': 1007.48, - 'SE4': 1172.35, + 'SE3': 973.81, + 'SE4': 1130.83, }), }), dict({ - 'deliveryEnd': '2024-11-04T22:00:00Z', - 'deliveryStart': '2024-11-04T21:00:00Z', + 'deliveryEnd': '2025-09-30T21:00:00Z', + 'deliveryStart': '2025-09-30T20:00:00Z', 'entryPerArea': dict({ - 'SE3': 792.09, - 'SE4': 920.28, + 'SE3': 872.18, + 'SE4': 1019.05, }), }), dict({ - 'deliveryEnd': '2024-11-04T23:00:00Z', - 'deliveryStart': '2024-11-04T22:00:00Z', + 'deliveryEnd': '2025-09-30T22:00:00Z', + 'deliveryStart': '2025-09-30T21:00:00Z', 'entryPerArea': dict({ - 'SE3': 465.38, - 'SE4': 528.83, + 'SE3': 697.17, + 'SE4': 812.37, }), }), ]), - 'updatedAt': '2024-11-04T08:09:11.1931991Z', + 'updatedAt': '2025-09-29T11:17:12.3019385Z', 'version': 3, }), - '2024-11-05': dict({ + '2025-10-01': dict({ 'areaAverages': list([ dict({ 'areaCode': 'SE3', - 'price': 900.74, + 'price': 1033.98, }), dict({ 'areaCode': 'SE4', - 'price': 1166.12, + 'price': 1180.78, }), ]), 'areaStates': list([ @@ -304,53 +304,53 @@ dict({ 'averagePricePerArea': dict({ 'SE3': dict({ - 'average': 422.87, - 'max': 1406.14, - 'min': 61.69, + 'average': 745.93, + 'max': 1809.96, + 'min': 441.96, }), 'SE4': dict({ - 'average': 497.97, - 'max': 1648.25, - 'min': 65.19, + 'average': 860.99, + 'max': 2029.34, + 'min': 515.46, }), }), 'blockName': 'Off-peak 1', - 'deliveryEnd': '2024-11-05T07:00:00Z', - 'deliveryStart': '2024-11-04T23:00:00Z', + 'deliveryEnd': '2025-10-01T06:00:00Z', + 'deliveryStart': '2025-09-30T22:00:00Z', }), dict({ 'averagePricePerArea': dict({ 'SE3': dict({ - 'average': 1315.97, - 'max': 2512.65, - 'min': 925.05, + 'average': 1219.13, + 'max': 3828.03, + 'min': 607.74, }), 'SE4': dict({ - 'average': 1735.59, - 'max': 3533.03, - 'min': 1081.72, + 'average': 1381.22, + 'max': 4442.74, + 'min': 683.12, }), }), 'blockName': 'Peak', - 'deliveryEnd': '2024-11-05T19:00:00Z', - 'deliveryStart': '2024-11-05T07:00:00Z', + 'deliveryEnd': '2025-10-01T18:00:00Z', + 'deliveryStart': '2025-10-01T06:00:00Z', }), dict({ 'averagePricePerArea': dict({ 'SE3': dict({ - 'average': 610.79, - 'max': 835.53, - 'min': 289.14, + 'average': 1054.61, + 'max': 1997.96, + 'min': 785.68, }), 'SE4': dict({ - 'average': 793.98, - 'max': 1112.57, - 'min': 349.21, + 'average': 1219.07, + 'max': 2312.16, + 'min': 912.22, }), }), 'blockName': 'Off-peak 2', - 'deliveryEnd': '2024-11-05T23:00:00Z', - 'deliveryStart': '2024-11-05T19:00:00Z', + 'deliveryEnd': '2025-10-01T22:00:00Z', + 'deliveryStart': '2025-10-01T18:00:00Z', }), ]), 'currency': 'SEK', @@ -358,482 +358,1634 @@ 'SE3', 'SE4', ]), - 'deliveryDateCET': '2024-11-05', - 'exchangeRate': 11.6402, + 'deliveryDateCET': '2025-10-01', + 'exchangeRate': 11.05186, 'market': 'DayAhead', 'multiAreaEntries': list([ dict({ - 'deliveryEnd': '2024-11-05T00:00:00Z', - 'deliveryStart': '2024-11-04T23:00:00Z', + 'deliveryEnd': '2025-09-30T22:15:00Z', + 'deliveryStart': '2025-09-30T22:00:00Z', 'entryPerArea': dict({ - 'SE3': 250.73, - 'SE4': 283.79, + 'SE3': 556.68, + 'SE4': 642.22, }), }), dict({ - 'deliveryEnd': '2024-11-05T01:00:00Z', - 'deliveryStart': '2024-11-05T00:00:00Z', + 'deliveryEnd': '2025-09-30T22:30:00Z', + 'deliveryStart': '2025-09-30T22:15:00Z', 'entryPerArea': dict({ - 'SE3': 76.36, - 'SE4': 81.36, + 'SE3': 519.88, + 'SE4': 600.12, }), }), dict({ - 'deliveryEnd': '2024-11-05T02:00:00Z', - 'deliveryStart': '2024-11-05T01:00:00Z', + 'deliveryEnd': '2025-09-30T22:45:00Z', + 'deliveryStart': '2025-09-30T22:30:00Z', 'entryPerArea': dict({ - 'SE3': 73.92, - 'SE4': 79.15, + 'SE3': 508.28, + 'SE4': 586.3, }), }), dict({ - 'deliveryEnd': '2024-11-05T03:00:00Z', - 'deliveryStart': '2024-11-05T02:00:00Z', + 'deliveryEnd': '2025-09-30T23:00:00Z', + 'deliveryStart': '2025-09-30T22:45:00Z', 'entryPerArea': dict({ - 'SE3': 61.69, - 'SE4': 65.19, + 'SE3': 509.93, + 'SE4': 589.62, }), }), dict({ - 'deliveryEnd': '2024-11-05T04:00:00Z', - 'deliveryStart': '2024-11-05T03:00:00Z', + 'deliveryEnd': '2025-09-30T23:15:00Z', + 'deliveryStart': '2025-09-30T23:00:00Z', 'entryPerArea': dict({ - 'SE3': 64.6, - 'SE4': 68.44, + 'SE3': 501.64, + 'SE4': 577.24, }), }), dict({ - 'deliveryEnd': '2024-11-05T05:00:00Z', - 'deliveryStart': '2024-11-05T04:00:00Z', + 'deliveryEnd': '2025-09-30T23:30:00Z', + 'deliveryStart': '2025-09-30T23:15:00Z', 'entryPerArea': dict({ - 'SE3': 453.27, - 'SE4': 516.71, + 'SE3': 509.05, + 'SE4': 585.42, }), }), dict({ - 'deliveryEnd': '2024-11-05T06:00:00Z', - 'deliveryStart': '2024-11-05T05:00:00Z', + 'deliveryEnd': '2025-09-30T23:45:00Z', + 'deliveryStart': '2025-09-30T23:30:00Z', 'entryPerArea': dict({ - 'SE3': 996.28, - 'SE4': 1240.85, + 'SE3': 491.03, + 'SE4': 567.18, }), }), dict({ - 'deliveryEnd': '2024-11-05T07:00:00Z', - 'deliveryStart': '2024-11-05T06:00:00Z', + 'deliveryEnd': '2025-10-01T00:00:00Z', + 'deliveryStart': '2025-09-30T23:45:00Z', 'entryPerArea': dict({ - 'SE3': 1406.14, - 'SE4': 1648.25, + 'SE3': 442.07, + 'SE4': 517.45, }), }), dict({ - 'deliveryEnd': '2024-11-05T08:00:00Z', - 'deliveryStart': '2024-11-05T07:00:00Z', + 'deliveryEnd': '2025-10-01T00:15:00Z', + 'deliveryStart': '2025-10-01T00:00:00Z', 'entryPerArea': dict({ - 'SE3': 1346.54, - 'SE4': 1570.5, + 'SE3': 504.08, + 'SE4': 580.55, }), }), dict({ - 'deliveryEnd': '2024-11-05T09:00:00Z', - 'deliveryStart': '2024-11-05T08:00:00Z', + 'deliveryEnd': '2025-10-01T00:30:00Z', + 'deliveryStart': '2025-10-01T00:15:00Z', 'entryPerArea': dict({ - 'SE3': 1150.28, - 'SE4': 1345.37, + 'SE3': 504.85, + 'SE4': 581.55, }), }), dict({ - 'deliveryEnd': '2024-11-05T10:00:00Z', - 'deliveryStart': '2024-11-05T09:00:00Z', + 'deliveryEnd': '2025-10-01T00:45:00Z', + 'deliveryStart': '2025-10-01T00:30:00Z', 'entryPerArea': dict({ - 'SE3': 1031.32, - 'SE4': 1206.51, + 'SE3': 504.3, + 'SE4': 580.78, }), }), dict({ - 'deliveryEnd': '2024-11-05T11:00:00Z', - 'deliveryStart': '2024-11-05T10:00:00Z', + 'deliveryEnd': '2025-10-01T01:00:00Z', + 'deliveryStart': '2025-10-01T00:45:00Z', 'entryPerArea': dict({ - 'SE3': 927.37, - 'SE4': 1085.8, + 'SE3': 506.29, + 'SE4': 583.1, }), }), dict({ - 'deliveryEnd': '2024-11-05T12:00:00Z', - 'deliveryStart': '2024-11-05T11:00:00Z', + 'deliveryEnd': '2025-10-01T01:15:00Z', + 'deliveryStart': '2025-10-01T01:00:00Z', 'entryPerArea': dict({ - 'SE3': 925.05, - 'SE4': 1081.72, + 'SE3': 442.07, + 'SE4': 515.46, }), }), dict({ - 'deliveryEnd': '2024-11-05T13:00:00Z', - 'deliveryStart': '2024-11-05T12:00:00Z', + 'deliveryEnd': '2025-10-01T01:30:00Z', + 'deliveryStart': '2025-10-01T01:15:00Z', 'entryPerArea': dict({ - 'SE3': 949.49, - 'SE4': 1130.38, + 'SE3': 441.96, + 'SE4': 517.23, }), }), dict({ - 'deliveryEnd': '2024-11-05T14:00:00Z', - 'deliveryStart': '2024-11-05T13:00:00Z', + 'deliveryEnd': '2025-10-01T01:45:00Z', + 'deliveryStart': '2025-10-01T01:30:00Z', 'entryPerArea': dict({ - 'SE3': 1042.03, - 'SE4': 1256.91, + 'SE3': 442.07, + 'SE4': 516.23, }), }), dict({ - 'deliveryEnd': '2024-11-05T15:00:00Z', - 'deliveryStart': '2024-11-05T14:00:00Z', + 'deliveryEnd': '2025-10-01T02:00:00Z', + 'deliveryStart': '2025-10-01T01:45:00Z', 'entryPerArea': dict({ - 'SE3': 1258.89, - 'SE4': 1765.82, + 'SE3': 442.07, + 'SE4': 516.23, }), }), dict({ - 'deliveryEnd': '2024-11-05T16:00:00Z', - 'deliveryStart': '2024-11-05T15:00:00Z', + 'deliveryEnd': '2025-10-01T02:15:00Z', + 'deliveryStart': '2025-10-01T02:00:00Z', 'entryPerArea': dict({ - 'SE3': 1816.45, - 'SE4': 2522.55, + 'SE3': 441.96, + 'SE4': 517.34, }), }), dict({ - 'deliveryEnd': '2024-11-05T17:00:00Z', - 'deliveryStart': '2024-11-05T16:00:00Z', + 'deliveryEnd': '2025-10-01T02:30:00Z', + 'deliveryStart': '2025-10-01T02:15:00Z', 'entryPerArea': dict({ - 'SE3': 2512.65, - 'SE4': 3533.03, + 'SE3': 483.3, + 'SE4': 559.11, }), }), dict({ - 'deliveryEnd': '2024-11-05T18:00:00Z', - 'deliveryStart': '2024-11-05T17:00:00Z', + 'deliveryEnd': '2025-10-01T02:45:00Z', + 'deliveryStart': '2025-10-01T02:30:00Z', 'entryPerArea': dict({ - 'SE3': 1819.83, - 'SE4': 2524.06, + 'SE3': 484.29, + 'SE4': 559.0, }), }), dict({ - 'deliveryEnd': '2024-11-05T19:00:00Z', - 'deliveryStart': '2024-11-05T18:00:00Z', + 'deliveryEnd': '2025-10-01T03:00:00Z', + 'deliveryStart': '2025-10-01T02:45:00Z', 'entryPerArea': dict({ - 'SE3': 1011.77, + 'SE3': 574.7, + 'SE4': 659.35, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T03:15:00Z', + 'deliveryStart': '2025-10-01T03:00:00Z', + 'entryPerArea': dict({ + 'SE3': 543.31, + 'SE4': 631.95, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T03:30:00Z', + 'deliveryStart': '2025-10-01T03:15:00Z', + 'entryPerArea': dict({ + 'SE3': 578.01, + 'SE4': 671.18, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T03:45:00Z', + 'deliveryStart': '2025-10-01T03:30:00Z', + 'entryPerArea': dict({ + 'SE3': 774.96, + 'SE4': 893.1, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T04:00:00Z', + 'deliveryStart': '2025-10-01T03:45:00Z', + 'entryPerArea': dict({ + 'SE3': 787.0, + 'SE4': 909.79, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T04:15:00Z', + 'deliveryStart': '2025-10-01T04:00:00Z', + 'entryPerArea': dict({ + 'SE3': 902.38, + 'SE4': 1041.86, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T04:30:00Z', + 'deliveryStart': '2025-10-01T04:15:00Z', + 'entryPerArea': dict({ + 'SE3': 1079.32, + 'SE4': 1254.17, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T04:45:00Z', + 'deliveryStart': '2025-10-01T04:30:00Z', + 'entryPerArea': dict({ + 'SE3': 1222.67, + 'SE4': 1421.93, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T05:00:00Z', + 'deliveryStart': '2025-10-01T04:45:00Z', + 'entryPerArea': dict({ + 'SE3': 1394.63, + 'SE4': 1623.08, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T05:15:00Z', + 'deliveryStart': '2025-10-01T05:00:00Z', + 'entryPerArea': dict({ + 'SE3': 1529.36, + 'SE4': 1787.86, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T05:30:00Z', + 'deliveryStart': '2025-10-01T05:15:00Z', + 'entryPerArea': dict({ + 'SE3': 1724.53, + 'SE4': 2015.75, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T05:45:00Z', + 'deliveryStart': '2025-10-01T05:30:00Z', + 'entryPerArea': dict({ + 'SE3': 1809.96, + 'SE4': 2029.34, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T06:00:00Z', + 'deliveryStart': '2025-10-01T05:45:00Z', + 'entryPerArea': dict({ + 'SE3': 1713.04, + 'SE4': 1920.15, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T06:15:00Z', + 'deliveryStart': '2025-10-01T06:00:00Z', + 'entryPerArea': dict({ + 'SE3': 1925.9, + 'SE4': 2162.63, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T06:30:00Z', + 'deliveryStart': '2025-10-01T06:15:00Z', + 'entryPerArea': dict({ + 'SE3': 1440.06, + 'SE4': 1614.01, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T06:45:00Z', + 'deliveryStart': '2025-10-01T06:30:00Z', + 'entryPerArea': dict({ + 'SE3': 1183.32, + 'SE4': 1319.37, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T07:00:00Z', + 'deliveryStart': '2025-10-01T06:45:00Z', + 'entryPerArea': dict({ + 'SE3': 962.95, + 'SE4': 1068.71, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T07:15:00Z', + 'deliveryStart': '2025-10-01T07:00:00Z', + 'entryPerArea': dict({ + 'SE3': 1402.04, + 'SE4': 1569.92, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T07:30:00Z', + 'deliveryStart': '2025-10-01T07:15:00Z', + 'entryPerArea': dict({ + 'SE3': 1060.65, + 'SE4': 1178.46, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T07:45:00Z', + 'deliveryStart': '2025-10-01T07:30:00Z', + 'entryPerArea': dict({ + 'SE3': 949.13, + 'SE4': 1050.59, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T08:00:00Z', + 'deliveryStart': '2025-10-01T07:45:00Z', + 'entryPerArea': dict({ + 'SE3': 841.82, + 'SE4': 938.3, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T08:15:00Z', + 'deliveryStart': '2025-10-01T08:00:00Z', + 'entryPerArea': dict({ + 'SE3': 1037.44, + 'SE4': 1141.44, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T08:30:00Z', + 'deliveryStart': '2025-10-01T08:15:00Z', + 'entryPerArea': dict({ + 'SE3': 950.13, + 'SE4': 1041.64, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T08:45:00Z', + 'deliveryStart': '2025-10-01T08:30:00Z', + 'entryPerArea': dict({ + 'SE3': 826.13, + 'SE4': 905.04, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T09:00:00Z', + 'deliveryStart': '2025-10-01T08:45:00Z', + 'entryPerArea': dict({ + 'SE3': 684.55, + 'SE4': 754.62, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T09:15:00Z', + 'deliveryStart': '2025-10-01T09:00:00Z', + 'entryPerArea': dict({ + 'SE3': 861.6, + 'SE4': 936.09, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T09:30:00Z', + 'deliveryStart': '2025-10-01T09:15:00Z', + 'entryPerArea': dict({ + 'SE3': 722.79, + 'SE4': 799.6, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T09:45:00Z', + 'deliveryStart': '2025-10-01T09:30:00Z', + 'entryPerArea': dict({ + 'SE3': 640.57, + 'SE4': 718.59, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T10:00:00Z', + 'deliveryStart': '2025-10-01T09:45:00Z', + 'entryPerArea': dict({ + 'SE3': 607.74, + 'SE4': 683.12, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T10:15:00Z', + 'deliveryStart': '2025-10-01T10:00:00Z', + 'entryPerArea': dict({ + 'SE3': 674.05, + 'SE4': 752.41, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T10:30:00Z', + 'deliveryStart': '2025-10-01T10:15:00Z', + 'entryPerArea': dict({ + 'SE3': 638.58, + 'SE4': 717.49, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T10:45:00Z', + 'deliveryStart': '2025-10-01T10:30:00Z', + 'entryPerArea': dict({ + 'SE3': 638.47, + 'SE4': 719.81, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T11:00:00Z', + 'deliveryStart': '2025-10-01T10:45:00Z', + 'entryPerArea': dict({ + 'SE3': 634.82, + 'SE4': 717.16, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T11:15:00Z', + 'deliveryStart': '2025-10-01T11:00:00Z', + 'entryPerArea': dict({ + 'SE3': 637.36, + 'SE4': 721.58, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T11:30:00Z', + 'deliveryStart': '2025-10-01T11:15:00Z', + 'entryPerArea': dict({ + 'SE3': 660.68, + 'SE4': 746.33, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T11:45:00Z', + 'deliveryStart': '2025-10-01T11:30:00Z', + 'entryPerArea': dict({ + 'SE3': 679.14, + 'SE4': 766.45, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T12:00:00Z', + 'deliveryStart': '2025-10-01T11:45:00Z', + 'entryPerArea': dict({ + 'SE3': 694.61, + 'SE4': 782.91, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T12:15:00Z', + 'deliveryStart': '2025-10-01T12:00:00Z', + 'entryPerArea': dict({ + 'SE3': 622.33, + 'SE4': 708.87, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T12:30:00Z', + 'deliveryStart': '2025-10-01T12:15:00Z', + 'entryPerArea': dict({ + 'SE3': 685.44, + 'SE4': 775.84, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T12:45:00Z', + 'deliveryStart': '2025-10-01T12:30:00Z', + 'entryPerArea': dict({ + 'SE3': 732.85, + 'SE4': 826.57, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T13:00:00Z', + 'deliveryStart': '2025-10-01T12:45:00Z', + 'entryPerArea': dict({ + 'SE3': 801.92, + 'SE4': 901.28, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T13:15:00Z', + 'deliveryStart': '2025-10-01T13:00:00Z', + 'entryPerArea': dict({ + 'SE3': 629.4, + 'SE4': 717.93, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T13:30:00Z', + 'deliveryStart': '2025-10-01T13:15:00Z', + 'entryPerArea': dict({ + 'SE3': 729.53, + 'SE4': 825.46, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T13:45:00Z', + 'deliveryStart': '2025-10-01T13:30:00Z', + 'entryPerArea': dict({ + 'SE3': 884.81, + 'SE4': 983.95, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T14:00:00Z', + 'deliveryStart': '2025-10-01T13:45:00Z', + 'entryPerArea': dict({ + 'SE3': 984.94, + 'SE4': 1089.71, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T14:15:00Z', + 'deliveryStart': '2025-10-01T14:00:00Z', + 'entryPerArea': dict({ + 'SE3': 615.26, + 'SE4': 703.12, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T14:30:00Z', + 'deliveryStart': '2025-10-01T14:15:00Z', + 'entryPerArea': dict({ + 'SE3': 902.94, + 'SE4': 1002.74, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T14:45:00Z', + 'deliveryStart': '2025-10-01T14:30:00Z', + 'entryPerArea': dict({ + 'SE3': 1043.85, + 'SE4': 1158.35, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T15:00:00Z', + 'deliveryStart': '2025-10-01T14:45:00Z', + 'entryPerArea': dict({ + 'SE3': 1075.12, + 'SE4': 1194.15, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T15:15:00Z', + 'deliveryStart': '2025-10-01T15:00:00Z', + 'entryPerArea': dict({ + 'SE3': 980.52, + 'SE4': 1089.38, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T15:30:00Z', + 'deliveryStart': '2025-10-01T15:15:00Z', + 'entryPerArea': dict({ + 'SE3': 1162.66, + 'SE4': 1300.14, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T15:45:00Z', + 'deliveryStart': '2025-10-01T15:30:00Z', + 'entryPerArea': dict({ + 'SE3': 1453.87, + 'SE4': 1628.6, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T16:00:00Z', + 'deliveryStart': '2025-10-01T15:45:00Z', + 'entryPerArea': dict({ + 'SE3': 1955.96, + 'SE4': 2193.35, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T16:15:00Z', + 'deliveryStart': '2025-10-01T16:00:00Z', + 'entryPerArea': dict({ + 'SE3': 1423.48, + 'SE4': 1623.74, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T16:30:00Z', + 'deliveryStart': '2025-10-01T16:15:00Z', + 'entryPerArea': dict({ + 'SE3': 1900.04, + 'SE4': 2199.98, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T16:45:00Z', + 'deliveryStart': '2025-10-01T16:30:00Z', + 'entryPerArea': dict({ + 'SE3': 2611.11, + 'SE4': 3031.08, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T17:00:00Z', + 'deliveryStart': '2025-10-01T16:45:00Z', + 'entryPerArea': dict({ + 'SE3': 3467.41, + 'SE4': 4029.51, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T17:15:00Z', + 'deliveryStart': '2025-10-01T17:00:00Z', + 'entryPerArea': dict({ + 'SE3': 3828.03, + 'SE4': 4442.74, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T17:30:00Z', + 'deliveryStart': '2025-10-01T17:15:00Z', + 'entryPerArea': dict({ + 'SE3': 3429.83, + 'SE4': 3982.21, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T17:45:00Z', + 'deliveryStart': '2025-10-01T17:30:00Z', + 'entryPerArea': dict({ + 'SE3': 2934.38, + 'SE4': 3405.74, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T18:00:00Z', + 'deliveryStart': '2025-10-01T17:45:00Z', + 'entryPerArea': dict({ + 'SE3': 2308.07, + 'SE4': 2677.64, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T18:15:00Z', + 'deliveryStart': '2025-10-01T18:00:00Z', + 'entryPerArea': dict({ + 'SE3': 1997.96, 'SE4': 0.0, }), }), dict({ - 'deliveryEnd': '2024-11-05T20:00:00Z', - 'deliveryStart': '2024-11-05T19:00:00Z', + 'deliveryEnd': '2025-10-01T18:30:00Z', + 'deliveryStart': '2025-10-01T18:15:00Z', + 'entryPerArea': dict({ + 'SE3': 1424.03, + 'SE4': 1646.17, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T18:45:00Z', + 'deliveryStart': '2025-10-01T18:30:00Z', + 'entryPerArea': dict({ + 'SE3': 1216.81, + 'SE4': 1388.11, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T19:00:00Z', + 'deliveryStart': '2025-10-01T18:45:00Z', + 'entryPerArea': dict({ + 'SE3': 1070.15, + 'SE4': 1204.65, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T19:15:00Z', + 'deliveryStart': '2025-10-01T19:00:00Z', + 'entryPerArea': dict({ + 'SE3': 1218.14, + 'SE4': 1405.02, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T19:30:00Z', + 'deliveryStart': '2025-10-01T19:15:00Z', + 'entryPerArea': dict({ + 'SE3': 1135.8, + 'SE4': 1309.42, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T19:45:00Z', + 'deliveryStart': '2025-10-01T19:30:00Z', + 'entryPerArea': dict({ + 'SE3': 959.96, + 'SE4': 1115.69, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T20:00:00Z', + 'deliveryStart': '2025-10-01T19:45:00Z', + 'entryPerArea': dict({ + 'SE3': 913.66, + 'SE4': 1064.52, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T20:15:00Z', + 'deliveryStart': '2025-10-01T20:00:00Z', + 'entryPerArea': dict({ + 'SE3': 1001.63, + 'SE4': 1161.22, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T20:30:00Z', + 'deliveryStart': '2025-10-01T20:15:00Z', + 'entryPerArea': dict({ + 'SE3': 933.0, + 'SE4': 1083.08, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T20:45:00Z', + 'deliveryStart': '2025-10-01T20:30:00Z', + 'entryPerArea': dict({ + 'SE3': 874.53, + 'SE4': 1017.66, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T21:00:00Z', + 'deliveryStart': '2025-10-01T20:45:00Z', + 'entryPerArea': dict({ + 'SE3': 821.71, + 'SE4': 955.32, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T21:15:00Z', + 'deliveryStart': '2025-10-01T21:00:00Z', + 'entryPerArea': dict({ + 'SE3': 860.5, + 'SE4': 997.32, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T21:30:00Z', + 'deliveryStart': '2025-10-01T21:15:00Z', + 'entryPerArea': dict({ + 'SE3': 840.16, + 'SE4': 977.87, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T21:45:00Z', + 'deliveryStart': '2025-10-01T21:30:00Z', + 'entryPerArea': dict({ + 'SE3': 820.05, + 'SE4': 954.66, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T22:00:00Z', + 'deliveryStart': '2025-10-01T21:45:00Z', + 'entryPerArea': dict({ + 'SE3': 785.68, + 'SE4': 912.22, + }), + }), + ]), + 'updatedAt': '2025-09-30T12:08:16.4448023Z', + 'version': 3, + }), + '2025-10-02': dict({ + 'areaAverages': list([ + dict({ + 'areaCode': 'SE3', + 'price': 1129.65, + }), + dict({ + 'areaCode': 'SE4', + 'price': 1119.28, + }), + ]), + 'areaStates': list([ + dict({ + 'areas': list([ + 'SE3', + 'SE4', + ]), + 'state': 'Final', + }), + ]), + 'blockPriceAggregates': list([ + dict({ + 'averagePricePerArea': dict({ + 'SE3': dict({ + 'average': 961.76, + 'max': 1831.25, + 'min': 673.05, + }), + 'SE4': dict({ + 'average': 1102.25, + 'max': 2182.34, + 'min': 758.78, + }), + }), + 'blockName': 'Off-peak 1', + 'deliveryEnd': '2025-10-02T06:00:00Z', + 'deliveryStart': '2025-10-01T22:00:00Z', + }), + dict({ + 'averagePricePerArea': dict({ + 'SE3': dict({ + 'average': 1191.34, + 'max': 3288.35, + 'min': 563.38, + }), + 'SE4': dict({ + 'average': 1155.07, + 'max': 2617.73, + 'min': 635.76, + }), + }), + 'blockName': 'Peak', + 'deliveryEnd': '2025-10-02T18:00:00Z', + 'deliveryStart': '2025-10-02T06:00:00Z', + }), + dict({ + 'averagePricePerArea': dict({ + 'SE3': dict({ + 'average': 1280.38, + 'max': 1935.08, + 'min': 646.9, + }), + 'SE4': dict({ + 'average': 1045.99, + 'max': 1532.57, + 'min': 591.84, + }), + }), + 'blockName': 'Off-peak 2', + 'deliveryEnd': '2025-10-02T22:00:00Z', + 'deliveryStart': '2025-10-02T18:00:00Z', + }), + ]), + 'currency': 'SEK', + 'deliveryAreas': list([ + 'SE3', + 'SE4', + ]), + 'deliveryDateCET': '2025-10-02', + 'exchangeRate': 11.03362, + 'market': 'DayAhead', + 'multiAreaEntries': list([ + dict({ + 'deliveryEnd': '2025-10-01T22:15:00Z', + 'deliveryStart': '2025-10-01T22:00:00Z', + 'entryPerArea': dict({ + 'SE3': 933.22, + 'SE4': 1062.32, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T22:30:00Z', + 'deliveryStart': '2025-10-01T22:15:00Z', + 'entryPerArea': dict({ + 'SE3': 854.22, + 'SE4': 971.95, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T22:45:00Z', + 'deliveryStart': '2025-10-01T22:30:00Z', + 'entryPerArea': dict({ + 'SE3': 809.54, + 'SE4': 919.1, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T23:00:00Z', + 'deliveryStart': '2025-10-01T22:45:00Z', + 'entryPerArea': dict({ + 'SE3': 811.74, + 'SE4': 922.63, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T23:15:00Z', + 'deliveryStart': '2025-10-01T23:00:00Z', + 'entryPerArea': dict({ + 'SE3': 835.13, + 'SE4': 950.99, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T23:30:00Z', + 'deliveryStart': '2025-10-01T23:15:00Z', + 'entryPerArea': dict({ + 'SE3': 828.85, + 'SE4': 942.82, + }), + }), + dict({ + 'deliveryEnd': '2025-10-01T23:45:00Z', + 'deliveryStart': '2025-10-01T23:30:00Z', + 'entryPerArea': dict({ + 'SE3': 796.63, + 'SE4': 903.54, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T00:00:00Z', + 'deliveryStart': '2025-10-01T23:45:00Z', + 'entryPerArea': dict({ + 'SE3': 706.7, + 'SE4': 799.61, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T00:15:00Z', + 'deliveryStart': '2025-10-02T00:00:00Z', + 'entryPerArea': dict({ + 'SE3': 695.23, + 'SE4': 786.81, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T00:30:00Z', + 'deliveryStart': '2025-10-02T00:15:00Z', + 'entryPerArea': dict({ + 'SE3': 695.12, + 'SE4': 783.83, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T00:45:00Z', + 'deliveryStart': '2025-10-02T00:30:00Z', + 'entryPerArea': dict({ + 'SE3': 684.86, + 'SE4': 771.8, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T01:00:00Z', + 'deliveryStart': '2025-10-02T00:45:00Z', 'entryPerArea': dict({ - 'SE3': 835.53, - 'SE4': 1112.57, + 'SE3': 673.05, + 'SE4': 758.78, }), }), dict({ - 'deliveryEnd': '2024-11-05T21:00:00Z', - 'deliveryStart': '2024-11-05T20:00:00Z', + 'deliveryEnd': '2025-10-02T01:15:00Z', + 'deliveryStart': '2025-10-02T01:00:00Z', 'entryPerArea': dict({ - 'SE3': 796.19, - 'SE4': 1051.69, + 'SE3': 695.01, + 'SE4': 791.22, }), }), dict({ - 'deliveryEnd': '2024-11-05T22:00:00Z', - 'deliveryStart': '2024-11-05T21:00:00Z', + 'deliveryEnd': '2025-10-02T01:30:00Z', + 'deliveryStart': '2025-10-02T01:15:00Z', 'entryPerArea': dict({ - 'SE3': 522.3, - 'SE4': 662.44, + 'SE3': 693.35, + 'SE4': 789.12, }), }), dict({ - 'deliveryEnd': '2024-11-05T23:00:00Z', - 'deliveryStart': '2024-11-05T22:00:00Z', + 'deliveryEnd': '2025-10-02T01:45:00Z', + 'deliveryStart': '2025-10-02T01:30:00Z', 'entryPerArea': dict({ - 'SE3': 289.14, - 'SE4': 349.21, + 'SE3': 702.4, + 'SE4': 799.61, }), }), - ]), - 'updatedAt': '2024-11-04T12:15:03.9456464Z', - 'version': 3, - }), - '2024-11-06': dict({ - 'areaAverages': list([ dict({ - 'areaCode': 'SE3', - 'price': 900.65, + 'deliveryEnd': '2025-10-02T02:00:00Z', + 'deliveryStart': '2025-10-02T01:45:00Z', + 'entryPerArea': dict({ + 'SE3': 749.4, + 'SE4': 853.45, + }), }), dict({ - 'areaCode': 'SE4', - 'price': 1581.19, + 'deliveryEnd': '2025-10-02T02:15:00Z', + 'deliveryStart': '2025-10-02T02:00:00Z', + 'entryPerArea': dict({ + 'SE3': 796.85, + 'SE4': 907.4, + }), }), - ]), - 'areaStates': list([ dict({ - 'areas': list([ - 'SE3', - 'SE4', - ]), - 'state': 'Final', + 'deliveryEnd': '2025-10-02T02:30:00Z', + 'deliveryStart': '2025-10-02T02:15:00Z', + 'entryPerArea': dict({ + 'SE3': 811.19, + 'SE4': 924.07, + }), }), - ]), - 'blockPriceAggregates': list([ dict({ - 'averagePricePerArea': dict({ - 'SE3': dict({ - 'average': 422.51, - 'max': 1820.5, - 'min': 74.06, - }), - 'SE4': dict({ - 'average': 706.61, - 'max': 2449.96, - 'min': 157.34, - }), + 'deliveryEnd': '2025-10-02T02:45:00Z', + 'deliveryStart': '2025-10-02T02:30:00Z', + 'entryPerArea': dict({ + 'SE3': 803.8, + 'SE4': 916.23, }), - 'blockName': 'Off-peak 1', - 'deliveryEnd': '2024-11-06T07:00:00Z', - 'deliveryStart': '2024-11-05T23:00:00Z', }), dict({ - 'averagePricePerArea': dict({ - 'SE3': dict({ - 'average': 1346.82, - 'max': 2366.57, - 'min': 903.31, - }), - 'SE4': dict({ - 'average': 2306.88, - 'max': 5511.77, - 'min': 1362.84, - }), + 'deliveryEnd': '2025-10-02T03:00:00Z', + 'deliveryStart': '2025-10-02T02:45:00Z', + 'entryPerArea': dict({ + 'SE3': 839.11, + 'SE4': 953.3, }), - 'blockName': 'Peak', - 'deliveryEnd': '2024-11-06T19:00:00Z', - 'deliveryStart': '2024-11-06T07:00:00Z', }), dict({ - 'averagePricePerArea': dict({ - 'SE3': dict({ - 'average': 518.43, - 'max': 716.82, - 'min': 250.64, - }), - 'SE4': dict({ - 'average': 1153.25, - 'max': 1624.33, - 'min': 539.42, - }), + 'deliveryEnd': '2025-10-02T03:15:00Z', + 'deliveryStart': '2025-10-02T03:00:00Z', + 'entryPerArea': dict({ + 'SE3': 825.2, + 'SE4': 943.15, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T03:30:00Z', + 'deliveryStart': '2025-10-02T03:15:00Z', + 'entryPerArea': dict({ + 'SE3': 838.78, + 'SE4': 958.93, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T03:45:00Z', + 'deliveryStart': '2025-10-02T03:30:00Z', + 'entryPerArea': dict({ + 'SE3': 906.19, + 'SE4': 1030.65, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T04:00:00Z', + 'deliveryStart': '2025-10-02T03:45:00Z', + 'entryPerArea': dict({ + 'SE3': 1057.79, + 'SE4': 1195.82, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T04:15:00Z', + 'deliveryStart': '2025-10-02T04:00:00Z', + 'entryPerArea': dict({ + 'SE3': 912.15, + 'SE4': 1040.8, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T04:30:00Z', + 'deliveryStart': '2025-10-02T04:15:00Z', + 'entryPerArea': dict({ + 'SE3': 1131.28, + 'SE4': 1283.43, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T04:45:00Z', + 'deliveryStart': '2025-10-02T04:30:00Z', + 'entryPerArea': dict({ + 'SE3': 1294.68, + 'SE4': 1468.91, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T05:00:00Z', + 'deliveryStart': '2025-10-02T04:45:00Z', + 'entryPerArea': dict({ + 'SE3': 1625.8, + 'SE4': 1845.81, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T05:15:00Z', + 'deliveryStart': '2025-10-02T05:00:00Z', + 'entryPerArea': dict({ + 'SE3': 1649.31, + 'SE4': 1946.77, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T05:30:00Z', + 'deliveryStart': '2025-10-02T05:15:00Z', + 'entryPerArea': dict({ + 'SE3': 1831.25, + 'SE4': 2182.34, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T05:45:00Z', + 'deliveryStart': '2025-10-02T05:30:00Z', + 'entryPerArea': dict({ + 'SE3': 1743.31, + 'SE4': 2063.4, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T06:00:00Z', + 'deliveryStart': '2025-10-02T05:45:00Z', + 'entryPerArea': dict({ + 'SE3': 1545.04, + 'SE4': 1803.33, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T06:15:00Z', + 'deliveryStart': '2025-10-02T06:00:00Z', + 'entryPerArea': dict({ + 'SE3': 1783.47, + 'SE4': 2080.72, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T06:30:00Z', + 'deliveryStart': '2025-10-02T06:15:00Z', + 'entryPerArea': dict({ + 'SE3': 1470.89, + 'SE4': 1675.23, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T06:45:00Z', + 'deliveryStart': '2025-10-02T06:30:00Z', + 'entryPerArea': dict({ + 'SE3': 1191.08, + 'SE4': 1288.06, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T07:00:00Z', + 'deliveryStart': '2025-10-02T06:45:00Z', + 'entryPerArea': dict({ + 'SE3': 1012.22, + 'SE4': 1112.19, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T07:15:00Z', + 'deliveryStart': '2025-10-02T07:00:00Z', + 'entryPerArea': dict({ + 'SE3': 1278.69, + 'SE4': 1375.67, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T07:30:00Z', + 'deliveryStart': '2025-10-02T07:15:00Z', + 'entryPerArea': dict({ + 'SE3': 1170.12, + 'SE4': 1258.61, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T07:45:00Z', + 'deliveryStart': '2025-10-02T07:30:00Z', + 'entryPerArea': dict({ + 'SE3': 937.09, + 'SE4': 1021.93, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T08:00:00Z', + 'deliveryStart': '2025-10-02T07:45:00Z', + 'entryPerArea': dict({ + 'SE3': 815.94, + 'SE4': 900.67, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T08:15:00Z', + 'deliveryStart': '2025-10-02T08:00:00Z', + 'entryPerArea': dict({ + 'SE3': 1044.66, + 'SE4': 1135.25, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T08:30:00Z', + 'deliveryStart': '2025-10-02T08:15:00Z', + 'entryPerArea': dict({ + 'SE3': 1020.61, + 'SE4': 1112.74, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T08:45:00Z', + 'deliveryStart': '2025-10-02T08:30:00Z', + 'entryPerArea': dict({ + 'SE3': 866.14, + 'SE4': 953.53, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T09:00:00Z', + 'deliveryStart': '2025-10-02T08:45:00Z', + 'entryPerArea': dict({ + 'SE3': 774.34, + 'SE4': 860.18, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T09:15:00Z', + 'deliveryStart': '2025-10-02T09:00:00Z', + 'entryPerArea': dict({ + 'SE3': 928.26, + 'SE4': 1020.39, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T09:30:00Z', + 'deliveryStart': '2025-10-02T09:15:00Z', + 'entryPerArea': dict({ + 'SE3': 834.47, + 'SE4': 922.96, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T09:45:00Z', + 'deliveryStart': '2025-10-02T09:30:00Z', + 'entryPerArea': dict({ + 'SE3': 712.33, + 'SE4': 794.64, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T10:00:00Z', + 'deliveryStart': '2025-10-02T09:45:00Z', + 'entryPerArea': dict({ + 'SE3': 646.46, + 'SE4': 725.9, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T10:15:00Z', + 'deliveryStart': '2025-10-02T10:00:00Z', + 'entryPerArea': dict({ + 'SE3': 692.91, + 'SE4': 773.9, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T10:30:00Z', + 'deliveryStart': '2025-10-02T10:15:00Z', + 'entryPerArea': dict({ + 'SE3': 627.59, + 'SE4': 706.59, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T10:45:00Z', + 'deliveryStart': '2025-10-02T10:30:00Z', + 'entryPerArea': dict({ + 'SE3': 630.02, + 'SE4': 708.14, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T11:00:00Z', + 'deliveryStart': '2025-10-02T10:45:00Z', + 'entryPerArea': dict({ + 'SE3': 625.94, + 'SE4': 703.61, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T11:15:00Z', + 'deliveryStart': '2025-10-02T11:00:00Z', + 'entryPerArea': dict({ + 'SE3': 563.38, + 'SE4': 635.76, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T11:30:00Z', + 'deliveryStart': '2025-10-02T11:15:00Z', + 'entryPerArea': dict({ + 'SE3': 588.42, + 'SE4': 663.12, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T11:45:00Z', + 'deliveryStart': '2025-10-02T11:30:00Z', + 'entryPerArea': dict({ + 'SE3': 597.03, + 'SE4': 672.83, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T12:00:00Z', + 'deliveryStart': '2025-10-02T11:45:00Z', + 'entryPerArea': dict({ + 'SE3': 608.61, + 'SE4': 685.19, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T12:15:00Z', + 'deliveryStart': '2025-10-02T12:00:00Z', + 'entryPerArea': dict({ + 'SE3': 599.24, + 'SE4': 676.91, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T12:30:00Z', + 'deliveryStart': '2025-10-02T12:15:00Z', + 'entryPerArea': dict({ + 'SE3': 649.77, + 'SE4': 729.54, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T12:45:00Z', + 'deliveryStart': '2025-10-02T12:30:00Z', + 'entryPerArea': dict({ + 'SE3': 728.22, + 'SE4': 821.23, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T13:00:00Z', + 'deliveryStart': '2025-10-02T12:45:00Z', + 'entryPerArea': dict({ + 'SE3': 803.91, + 'SE4': 909.06, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T13:15:00Z', + 'deliveryStart': '2025-10-02T13:00:00Z', + 'entryPerArea': dict({ + 'SE3': 594.38, + 'SE4': 679.23, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T13:30:00Z', + 'deliveryStart': '2025-10-02T13:15:00Z', + 'entryPerArea': dict({ + 'SE3': 738.48, + 'SE4': 825.09, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T13:45:00Z', + 'deliveryStart': '2025-10-02T13:30:00Z', + 'entryPerArea': dict({ + 'SE3': 873.53, + 'SE4': 962.02, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T14:00:00Z', + 'deliveryStart': '2025-10-02T13:45:00Z', + 'entryPerArea': dict({ + 'SE3': 994.57, + 'SE4': 1083.5, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T14:15:00Z', + 'deliveryStart': '2025-10-02T14:00:00Z', + 'entryPerArea': dict({ + 'SE3': 733.52, + 'SE4': 813.18, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T14:30:00Z', + 'deliveryStart': '2025-10-02T14:15:00Z', + 'entryPerArea': dict({ + 'SE3': 864.59, + 'SE4': 944.04, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T14:45:00Z', + 'deliveryStart': '2025-10-02T14:30:00Z', + 'entryPerArea': dict({ + 'SE3': 1032.08, + 'SE4': 1113.18, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T15:00:00Z', + 'deliveryStart': '2025-10-02T14:45:00Z', + 'entryPerArea': dict({ + 'SE3': 1153.01, + 'SE4': 1241.61, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T15:15:00Z', + 'deliveryStart': '2025-10-02T15:00:00Z', + 'entryPerArea': dict({ + 'SE3': 1271.18, + 'SE4': 1017.41, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T15:30:00Z', + 'deliveryStart': '2025-10-02T15:15:00Z', + 'entryPerArea': dict({ + 'SE3': 1375.23, + 'SE4': 1093.1, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T15:45:00Z', + 'deliveryStart': '2025-10-02T15:30:00Z', + 'entryPerArea': dict({ + 'SE3': 1544.82, + 'SE4': 1244.81, + }), + }), + dict({ + 'deliveryEnd': '2025-10-02T16:00:00Z', + 'deliveryStart': '2025-10-02T15:45:00Z', + 'entryPerArea': dict({ + 'SE3': 2412.17, + 'SE4': 1960.12, }), - 'blockName': 'Off-peak 2', - 'deliveryEnd': '2024-11-06T23:00:00Z', - 'deliveryStart': '2024-11-06T19:00:00Z', }), - ]), - 'currency': 'SEK', - 'deliveryAreas': list([ - 'SE3', - 'SE4', - ]), - 'deliveryDateCET': '2024-11-06', - 'exchangeRate': 11.66314, - 'market': 'DayAhead', - 'multiAreaEntries': list([ dict({ - 'deliveryEnd': '2024-11-06T00:00:00Z', - 'deliveryStart': '2024-11-05T23:00:00Z', + 'deliveryEnd': '2025-10-02T16:15:00Z', + 'deliveryStart': '2025-10-02T16:00:00Z', 'entryPerArea': dict({ - 'SE3': 126.66, - 'SE4': 275.6, + 'SE3': 1677.66, + 'SE4': 1334.3, }), }), dict({ - 'deliveryEnd': '2024-11-06T01:00:00Z', - 'deliveryStart': '2024-11-06T00:00:00Z', + 'deliveryEnd': '2025-10-02T16:30:00Z', + 'deliveryStart': '2025-10-02T16:15:00Z', 'entryPerArea': dict({ - 'SE3': 74.06, - 'SE4': 157.34, + 'SE3': 2010.55, + 'SE4': 1606.61, }), }), dict({ - 'deliveryEnd': '2024-11-06T02:00:00Z', - 'deliveryStart': '2024-11-06T01:00:00Z', + 'deliveryEnd': '2025-10-02T16:45:00Z', + 'deliveryStart': '2025-10-02T16:30:00Z', 'entryPerArea': dict({ - 'SE3': 78.38, - 'SE4': 165.62, + 'SE3': 2524.38, + 'SE4': 2013.53, }), }), dict({ - 'deliveryEnd': '2024-11-06T03:00:00Z', - 'deliveryStart': '2024-11-06T02:00:00Z', + 'deliveryEnd': '2025-10-02T17:00:00Z', + 'deliveryStart': '2025-10-02T16:45:00Z', 'entryPerArea': dict({ - 'SE3': 92.37, - 'SE4': 196.17, + 'SE3': 3288.35, + 'SE4': 2617.73, }), }), dict({ - 'deliveryEnd': '2024-11-06T04:00:00Z', - 'deliveryStart': '2024-11-06T03:00:00Z', + 'deliveryEnd': '2025-10-02T17:15:00Z', + 'deliveryStart': '2025-10-02T17:00:00Z', 'entryPerArea': dict({ - 'SE3': 99.14, - 'SE4': 190.58, + 'SE3': 3065.69, + 'SE4': 2472.19, }), }), dict({ - 'deliveryEnd': '2024-11-06T05:00:00Z', - 'deliveryStart': '2024-11-06T04:00:00Z', + 'deliveryEnd': '2025-10-02T17:30:00Z', + 'deliveryStart': '2025-10-02T17:15:00Z', 'entryPerArea': dict({ - 'SE3': 447.51, - 'SE4': 932.93, + 'SE3': 2824.72, + 'SE4': 2276.46, }), }), dict({ - 'deliveryEnd': '2024-11-06T06:00:00Z', - 'deliveryStart': '2024-11-06T05:00:00Z', + 'deliveryEnd': '2025-10-02T17:45:00Z', + 'deliveryStart': '2025-10-02T17:30:00Z', 'entryPerArea': dict({ - 'SE3': 641.47, - 'SE4': 1284.69, + 'SE3': 2279.66, + 'SE4': 1835.44, }), }), dict({ - 'deliveryEnd': '2024-11-06T07:00:00Z', - 'deliveryStart': '2024-11-06T06:00:00Z', + 'deliveryEnd': '2025-10-02T18:00:00Z', + 'deliveryStart': '2025-10-02T17:45:00Z', 'entryPerArea': dict({ - 'SE3': 1820.5, - 'SE4': 2449.96, + 'SE3': 1723.78, + 'SE4': 1385.38, }), }), dict({ - 'deliveryEnd': '2024-11-06T08:00:00Z', - 'deliveryStart': '2024-11-06T07:00:00Z', + 'deliveryEnd': '2025-10-02T18:15:00Z', + 'deliveryStart': '2025-10-02T18:00:00Z', 'entryPerArea': dict({ - 'SE3': 1723.0, - 'SE4': 2244.22, + 'SE3': 1935.08, + 'SE4': 1532.57, }), }), dict({ - 'deliveryEnd': '2024-11-06T09:00:00Z', - 'deliveryStart': '2024-11-06T08:00:00Z', + 'deliveryEnd': '2025-10-02T18:30:00Z', + 'deliveryStart': '2025-10-02T18:15:00Z', 'entryPerArea': dict({ - 'SE3': 1298.57, - 'SE4': 1643.45, + 'SE3': 1568.54, + 'SE4': 1240.18, }), }), dict({ - 'deliveryEnd': '2024-11-06T10:00:00Z', - 'deliveryStart': '2024-11-06T09:00:00Z', + 'deliveryEnd': '2025-10-02T18:45:00Z', + 'deliveryStart': '2025-10-02T18:30:00Z', 'entryPerArea': dict({ - 'SE3': 1099.25, - 'SE4': 1507.23, + 'SE3': 1430.51, + 'SE4': 1115.61, }), }), dict({ - 'deliveryEnd': '2024-11-06T11:00:00Z', - 'deliveryStart': '2024-11-06T10:00:00Z', + 'deliveryEnd': '2025-10-02T19:00:00Z', + 'deliveryStart': '2025-10-02T18:45:00Z', 'entryPerArea': dict({ - 'SE3': 903.31, - 'SE4': 1362.84, + 'SE3': 1377.66, + 'SE4': 1075.12, }), }), dict({ - 'deliveryEnd': '2024-11-06T12:00:00Z', - 'deliveryStart': '2024-11-06T11:00:00Z', + 'deliveryEnd': '2025-10-02T19:15:00Z', + 'deliveryStart': '2025-10-02T19:00:00Z', 'entryPerArea': dict({ - 'SE3': 959.99, - 'SE4': 1376.13, + 'SE3': 1408.44, + 'SE4': 1108.66, }), }), dict({ - 'deliveryEnd': '2024-11-06T13:00:00Z', - 'deliveryStart': '2024-11-06T12:00:00Z', + 'deliveryEnd': '2025-10-02T19:30:00Z', + 'deliveryStart': '2025-10-02T19:15:00Z', 'entryPerArea': dict({ - 'SE3': 1186.61, - 'SE4': 1449.96, + 'SE3': 1326.79, + 'SE4': 1049.74, }), }), dict({ - 'deliveryEnd': '2024-11-06T14:00:00Z', - 'deliveryStart': '2024-11-06T13:00:00Z', + 'deliveryEnd': '2025-10-02T19:45:00Z', + 'deliveryStart': '2025-10-02T19:30:00Z', 'entryPerArea': dict({ - 'SE3': 1307.67, - 'SE4': 1608.35, + 'SE3': 1210.94, + 'SE4': 951.1, }), }), dict({ - 'deliveryEnd': '2024-11-06T15:00:00Z', - 'deliveryStart': '2024-11-06T14:00:00Z', + 'deliveryEnd': '2025-10-02T20:00:00Z', + 'deliveryStart': '2025-10-02T19:45:00Z', 'entryPerArea': dict({ - 'SE3': 1385.46, - 'SE4': 2110.8, + 'SE3': 1293.58, + 'SE4': 1026.79, }), }), dict({ - 'deliveryEnd': '2024-11-06T16:00:00Z', - 'deliveryStart': '2024-11-06T15:00:00Z', + 'deliveryEnd': '2025-10-02T20:15:00Z', + 'deliveryStart': '2025-10-02T20:00:00Z', 'entryPerArea': dict({ - 'SE3': 1366.8, - 'SE4': 3031.25, + 'SE3': 1385.71, + 'SE4': 1091.0, }), }), dict({ - 'deliveryEnd': '2024-11-06T17:00:00Z', - 'deliveryStart': '2024-11-06T16:00:00Z', + 'deliveryEnd': '2025-10-02T20:30:00Z', + 'deliveryStart': '2025-10-02T20:15:00Z', 'entryPerArea': dict({ - 'SE3': 2366.57, - 'SE4': 5511.77, + 'SE3': 1341.47, + 'SE4': 1104.13, }), }), dict({ - 'deliveryEnd': '2024-11-06T18:00:00Z', - 'deliveryStart': '2024-11-06T17:00:00Z', + 'deliveryEnd': '2025-10-02T20:45:00Z', + 'deliveryStart': '2025-10-02T20:30:00Z', 'entryPerArea': dict({ - 'SE3': 1481.92, - 'SE4': 3351.64, + 'SE3': 1284.98, + 'SE4': 1024.36, }), }), dict({ - 'deliveryEnd': '2024-11-06T19:00:00Z', - 'deliveryStart': '2024-11-06T18:00:00Z', + 'deliveryEnd': '2025-10-02T21:00:00Z', + 'deliveryStart': '2025-10-02T20:45:00Z', 'entryPerArea': dict({ - 'SE3': 1082.69, - 'SE4': 2484.95, + 'SE3': 1071.47, + 'SE4': 892.51, }), }), dict({ - 'deliveryEnd': '2024-11-06T20:00:00Z', - 'deliveryStart': '2024-11-06T19:00:00Z', + 'deliveryEnd': '2025-10-02T21:15:00Z', + 'deliveryStart': '2025-10-02T21:00:00Z', 'entryPerArea': dict({ - 'SE3': 716.82, - 'SE4': 1624.33, + 'SE3': 1218.0, + 'SE4': 1123.99, }), }), dict({ - 'deliveryEnd': '2024-11-06T21:00:00Z', - 'deliveryStart': '2024-11-06T20:00:00Z', + 'deliveryEnd': '2025-10-02T21:30:00Z', + 'deliveryStart': '2025-10-02T21:15:00Z', 'entryPerArea': dict({ - 'SE3': 583.16, - 'SE4': 1306.27, + 'SE3': 1112.3, + 'SE4': 1001.63, }), }), dict({ - 'deliveryEnd': '2024-11-06T22:00:00Z', - 'deliveryStart': '2024-11-06T21:00:00Z', + 'deliveryEnd': '2025-10-02T21:45:00Z', + 'deliveryStart': '2025-10-02T21:30:00Z', 'entryPerArea': dict({ - 'SE3': 523.09, - 'SE4': 1142.99, + 'SE3': 873.64, + 'SE4': 806.67, }), }), dict({ - 'deliveryEnd': '2024-11-06T23:00:00Z', - 'deliveryStart': '2024-11-06T22:00:00Z', + 'deliveryEnd': '2025-10-02T22:00:00Z', + 'deliveryStart': '2025-10-02T21:45:00Z', 'entryPerArea': dict({ - 'SE3': 250.64, - 'SE4': 539.42, + 'SE3': 646.9, + 'SE4': 591.84, }), }), ]), - 'updatedAt': '2024-11-05T12:12:51.9853434Z', + 'updatedAt': '2025-10-01T11:25:06.1484362Z', 'version': 3, }), }), diff --git a/tests/components/nordpool/snapshots/test_sensor.ambr b/tests/components/nordpool/snapshots/test_sensor.ambr index 232836d1cc9a3..b2a53981fbc32 100644 --- a/tests/components/nordpool/snapshots/test_sensor.ambr +++ b/tests/components/nordpool/snapshots/test_sensor.ambr @@ -99,7 +99,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '1.01177', + 'state': '1.99796', }) # --- # name: test_sensor[sensor.nord_pool_se3_daily_average-entry] @@ -154,7 +154,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '0.90074', + 'state': '1.03398', }) # --- # name: test_sensor[sensor.nord_pool_se3_exchange_rate-entry] @@ -205,7 +205,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '11.6402', + 'state': '11.05186', }) # --- # name: test_sensor[sensor.nord_pool_se3_highest_price-entry] @@ -249,9 +249,9 @@ # name: test_sensor[sensor.nord_pool_se3_highest_price-state] StateSnapshot({ 'attributes': ReadOnlyDict({ - 'end': '2024-11-05T17:00:00+00:00', + 'end': '2025-10-01T17:15:00+00:00', 'friendly_name': 'Nord Pool SE3 Highest price', - 'start': '2024-11-05T16:00:00+00:00', + 'start': '2025-10-01T17:00:00+00:00', 'unit_of_measurement': 'SEK/kWh', }), 'context': , @@ -259,7 +259,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '2.51265', + 'state': '3.82803', }) # --- # name: test_sensor[sensor.nord_pool_se3_last_updated-entry] @@ -308,7 +308,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '2024-11-04T12:15:03+00:00', + 'state': '2025-09-30T12:08:16+00:00', }) # --- # name: test_sensor[sensor.nord_pool_se3_lowest_price-entry] @@ -352,9 +352,9 @@ # name: test_sensor[sensor.nord_pool_se3_lowest_price-state] StateSnapshot({ 'attributes': ReadOnlyDict({ - 'end': '2024-11-05T03:00:00+00:00', + 'end': '2025-10-01T02:15:00+00:00', 'friendly_name': 'Nord Pool SE3 Lowest price', - 'start': '2024-11-05T02:00:00+00:00', + 'start': '2025-10-01T02:00:00+00:00', 'unit_of_measurement': 'SEK/kWh', }), 'context': , @@ -362,7 +362,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '0.06169', + 'state': '0.44196', }) # --- # name: test_sensor[sensor.nord_pool_se3_next_price-entry] @@ -414,7 +414,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '0.83553', + 'state': '1.21814', }) # --- # name: test_sensor[sensor.nord_pool_se3_off_peak_1_average-entry] @@ -469,7 +469,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '0.42287', + 'state': '0.74593', }) # --- # name: test_sensor[sensor.nord_pool_se3_off_peak_1_highest_price-entry] @@ -524,7 +524,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '1.40614', + 'state': '1.80996', }) # --- # name: test_sensor[sensor.nord_pool_se3_off_peak_1_lowest_price-entry] @@ -579,7 +579,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '0.06169', + 'state': '0.44196', }) # --- # name: test_sensor[sensor.nord_pool_se3_off_peak_1_time_from-entry] @@ -628,7 +628,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '2024-11-04T23:00:00+00:00', + 'state': '2025-09-30T22:00:00+00:00', }) # --- # name: test_sensor[sensor.nord_pool_se3_off_peak_1_time_until-entry] @@ -677,7 +677,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '2024-11-05T07:00:00+00:00', + 'state': '2025-10-01T06:00:00+00:00', }) # --- # name: test_sensor[sensor.nord_pool_se3_off_peak_2_average-entry] @@ -732,7 +732,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '0.61079', + 'state': '1.05461', }) # --- # name: test_sensor[sensor.nord_pool_se3_off_peak_2_highest_price-entry] @@ -787,7 +787,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '0.83553', + 'state': '1.99796', }) # --- # name: test_sensor[sensor.nord_pool_se3_off_peak_2_lowest_price-entry] @@ -842,7 +842,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '0.28914', + 'state': '0.78568', }) # --- # name: test_sensor[sensor.nord_pool_se3_off_peak_2_time_from-entry] @@ -891,7 +891,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '2024-11-05T19:00:00+00:00', + 'state': '2025-10-01T18:00:00+00:00', }) # --- # name: test_sensor[sensor.nord_pool_se3_off_peak_2_time_until-entry] @@ -940,7 +940,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '2024-11-05T23:00:00+00:00', + 'state': '2025-10-01T22:00:00+00:00', }) # --- # name: test_sensor[sensor.nord_pool_se3_peak_average-entry] @@ -995,7 +995,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '1.31597', + 'state': '1.21913', }) # --- # name: test_sensor[sensor.nord_pool_se3_peak_highest_price-entry] @@ -1050,7 +1050,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '2.51265', + 'state': '3.82803', }) # --- # name: test_sensor[sensor.nord_pool_se3_peak_lowest_price-entry] @@ -1105,7 +1105,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '0.92505', + 'state': '0.60774', }) # --- # name: test_sensor[sensor.nord_pool_se3_peak_time_from-entry] @@ -1154,7 +1154,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '2024-11-05T07:00:00+00:00', + 'state': '2025-10-01T06:00:00+00:00', }) # --- # name: test_sensor[sensor.nord_pool_se3_peak_time_until-entry] @@ -1203,7 +1203,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '2024-11-05T19:00:00+00:00', + 'state': '2025-10-01T18:00:00+00:00', }) # --- # name: test_sensor[sensor.nord_pool_se3_previous_price-entry] @@ -1255,7 +1255,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '1.81983', + 'state': '3.82803', }) # --- # name: test_sensor[sensor.nord_pool_se4_currency-entry] @@ -1413,7 +1413,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '1.16612', + 'state': '1.18078', }) # --- # name: test_sensor[sensor.nord_pool_se4_exchange_rate-entry] @@ -1464,7 +1464,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '11.6402', + 'state': '11.05186', }) # --- # name: test_sensor[sensor.nord_pool_se4_highest_price-entry] @@ -1508,9 +1508,9 @@ # name: test_sensor[sensor.nord_pool_se4_highest_price-state] StateSnapshot({ 'attributes': ReadOnlyDict({ - 'end': '2024-11-05T17:00:00+00:00', + 'end': '2025-10-01T17:15:00+00:00', 'friendly_name': 'Nord Pool SE4 Highest price', - 'start': '2024-11-05T16:00:00+00:00', + 'start': '2025-10-01T17:00:00+00:00', 'unit_of_measurement': 'SEK/kWh', }), 'context': , @@ -1518,7 +1518,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '3.53303', + 'state': '4.44274', }) # --- # name: test_sensor[sensor.nord_pool_se4_last_updated-entry] @@ -1567,7 +1567,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '2024-11-04T12:15:03+00:00', + 'state': '2025-09-30T12:08:16+00:00', }) # --- # name: test_sensor[sensor.nord_pool_se4_lowest_price-entry] @@ -1611,9 +1611,9 @@ # name: test_sensor[sensor.nord_pool_se4_lowest_price-state] StateSnapshot({ 'attributes': ReadOnlyDict({ - 'end': '2024-11-05T19:00:00+00:00', + 'end': '2025-10-01T18:15:00+00:00', 'friendly_name': 'Nord Pool SE4 Lowest price', - 'start': '2024-11-05T18:00:00+00:00', + 'start': '2025-10-01T18:00:00+00:00', 'unit_of_measurement': 'SEK/kWh', }), 'context': , @@ -1673,7 +1673,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '1.11257', + 'state': '1.40502', }) # --- # name: test_sensor[sensor.nord_pool_se4_off_peak_1_average-entry] @@ -1728,7 +1728,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '0.49797', + 'state': '0.86099', }) # --- # name: test_sensor[sensor.nord_pool_se4_off_peak_1_highest_price-entry] @@ -1783,7 +1783,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '1.64825', + 'state': '2.02934', }) # --- # name: test_sensor[sensor.nord_pool_se4_off_peak_1_lowest_price-entry] @@ -1838,7 +1838,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '0.06519', + 'state': '0.51546', }) # --- # name: test_sensor[sensor.nord_pool_se4_off_peak_1_time_from-entry] @@ -1887,7 +1887,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '2024-11-04T23:00:00+00:00', + 'state': '2025-09-30T22:00:00+00:00', }) # --- # name: test_sensor[sensor.nord_pool_se4_off_peak_1_time_until-entry] @@ -1936,7 +1936,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '2024-11-05T07:00:00+00:00', + 'state': '2025-10-01T06:00:00+00:00', }) # --- # name: test_sensor[sensor.nord_pool_se4_off_peak_2_average-entry] @@ -1991,7 +1991,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '0.79398', + 'state': '1.21907', }) # --- # name: test_sensor[sensor.nord_pool_se4_off_peak_2_highest_price-entry] @@ -2046,7 +2046,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '1.11257', + 'state': '2.31216', }) # --- # name: test_sensor[sensor.nord_pool_se4_off_peak_2_lowest_price-entry] @@ -2101,7 +2101,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '0.34921', + 'state': '0.91222', }) # --- # name: test_sensor[sensor.nord_pool_se4_off_peak_2_time_from-entry] @@ -2150,7 +2150,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '2024-11-05T19:00:00+00:00', + 'state': '2025-10-01T18:00:00+00:00', }) # --- # name: test_sensor[sensor.nord_pool_se4_off_peak_2_time_until-entry] @@ -2199,7 +2199,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '2024-11-05T23:00:00+00:00', + 'state': '2025-10-01T22:00:00+00:00', }) # --- # name: test_sensor[sensor.nord_pool_se4_peak_average-entry] @@ -2254,7 +2254,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '1.73559', + 'state': '1.38122', }) # --- # name: test_sensor[sensor.nord_pool_se4_peak_highest_price-entry] @@ -2309,7 +2309,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '3.53303', + 'state': '4.44274', }) # --- # name: test_sensor[sensor.nord_pool_se4_peak_lowest_price-entry] @@ -2364,7 +2364,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '1.08172', + 'state': '0.68312', }) # --- # name: test_sensor[sensor.nord_pool_se4_peak_time_from-entry] @@ -2413,7 +2413,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '2024-11-05T07:00:00+00:00', + 'state': '2025-10-01T06:00:00+00:00', }) # --- # name: test_sensor[sensor.nord_pool_se4_peak_time_until-entry] @@ -2462,7 +2462,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '2024-11-05T19:00:00+00:00', + 'state': '2025-10-01T18:00:00+00:00', }) # --- # name: test_sensor[sensor.nord_pool_se4_previous_price-entry] @@ -2514,6 +2514,6 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '2.52406', + 'state': '4.44274', }) # --- diff --git a/tests/components/nordpool/snapshots/test_services.ambr b/tests/components/nordpool/snapshots/test_services.ambr index 5e39082f6474a..a478791bd9a59 100644 --- a/tests/components/nordpool/snapshots/test_services.ambr +++ b/tests/components/nordpool/snapshots/test_services.ambr @@ -9,124 +9,484 @@ dict({ 'SE3': list([ dict({ - 'end': '2024-11-05T00:00:00+00:00', - 'price': 250.73, - 'start': '2024-11-04T23:00:00+00:00', + 'end': '2025-09-30T22:15:00+00:00', + 'price': 556.68, + 'start': '2025-09-30T22:00:00+00:00', }), dict({ - 'end': '2024-11-05T01:00:00+00:00', - 'price': 76.36, - 'start': '2024-11-05T00:00:00+00:00', + 'end': '2025-09-30T22:30:00+00:00', + 'price': 519.88, + 'start': '2025-09-30T22:15:00+00:00', }), dict({ - 'end': '2024-11-05T02:00:00+00:00', - 'price': 73.92, - 'start': '2024-11-05T01:00:00+00:00', + 'end': '2025-09-30T22:45:00+00:00', + 'price': 508.28, + 'start': '2025-09-30T22:30:00+00:00', }), dict({ - 'end': '2024-11-05T03:00:00+00:00', - 'price': 61.69, - 'start': '2024-11-05T02:00:00+00:00', + 'end': '2025-09-30T23:00:00+00:00', + 'price': 509.93, + 'start': '2025-09-30T22:45:00+00:00', }), dict({ - 'end': '2024-11-05T04:00:00+00:00', - 'price': 64.6, - 'start': '2024-11-05T03:00:00+00:00', + 'end': '2025-09-30T23:15:00+00:00', + 'price': 501.64, + 'start': '2025-09-30T23:00:00+00:00', }), dict({ - 'end': '2024-11-05T05:00:00+00:00', - 'price': 453.27, - 'start': '2024-11-05T04:00:00+00:00', + 'end': '2025-09-30T23:30:00+00:00', + 'price': 509.05, + 'start': '2025-09-30T23:15:00+00:00', }), dict({ - 'end': '2024-11-05T06:00:00+00:00', - 'price': 996.28, - 'start': '2024-11-05T05:00:00+00:00', + 'end': '2025-09-30T23:45:00+00:00', + 'price': 491.03, + 'start': '2025-09-30T23:30:00+00:00', }), dict({ - 'end': '2024-11-05T07:00:00+00:00', - 'price': 1406.14, - 'start': '2024-11-05T06:00:00+00:00', + 'end': '2025-10-01T00:00:00+00:00', + 'price': 442.07, + 'start': '2025-09-30T23:45:00+00:00', }), dict({ - 'end': '2024-11-05T08:00:00+00:00', - 'price': 1346.54, - 'start': '2024-11-05T07:00:00+00:00', + 'end': '2025-10-01T00:15:00+00:00', + 'price': 504.08, + 'start': '2025-10-01T00:00:00+00:00', }), dict({ - 'end': '2024-11-05T09:00:00+00:00', - 'price': 1150.28, - 'start': '2024-11-05T08:00:00+00:00', + 'end': '2025-10-01T00:30:00+00:00', + 'price': 504.85, + 'start': '2025-10-01T00:15:00+00:00', }), dict({ - 'end': '2024-11-05T10:00:00+00:00', - 'price': 1031.32, - 'start': '2024-11-05T09:00:00+00:00', + 'end': '2025-10-01T00:45:00+00:00', + 'price': 504.3, + 'start': '2025-10-01T00:30:00+00:00', }), dict({ - 'end': '2024-11-05T11:00:00+00:00', - 'price': 927.37, - 'start': '2024-11-05T10:00:00+00:00', + 'end': '2025-10-01T01:00:00+00:00', + 'price': 506.29, + 'start': '2025-10-01T00:45:00+00:00', }), dict({ - 'end': '2024-11-05T12:00:00+00:00', - 'price': 925.05, - 'start': '2024-11-05T11:00:00+00:00', + 'end': '2025-10-01T01:15:00+00:00', + 'price': 442.07, + 'start': '2025-10-01T01:00:00+00:00', }), dict({ - 'end': '2024-11-05T13:00:00+00:00', - 'price': 949.49, - 'start': '2024-11-05T12:00:00+00:00', + 'end': '2025-10-01T01:30:00+00:00', + 'price': 441.96, + 'start': '2025-10-01T01:15:00+00:00', }), dict({ - 'end': '2024-11-05T14:00:00+00:00', - 'price': 1042.03, - 'start': '2024-11-05T13:00:00+00:00', + 'end': '2025-10-01T01:45:00+00:00', + 'price': 442.07, + 'start': '2025-10-01T01:30:00+00:00', }), dict({ - 'end': '2024-11-05T15:00:00+00:00', - 'price': 1258.89, - 'start': '2024-11-05T14:00:00+00:00', + 'end': '2025-10-01T02:00:00+00:00', + 'price': 442.07, + 'start': '2025-10-01T01:45:00+00:00', }), dict({ - 'end': '2024-11-05T16:00:00+00:00', - 'price': 1816.45, - 'start': '2024-11-05T15:00:00+00:00', + 'end': '2025-10-01T02:15:00+00:00', + 'price': 441.96, + 'start': '2025-10-01T02:00:00+00:00', }), dict({ - 'end': '2024-11-05T17:00:00+00:00', - 'price': 2512.65, - 'start': '2024-11-05T16:00:00+00:00', + 'end': '2025-10-01T02:30:00+00:00', + 'price': 483.3, + 'start': '2025-10-01T02:15:00+00:00', }), dict({ - 'end': '2024-11-05T18:00:00+00:00', - 'price': 1819.83, - 'start': '2024-11-05T17:00:00+00:00', + 'end': '2025-10-01T02:45:00+00:00', + 'price': 484.29, + 'start': '2025-10-01T02:30:00+00:00', }), dict({ - 'end': '2024-11-05T19:00:00+00:00', - 'price': 1011.77, - 'start': '2024-11-05T18:00:00+00:00', + 'end': '2025-10-01T03:00:00+00:00', + 'price': 574.7, + 'start': '2025-10-01T02:45:00+00:00', }), dict({ - 'end': '2024-11-05T20:00:00+00:00', - 'price': 835.53, - 'start': '2024-11-05T19:00:00+00:00', + 'end': '2025-10-01T03:15:00+00:00', + 'price': 543.31, + 'start': '2025-10-01T03:00:00+00:00', }), dict({ - 'end': '2024-11-05T21:00:00+00:00', - 'price': 796.19, - 'start': '2024-11-05T20:00:00+00:00', + 'end': '2025-10-01T03:30:00+00:00', + 'price': 578.01, + 'start': '2025-10-01T03:15:00+00:00', }), dict({ - 'end': '2024-11-05T22:00:00+00:00', - 'price': 522.3, - 'start': '2024-11-05T21:00:00+00:00', + 'end': '2025-10-01T03:45:00+00:00', + 'price': 774.96, + 'start': '2025-10-01T03:30:00+00:00', }), dict({ - 'end': '2024-11-05T23:00:00+00:00', - 'price': 289.14, - 'start': '2024-11-05T22:00:00+00:00', + 'end': '2025-10-01T04:00:00+00:00', + 'price': 787.0, + 'start': '2025-10-01T03:45:00+00:00', + }), + dict({ + 'end': '2025-10-01T04:15:00+00:00', + 'price': 902.38, + 'start': '2025-10-01T04:00:00+00:00', + }), + dict({ + 'end': '2025-10-01T04:30:00+00:00', + 'price': 1079.32, + 'start': '2025-10-01T04:15:00+00:00', + }), + dict({ + 'end': '2025-10-01T04:45:00+00:00', + 'price': 1222.67, + 'start': '2025-10-01T04:30:00+00:00', + }), + dict({ + 'end': '2025-10-01T05:00:00+00:00', + 'price': 1394.63, + 'start': '2025-10-01T04:45:00+00:00', + }), + dict({ + 'end': '2025-10-01T05:15:00+00:00', + 'price': 1529.36, + 'start': '2025-10-01T05:00:00+00:00', + }), + dict({ + 'end': '2025-10-01T05:30:00+00:00', + 'price': 1724.53, + 'start': '2025-10-01T05:15:00+00:00', + }), + dict({ + 'end': '2025-10-01T05:45:00+00:00', + 'price': 1809.96, + 'start': '2025-10-01T05:30:00+00:00', + }), + dict({ + 'end': '2025-10-01T06:00:00+00:00', + 'price': 1713.04, + 'start': '2025-10-01T05:45:00+00:00', + }), + dict({ + 'end': '2025-10-01T06:15:00+00:00', + 'price': 1925.9, + 'start': '2025-10-01T06:00:00+00:00', + }), + dict({ + 'end': '2025-10-01T06:30:00+00:00', + 'price': 1440.06, + 'start': '2025-10-01T06:15:00+00:00', + }), + dict({ + 'end': '2025-10-01T06:45:00+00:00', + 'price': 1183.32, + 'start': '2025-10-01T06:30:00+00:00', + }), + dict({ + 'end': '2025-10-01T07:00:00+00:00', + 'price': 962.95, + 'start': '2025-10-01T06:45:00+00:00', + }), + dict({ + 'end': '2025-10-01T07:15:00+00:00', + 'price': 1402.04, + 'start': '2025-10-01T07:00:00+00:00', + }), + dict({ + 'end': '2025-10-01T07:30:00+00:00', + 'price': 1060.65, + 'start': '2025-10-01T07:15:00+00:00', + }), + dict({ + 'end': '2025-10-01T07:45:00+00:00', + 'price': 949.13, + 'start': '2025-10-01T07:30:00+00:00', + }), + dict({ + 'end': '2025-10-01T08:00:00+00:00', + 'price': 841.82, + 'start': '2025-10-01T07:45:00+00:00', + }), + dict({ + 'end': '2025-10-01T08:15:00+00:00', + 'price': 1037.44, + 'start': '2025-10-01T08:00:00+00:00', + }), + dict({ + 'end': '2025-10-01T08:30:00+00:00', + 'price': 950.13, + 'start': '2025-10-01T08:15:00+00:00', + }), + dict({ + 'end': '2025-10-01T08:45:00+00:00', + 'price': 826.13, + 'start': '2025-10-01T08:30:00+00:00', + }), + dict({ + 'end': '2025-10-01T09:00:00+00:00', + 'price': 684.55, + 'start': '2025-10-01T08:45:00+00:00', + }), + dict({ + 'end': '2025-10-01T09:15:00+00:00', + 'price': 861.6, + 'start': '2025-10-01T09:00:00+00:00', + }), + dict({ + 'end': '2025-10-01T09:30:00+00:00', + 'price': 722.79, + 'start': '2025-10-01T09:15:00+00:00', + }), + dict({ + 'end': '2025-10-01T09:45:00+00:00', + 'price': 640.57, + 'start': '2025-10-01T09:30:00+00:00', + }), + dict({ + 'end': '2025-10-01T10:00:00+00:00', + 'price': 607.74, + 'start': '2025-10-01T09:45:00+00:00', + }), + dict({ + 'end': '2025-10-01T10:15:00+00:00', + 'price': 674.05, + 'start': '2025-10-01T10:00:00+00:00', + }), + dict({ + 'end': '2025-10-01T10:30:00+00:00', + 'price': 638.58, + 'start': '2025-10-01T10:15:00+00:00', + }), + dict({ + 'end': '2025-10-01T10:45:00+00:00', + 'price': 638.47, + 'start': '2025-10-01T10:30:00+00:00', + }), + dict({ + 'end': '2025-10-01T11:00:00+00:00', + 'price': 634.82, + 'start': '2025-10-01T10:45:00+00:00', + }), + dict({ + 'end': '2025-10-01T11:15:00+00:00', + 'price': 637.36, + 'start': '2025-10-01T11:00:00+00:00', + }), + dict({ + 'end': '2025-10-01T11:30:00+00:00', + 'price': 660.68, + 'start': '2025-10-01T11:15:00+00:00', + }), + dict({ + 'end': '2025-10-01T11:45:00+00:00', + 'price': 679.14, + 'start': '2025-10-01T11:30:00+00:00', + }), + dict({ + 'end': '2025-10-01T12:00:00+00:00', + 'price': 694.61, + 'start': '2025-10-01T11:45:00+00:00', + }), + dict({ + 'end': '2025-10-01T12:15:00+00:00', + 'price': 622.33, + 'start': '2025-10-01T12:00:00+00:00', + }), + dict({ + 'end': '2025-10-01T12:30:00+00:00', + 'price': 685.44, + 'start': '2025-10-01T12:15:00+00:00', + }), + dict({ + 'end': '2025-10-01T12:45:00+00:00', + 'price': 732.85, + 'start': '2025-10-01T12:30:00+00:00', + }), + dict({ + 'end': '2025-10-01T13:00:00+00:00', + 'price': 801.92, + 'start': '2025-10-01T12:45:00+00:00', + }), + dict({ + 'end': '2025-10-01T13:15:00+00:00', + 'price': 629.4, + 'start': '2025-10-01T13:00:00+00:00', + }), + dict({ + 'end': '2025-10-01T13:30:00+00:00', + 'price': 729.53, + 'start': '2025-10-01T13:15:00+00:00', + }), + dict({ + 'end': '2025-10-01T13:45:00+00:00', + 'price': 884.81, + 'start': '2025-10-01T13:30:00+00:00', + }), + dict({ + 'end': '2025-10-01T14:00:00+00:00', + 'price': 984.94, + 'start': '2025-10-01T13:45:00+00:00', + }), + dict({ + 'end': '2025-10-01T14:15:00+00:00', + 'price': 615.26, + 'start': '2025-10-01T14:00:00+00:00', + }), + dict({ + 'end': '2025-10-01T14:30:00+00:00', + 'price': 902.94, + 'start': '2025-10-01T14:15:00+00:00', + }), + dict({ + 'end': '2025-10-01T14:45:00+00:00', + 'price': 1043.85, + 'start': '2025-10-01T14:30:00+00:00', + }), + dict({ + 'end': '2025-10-01T15:00:00+00:00', + 'price': 1075.12, + 'start': '2025-10-01T14:45:00+00:00', + }), + dict({ + 'end': '2025-10-01T15:15:00+00:00', + 'price': 980.52, + 'start': '2025-10-01T15:00:00+00:00', + }), + dict({ + 'end': '2025-10-01T15:30:00+00:00', + 'price': 1162.66, + 'start': '2025-10-01T15:15:00+00:00', + }), + dict({ + 'end': '2025-10-01T15:45:00+00:00', + 'price': 1453.87, + 'start': '2025-10-01T15:30:00+00:00', + }), + dict({ + 'end': '2025-10-01T16:00:00+00:00', + 'price': 1955.96, + 'start': '2025-10-01T15:45:00+00:00', + }), + dict({ + 'end': '2025-10-01T16:15:00+00:00', + 'price': 1423.48, + 'start': '2025-10-01T16:00:00+00:00', + }), + dict({ + 'end': '2025-10-01T16:30:00+00:00', + 'price': 1900.04, + 'start': '2025-10-01T16:15:00+00:00', + }), + dict({ + 'end': '2025-10-01T16:45:00+00:00', + 'price': 2611.11, + 'start': '2025-10-01T16:30:00+00:00', + }), + dict({ + 'end': '2025-10-01T17:00:00+00:00', + 'price': 3467.41, + 'start': '2025-10-01T16:45:00+00:00', + }), + dict({ + 'end': '2025-10-01T17:15:00+00:00', + 'price': 3828.03, + 'start': '2025-10-01T17:00:00+00:00', + }), + dict({ + 'end': '2025-10-01T17:30:00+00:00', + 'price': 3429.83, + 'start': '2025-10-01T17:15:00+00:00', + }), + dict({ + 'end': '2025-10-01T17:45:00+00:00', + 'price': 2934.38, + 'start': '2025-10-01T17:30:00+00:00', + }), + dict({ + 'end': '2025-10-01T18:00:00+00:00', + 'price': 2308.07, + 'start': '2025-10-01T17:45:00+00:00', + }), + dict({ + 'end': '2025-10-01T18:15:00+00:00', + 'price': 1997.96, + 'start': '2025-10-01T18:00:00+00:00', + }), + dict({ + 'end': '2025-10-01T18:30:00+00:00', + 'price': 1424.03, + 'start': '2025-10-01T18:15:00+00:00', + }), + dict({ + 'end': '2025-10-01T18:45:00+00:00', + 'price': 1216.81, + 'start': '2025-10-01T18:30:00+00:00', + }), + dict({ + 'end': '2025-10-01T19:00:00+00:00', + 'price': 1070.15, + 'start': '2025-10-01T18:45:00+00:00', + }), + dict({ + 'end': '2025-10-01T19:15:00+00:00', + 'price': 1218.14, + 'start': '2025-10-01T19:00:00+00:00', + }), + dict({ + 'end': '2025-10-01T19:30:00+00:00', + 'price': 1135.8, + 'start': '2025-10-01T19:15:00+00:00', + }), + dict({ + 'end': '2025-10-01T19:45:00+00:00', + 'price': 959.96, + 'start': '2025-10-01T19:30:00+00:00', + }), + dict({ + 'end': '2025-10-01T20:00:00+00:00', + 'price': 913.66, + 'start': '2025-10-01T19:45:00+00:00', + }), + dict({ + 'end': '2025-10-01T20:15:00+00:00', + 'price': 1001.63, + 'start': '2025-10-01T20:00:00+00:00', + }), + dict({ + 'end': '2025-10-01T20:30:00+00:00', + 'price': 933.0, + 'start': '2025-10-01T20:15:00+00:00', + }), + dict({ + 'end': '2025-10-01T20:45:00+00:00', + 'price': 874.53, + 'start': '2025-10-01T20:30:00+00:00', + }), + dict({ + 'end': '2025-10-01T21:00:00+00:00', + 'price': 821.71, + 'start': '2025-10-01T20:45:00+00:00', + }), + dict({ + 'end': '2025-10-01T21:15:00+00:00', + 'price': 860.5, + 'start': '2025-10-01T21:00:00+00:00', + }), + dict({ + 'end': '2025-10-01T21:30:00+00:00', + 'price': 840.16, + 'start': '2025-10-01T21:15:00+00:00', + }), + dict({ + 'end': '2025-10-01T21:45:00+00:00', + 'price': 820.05, + 'start': '2025-10-01T21:30:00+00:00', + }), + dict({ + 'end': '2025-10-01T22:00:00+00:00', + 'price': 785.68, + 'start': '2025-10-01T21:45:00+00:00', }), ]), }) @@ -135,484 +495,484 @@ dict({ 'SE3': list([ dict({ - 'end': '2025-07-05T22:15:00+00:00', - 'price': 43.57, - 'start': '2025-07-05T22:00:00+00:00', + 'end': '2025-09-30T22:15:00+00:00', + 'price': 556.68, + 'start': '2025-09-30T22:00:00+00:00', }), dict({ - 'end': '2025-07-05T22:30:00+00:00', - 'price': 43.57, - 'start': '2025-07-05T22:15:00+00:00', + 'end': '2025-09-30T22:30:00+00:00', + 'price': 519.88, + 'start': '2025-09-30T22:15:00+00:00', }), dict({ - 'end': '2025-07-05T22:45:00+00:00', - 'price': 43.57, - 'start': '2025-07-05T22:30:00+00:00', + 'end': '2025-09-30T22:45:00+00:00', + 'price': 508.28, + 'start': '2025-09-30T22:30:00+00:00', }), dict({ - 'end': '2025-07-05T23:00:00+00:00', - 'price': 43.57, - 'start': '2025-07-05T22:45:00+00:00', + 'end': '2025-09-30T23:00:00+00:00', + 'price': 509.93, + 'start': '2025-09-30T22:45:00+00:00', }), dict({ - 'end': '2025-07-05T23:15:00+00:00', - 'price': 36.47, - 'start': '2025-07-05T23:00:00+00:00', + 'end': '2025-09-30T23:15:00+00:00', + 'price': 501.64, + 'start': '2025-09-30T23:00:00+00:00', }), dict({ - 'end': '2025-07-05T23:30:00+00:00', - 'price': 36.47, - 'start': '2025-07-05T23:15:00+00:00', + 'end': '2025-09-30T23:30:00+00:00', + 'price': 509.05, + 'start': '2025-09-30T23:15:00+00:00', }), dict({ - 'end': '2025-07-05T23:45:00+00:00', - 'price': 36.47, - 'start': '2025-07-05T23:30:00+00:00', + 'end': '2025-09-30T23:45:00+00:00', + 'price': 491.03, + 'start': '2025-09-30T23:30:00+00:00', }), dict({ - 'end': '2025-07-06T00:00:00+00:00', - 'price': 36.47, - 'start': '2025-07-05T23:45:00+00:00', + 'end': '2025-10-01T00:00:00+00:00', + 'price': 442.07, + 'start': '2025-09-30T23:45:00+00:00', }), dict({ - 'end': '2025-07-06T00:15:00+00:00', - 'price': 35.57, - 'start': '2025-07-06T00:00:00+00:00', + 'end': '2025-10-01T00:15:00+00:00', + 'price': 504.08, + 'start': '2025-10-01T00:00:00+00:00', }), dict({ - 'end': '2025-07-06T00:30:00+00:00', - 'price': 35.57, - 'start': '2025-07-06T00:15:00+00:00', + 'end': '2025-10-01T00:30:00+00:00', + 'price': 504.85, + 'start': '2025-10-01T00:15:00+00:00', }), dict({ - 'end': '2025-07-06T00:45:00+00:00', - 'price': 35.57, - 'start': '2025-07-06T00:30:00+00:00', + 'end': '2025-10-01T00:45:00+00:00', + 'price': 504.3, + 'start': '2025-10-01T00:30:00+00:00', }), dict({ - 'end': '2025-07-06T01:00:00+00:00', - 'price': 35.57, - 'start': '2025-07-06T00:45:00+00:00', + 'end': '2025-10-01T01:00:00+00:00', + 'price': 506.29, + 'start': '2025-10-01T00:45:00+00:00', }), dict({ - 'end': '2025-07-06T01:15:00+00:00', - 'price': 30.73, - 'start': '2025-07-06T01:00:00+00:00', + 'end': '2025-10-01T01:15:00+00:00', + 'price': 442.07, + 'start': '2025-10-01T01:00:00+00:00', }), dict({ - 'end': '2025-07-06T01:30:00+00:00', - 'price': 30.73, - 'start': '2025-07-06T01:15:00+00:00', + 'end': '2025-10-01T01:30:00+00:00', + 'price': 441.96, + 'start': '2025-10-01T01:15:00+00:00', }), dict({ - 'end': '2025-07-06T01:45:00+00:00', - 'price': 30.73, - 'start': '2025-07-06T01:30:00+00:00', + 'end': '2025-10-01T01:45:00+00:00', + 'price': 442.07, + 'start': '2025-10-01T01:30:00+00:00', }), dict({ - 'end': '2025-07-06T02:00:00+00:00', - 'price': 30.73, - 'start': '2025-07-06T01:45:00+00:00', + 'end': '2025-10-01T02:00:00+00:00', + 'price': 442.07, + 'start': '2025-10-01T01:45:00+00:00', }), dict({ - 'end': '2025-07-06T02:15:00+00:00', - 'price': 32.42, - 'start': '2025-07-06T02:00:00+00:00', + 'end': '2025-10-01T02:15:00+00:00', + 'price': 441.96, + 'start': '2025-10-01T02:00:00+00:00', }), dict({ - 'end': '2025-07-06T02:30:00+00:00', - 'price': 32.42, - 'start': '2025-07-06T02:15:00+00:00', + 'end': '2025-10-01T02:30:00+00:00', + 'price': 483.3, + 'start': '2025-10-01T02:15:00+00:00', }), dict({ - 'end': '2025-07-06T02:45:00+00:00', - 'price': 32.42, - 'start': '2025-07-06T02:30:00+00:00', + 'end': '2025-10-01T02:45:00+00:00', + 'price': 484.29, + 'start': '2025-10-01T02:30:00+00:00', }), dict({ - 'end': '2025-07-06T03:00:00+00:00', - 'price': 32.42, - 'start': '2025-07-06T02:45:00+00:00', + 'end': '2025-10-01T03:00:00+00:00', + 'price': 574.7, + 'start': '2025-10-01T02:45:00+00:00', }), dict({ - 'end': '2025-07-06T03:15:00+00:00', - 'price': 38.73, - 'start': '2025-07-06T03:00:00+00:00', + 'end': '2025-10-01T03:15:00+00:00', + 'price': 543.31, + 'start': '2025-10-01T03:00:00+00:00', }), dict({ - 'end': '2025-07-06T03:30:00+00:00', - 'price': 38.73, - 'start': '2025-07-06T03:15:00+00:00', + 'end': '2025-10-01T03:30:00+00:00', + 'price': 578.01, + 'start': '2025-10-01T03:15:00+00:00', }), dict({ - 'end': '2025-07-06T03:45:00+00:00', - 'price': 38.73, - 'start': '2025-07-06T03:30:00+00:00', + 'end': '2025-10-01T03:45:00+00:00', + 'price': 774.96, + 'start': '2025-10-01T03:30:00+00:00', }), dict({ - 'end': '2025-07-06T04:00:00+00:00', - 'price': 38.73, - 'start': '2025-07-06T03:45:00+00:00', + 'end': '2025-10-01T04:00:00+00:00', + 'price': 787.0, + 'start': '2025-10-01T03:45:00+00:00', }), dict({ - 'end': '2025-07-06T04:15:00+00:00', - 'price': 42.78, - 'start': '2025-07-06T04:00:00+00:00', + 'end': '2025-10-01T04:15:00+00:00', + 'price': 902.38, + 'start': '2025-10-01T04:00:00+00:00', }), dict({ - 'end': '2025-07-06T04:30:00+00:00', - 'price': 42.78, - 'start': '2025-07-06T04:15:00+00:00', + 'end': '2025-10-01T04:30:00+00:00', + 'price': 1079.32, + 'start': '2025-10-01T04:15:00+00:00', }), dict({ - 'end': '2025-07-06T04:45:00+00:00', - 'price': 42.78, - 'start': '2025-07-06T04:30:00+00:00', + 'end': '2025-10-01T04:45:00+00:00', + 'price': 1222.67, + 'start': '2025-10-01T04:30:00+00:00', }), dict({ - 'end': '2025-07-06T05:00:00+00:00', - 'price': 42.78, - 'start': '2025-07-06T04:45:00+00:00', + 'end': '2025-10-01T05:00:00+00:00', + 'price': 1394.63, + 'start': '2025-10-01T04:45:00+00:00', }), dict({ - 'end': '2025-07-06T05:15:00+00:00', - 'price': 54.71, - 'start': '2025-07-06T05:00:00+00:00', + 'end': '2025-10-01T05:15:00+00:00', + 'price': 1529.36, + 'start': '2025-10-01T05:00:00+00:00', }), dict({ - 'end': '2025-07-06T05:30:00+00:00', - 'price': 54.71, - 'start': '2025-07-06T05:15:00+00:00', + 'end': '2025-10-01T05:30:00+00:00', + 'price': 1724.53, + 'start': '2025-10-01T05:15:00+00:00', }), dict({ - 'end': '2025-07-06T05:45:00+00:00', - 'price': 54.71, - 'start': '2025-07-06T05:30:00+00:00', + 'end': '2025-10-01T05:45:00+00:00', + 'price': 1809.96, + 'start': '2025-10-01T05:30:00+00:00', }), dict({ - 'end': '2025-07-06T06:00:00+00:00', - 'price': 54.71, - 'start': '2025-07-06T05:45:00+00:00', + 'end': '2025-10-01T06:00:00+00:00', + 'price': 1713.04, + 'start': '2025-10-01T05:45:00+00:00', }), dict({ - 'end': '2025-07-06T06:15:00+00:00', - 'price': 83.87, - 'start': '2025-07-06T06:00:00+00:00', + 'end': '2025-10-01T06:15:00+00:00', + 'price': 1925.9, + 'start': '2025-10-01T06:00:00+00:00', }), dict({ - 'end': '2025-07-06T06:30:00+00:00', - 'price': 83.87, - 'start': '2025-07-06T06:15:00+00:00', + 'end': '2025-10-01T06:30:00+00:00', + 'price': 1440.06, + 'start': '2025-10-01T06:15:00+00:00', }), dict({ - 'end': '2025-07-06T06:45:00+00:00', - 'price': 83.87, - 'start': '2025-07-06T06:30:00+00:00', + 'end': '2025-10-01T06:45:00+00:00', + 'price': 1183.32, + 'start': '2025-10-01T06:30:00+00:00', }), dict({ - 'end': '2025-07-06T07:00:00+00:00', - 'price': 83.87, - 'start': '2025-07-06T06:45:00+00:00', + 'end': '2025-10-01T07:00:00+00:00', + 'price': 962.95, + 'start': '2025-10-01T06:45:00+00:00', }), dict({ - 'end': '2025-07-06T07:15:00+00:00', - 'price': 78.8, - 'start': '2025-07-06T07:00:00+00:00', + 'end': '2025-10-01T07:15:00+00:00', + 'price': 1402.04, + 'start': '2025-10-01T07:00:00+00:00', }), dict({ - 'end': '2025-07-06T07:30:00+00:00', - 'price': 78.8, - 'start': '2025-07-06T07:15:00+00:00', + 'end': '2025-10-01T07:30:00+00:00', + 'price': 1060.65, + 'start': '2025-10-01T07:15:00+00:00', }), dict({ - 'end': '2025-07-06T07:45:00+00:00', - 'price': 78.8, - 'start': '2025-07-06T07:30:00+00:00', + 'end': '2025-10-01T07:45:00+00:00', + 'price': 949.13, + 'start': '2025-10-01T07:30:00+00:00', }), dict({ - 'end': '2025-07-06T08:00:00+00:00', - 'price': 78.8, - 'start': '2025-07-06T07:45:00+00:00', + 'end': '2025-10-01T08:00:00+00:00', + 'price': 841.82, + 'start': '2025-10-01T07:45:00+00:00', }), dict({ - 'end': '2025-07-06T08:15:00+00:00', - 'price': 92.09, - 'start': '2025-07-06T08:00:00+00:00', + 'end': '2025-10-01T08:15:00+00:00', + 'price': 1037.44, + 'start': '2025-10-01T08:00:00+00:00', }), dict({ - 'end': '2025-07-06T08:30:00+00:00', - 'price': 92.09, - 'start': '2025-07-06T08:15:00+00:00', + 'end': '2025-10-01T08:30:00+00:00', + 'price': 950.13, + 'start': '2025-10-01T08:15:00+00:00', }), dict({ - 'end': '2025-07-06T08:45:00+00:00', - 'price': 92.09, - 'start': '2025-07-06T08:30:00+00:00', + 'end': '2025-10-01T08:45:00+00:00', + 'price': 826.13, + 'start': '2025-10-01T08:30:00+00:00', }), dict({ - 'end': '2025-07-06T09:00:00+00:00', - 'price': 92.09, - 'start': '2025-07-06T08:45:00+00:00', + 'end': '2025-10-01T09:00:00+00:00', + 'price': 684.55, + 'start': '2025-10-01T08:45:00+00:00', }), dict({ - 'end': '2025-07-06T09:15:00+00:00', - 'price': 104.92, - 'start': '2025-07-06T09:00:00+00:00', + 'end': '2025-10-01T09:15:00+00:00', + 'price': 861.6, + 'start': '2025-10-01T09:00:00+00:00', }), dict({ - 'end': '2025-07-06T09:30:00+00:00', - 'price': 104.92, - 'start': '2025-07-06T09:15:00+00:00', + 'end': '2025-10-01T09:30:00+00:00', + 'price': 722.79, + 'start': '2025-10-01T09:15:00+00:00', }), dict({ - 'end': '2025-07-06T09:45:00+00:00', - 'price': 104.92, - 'start': '2025-07-06T09:30:00+00:00', + 'end': '2025-10-01T09:45:00+00:00', + 'price': 640.57, + 'start': '2025-10-01T09:30:00+00:00', }), dict({ - 'end': '2025-07-06T10:00:00+00:00', - 'price': 104.92, - 'start': '2025-07-06T09:45:00+00:00', + 'end': '2025-10-01T10:00:00+00:00', + 'price': 607.74, + 'start': '2025-10-01T09:45:00+00:00', }), dict({ - 'end': '2025-07-06T10:15:00+00:00', - 'price': 72.5, - 'start': '2025-07-06T10:00:00+00:00', + 'end': '2025-10-01T10:15:00+00:00', + 'price': 674.05, + 'start': '2025-10-01T10:00:00+00:00', }), dict({ - 'end': '2025-07-06T10:30:00+00:00', - 'price': 72.5, - 'start': '2025-07-06T10:15:00+00:00', + 'end': '2025-10-01T10:30:00+00:00', + 'price': 638.58, + 'start': '2025-10-01T10:15:00+00:00', }), dict({ - 'end': '2025-07-06T10:45:00+00:00', - 'price': 72.5, - 'start': '2025-07-06T10:30:00+00:00', + 'end': '2025-10-01T10:45:00+00:00', + 'price': 638.47, + 'start': '2025-10-01T10:30:00+00:00', }), dict({ - 'end': '2025-07-06T11:00:00+00:00', - 'price': 72.5, - 'start': '2025-07-06T10:45:00+00:00', + 'end': '2025-10-01T11:00:00+00:00', + 'price': 634.82, + 'start': '2025-10-01T10:45:00+00:00', }), dict({ - 'end': '2025-07-06T11:15:00+00:00', - 'price': 63.49, - 'start': '2025-07-06T11:00:00+00:00', + 'end': '2025-10-01T11:15:00+00:00', + 'price': 637.36, + 'start': '2025-10-01T11:00:00+00:00', }), dict({ - 'end': '2025-07-06T11:30:00+00:00', - 'price': 63.49, - 'start': '2025-07-06T11:15:00+00:00', + 'end': '2025-10-01T11:30:00+00:00', + 'price': 660.68, + 'start': '2025-10-01T11:15:00+00:00', }), dict({ - 'end': '2025-07-06T11:45:00+00:00', - 'price': 63.49, - 'start': '2025-07-06T11:30:00+00:00', + 'end': '2025-10-01T11:45:00+00:00', + 'price': 679.14, + 'start': '2025-10-01T11:30:00+00:00', }), dict({ - 'end': '2025-07-06T12:00:00+00:00', - 'price': 63.49, - 'start': '2025-07-06T11:45:00+00:00', + 'end': '2025-10-01T12:00:00+00:00', + 'price': 694.61, + 'start': '2025-10-01T11:45:00+00:00', }), dict({ - 'end': '2025-07-06T12:15:00+00:00', - 'price': 91.64, - 'start': '2025-07-06T12:00:00+00:00', + 'end': '2025-10-01T12:15:00+00:00', + 'price': 622.33, + 'start': '2025-10-01T12:00:00+00:00', }), dict({ - 'end': '2025-07-06T12:30:00+00:00', - 'price': 91.64, - 'start': '2025-07-06T12:15:00+00:00', + 'end': '2025-10-01T12:30:00+00:00', + 'price': 685.44, + 'start': '2025-10-01T12:15:00+00:00', }), dict({ - 'end': '2025-07-06T12:45:00+00:00', - 'price': 91.64, - 'start': '2025-07-06T12:30:00+00:00', + 'end': '2025-10-01T12:45:00+00:00', + 'price': 732.85, + 'start': '2025-10-01T12:30:00+00:00', }), dict({ - 'end': '2025-07-06T13:00:00+00:00', - 'price': 91.64, - 'start': '2025-07-06T12:45:00+00:00', + 'end': '2025-10-01T13:00:00+00:00', + 'price': 801.92, + 'start': '2025-10-01T12:45:00+00:00', }), dict({ - 'end': '2025-07-06T13:15:00+00:00', - 'price': 111.79, - 'start': '2025-07-06T13:00:00+00:00', + 'end': '2025-10-01T13:15:00+00:00', + 'price': 629.4, + 'start': '2025-10-01T13:00:00+00:00', }), dict({ - 'end': '2025-07-06T13:30:00+00:00', - 'price': 111.79, - 'start': '2025-07-06T13:15:00+00:00', + 'end': '2025-10-01T13:30:00+00:00', + 'price': 729.53, + 'start': '2025-10-01T13:15:00+00:00', }), dict({ - 'end': '2025-07-06T13:45:00+00:00', - 'price': 111.79, - 'start': '2025-07-06T13:30:00+00:00', + 'end': '2025-10-01T13:45:00+00:00', + 'price': 884.81, + 'start': '2025-10-01T13:30:00+00:00', }), dict({ - 'end': '2025-07-06T14:00:00+00:00', - 'price': 111.79, - 'start': '2025-07-06T13:45:00+00:00', + 'end': '2025-10-01T14:00:00+00:00', + 'price': 984.94, + 'start': '2025-10-01T13:45:00+00:00', }), dict({ - 'end': '2025-07-06T14:15:00+00:00', - 'price': 234.04, - 'start': '2025-07-06T14:00:00+00:00', + 'end': '2025-10-01T14:15:00+00:00', + 'price': 615.26, + 'start': '2025-10-01T14:00:00+00:00', }), dict({ - 'end': '2025-07-06T14:30:00+00:00', - 'price': 234.04, - 'start': '2025-07-06T14:15:00+00:00', + 'end': '2025-10-01T14:30:00+00:00', + 'price': 902.94, + 'start': '2025-10-01T14:15:00+00:00', }), dict({ - 'end': '2025-07-06T14:45:00+00:00', - 'price': 234.04, - 'start': '2025-07-06T14:30:00+00:00', + 'end': '2025-10-01T14:45:00+00:00', + 'price': 1043.85, + 'start': '2025-10-01T14:30:00+00:00', }), dict({ - 'end': '2025-07-06T15:00:00+00:00', - 'price': 234.04, - 'start': '2025-07-06T14:45:00+00:00', + 'end': '2025-10-01T15:00:00+00:00', + 'price': 1075.12, + 'start': '2025-10-01T14:45:00+00:00', }), dict({ - 'end': '2025-07-06T15:15:00+00:00', - 'price': 435.33, - 'start': '2025-07-06T15:00:00+00:00', + 'end': '2025-10-01T15:15:00+00:00', + 'price': 980.52, + 'start': '2025-10-01T15:00:00+00:00', }), dict({ - 'end': '2025-07-06T15:30:00+00:00', - 'price': 435.33, - 'start': '2025-07-06T15:15:00+00:00', + 'end': '2025-10-01T15:30:00+00:00', + 'price': 1162.66, + 'start': '2025-10-01T15:15:00+00:00', }), dict({ - 'end': '2025-07-06T15:45:00+00:00', - 'price': 435.33, - 'start': '2025-07-06T15:30:00+00:00', + 'end': '2025-10-01T15:45:00+00:00', + 'price': 1453.87, + 'start': '2025-10-01T15:30:00+00:00', }), dict({ - 'end': '2025-07-06T16:00:00+00:00', - 'price': 435.33, - 'start': '2025-07-06T15:45:00+00:00', + 'end': '2025-10-01T16:00:00+00:00', + 'price': 1955.96, + 'start': '2025-10-01T15:45:00+00:00', }), dict({ - 'end': '2025-07-06T16:15:00+00:00', - 'price': 431.84, - 'start': '2025-07-06T16:00:00+00:00', + 'end': '2025-10-01T16:15:00+00:00', + 'price': 1423.48, + 'start': '2025-10-01T16:00:00+00:00', }), dict({ - 'end': '2025-07-06T16:30:00+00:00', - 'price': 431.84, - 'start': '2025-07-06T16:15:00+00:00', + 'end': '2025-10-01T16:30:00+00:00', + 'price': 1900.04, + 'start': '2025-10-01T16:15:00+00:00', }), dict({ - 'end': '2025-07-06T16:45:00+00:00', - 'price': 431.84, - 'start': '2025-07-06T16:30:00+00:00', + 'end': '2025-10-01T16:45:00+00:00', + 'price': 2611.11, + 'start': '2025-10-01T16:30:00+00:00', }), dict({ - 'end': '2025-07-06T17:00:00+00:00', - 'price': 431.84, - 'start': '2025-07-06T16:45:00+00:00', + 'end': '2025-10-01T17:00:00+00:00', + 'price': 3467.41, + 'start': '2025-10-01T16:45:00+00:00', }), dict({ - 'end': '2025-07-06T17:15:00+00:00', - 'price': 423.73, - 'start': '2025-07-06T17:00:00+00:00', + 'end': '2025-10-01T17:15:00+00:00', + 'price': 3828.03, + 'start': '2025-10-01T17:00:00+00:00', }), dict({ - 'end': '2025-07-06T17:30:00+00:00', - 'price': 423.73, - 'start': '2025-07-06T17:15:00+00:00', + 'end': '2025-10-01T17:30:00+00:00', + 'price': 3429.83, + 'start': '2025-10-01T17:15:00+00:00', }), dict({ - 'end': '2025-07-06T17:45:00+00:00', - 'price': 423.73, - 'start': '2025-07-06T17:30:00+00:00', + 'end': '2025-10-01T17:45:00+00:00', + 'price': 2934.38, + 'start': '2025-10-01T17:30:00+00:00', }), dict({ - 'end': '2025-07-06T18:00:00+00:00', - 'price': 423.73, - 'start': '2025-07-06T17:45:00+00:00', + 'end': '2025-10-01T18:00:00+00:00', + 'price': 2308.07, + 'start': '2025-10-01T17:45:00+00:00', }), dict({ - 'end': '2025-07-06T18:15:00+00:00', - 'price': 437.92, - 'start': '2025-07-06T18:00:00+00:00', + 'end': '2025-10-01T18:15:00+00:00', + 'price': 1997.96, + 'start': '2025-10-01T18:00:00+00:00', }), dict({ - 'end': '2025-07-06T18:30:00+00:00', - 'price': 437.92, - 'start': '2025-07-06T18:15:00+00:00', + 'end': '2025-10-01T18:30:00+00:00', + 'price': 1424.03, + 'start': '2025-10-01T18:15:00+00:00', }), dict({ - 'end': '2025-07-06T18:45:00+00:00', - 'price': 437.92, - 'start': '2025-07-06T18:30:00+00:00', + 'end': '2025-10-01T18:45:00+00:00', + 'price': 1216.81, + 'start': '2025-10-01T18:30:00+00:00', }), dict({ - 'end': '2025-07-06T19:00:00+00:00', - 'price': 437.92, - 'start': '2025-07-06T18:45:00+00:00', + 'end': '2025-10-01T19:00:00+00:00', + 'price': 1070.15, + 'start': '2025-10-01T18:45:00+00:00', }), dict({ - 'end': '2025-07-06T19:15:00+00:00', - 'price': 416.42, - 'start': '2025-07-06T19:00:00+00:00', + 'end': '2025-10-01T19:15:00+00:00', + 'price': 1218.14, + 'start': '2025-10-01T19:00:00+00:00', }), dict({ - 'end': '2025-07-06T19:30:00+00:00', - 'price': 416.42, - 'start': '2025-07-06T19:15:00+00:00', + 'end': '2025-10-01T19:30:00+00:00', + 'price': 1135.8, + 'start': '2025-10-01T19:15:00+00:00', }), dict({ - 'end': '2025-07-06T19:45:00+00:00', - 'price': 416.42, - 'start': '2025-07-06T19:30:00+00:00', + 'end': '2025-10-01T19:45:00+00:00', + 'price': 959.96, + 'start': '2025-10-01T19:30:00+00:00', }), dict({ - 'end': '2025-07-06T20:00:00+00:00', - 'price': 416.42, - 'start': '2025-07-06T19:45:00+00:00', + 'end': '2025-10-01T20:00:00+00:00', + 'price': 913.66, + 'start': '2025-10-01T19:45:00+00:00', }), dict({ - 'end': '2025-07-06T20:15:00+00:00', - 'price': 414.39, - 'start': '2025-07-06T20:00:00+00:00', + 'end': '2025-10-01T20:15:00+00:00', + 'price': 1001.63, + 'start': '2025-10-01T20:00:00+00:00', }), dict({ - 'end': '2025-07-06T20:30:00+00:00', - 'price': 414.39, - 'start': '2025-07-06T20:15:00+00:00', + 'end': '2025-10-01T20:30:00+00:00', + 'price': 933.0, + 'start': '2025-10-01T20:15:00+00:00', }), dict({ - 'end': '2025-07-06T20:45:00+00:00', - 'price': 414.39, - 'start': '2025-07-06T20:30:00+00:00', + 'end': '2025-10-01T20:45:00+00:00', + 'price': 874.53, + 'start': '2025-10-01T20:30:00+00:00', }), dict({ - 'end': '2025-07-06T21:00:00+00:00', - 'price': 414.39, - 'start': '2025-07-06T20:45:00+00:00', + 'end': '2025-10-01T21:00:00+00:00', + 'price': 821.71, + 'start': '2025-10-01T20:45:00+00:00', }), dict({ - 'end': '2025-07-06T21:15:00+00:00', - 'price': 396.38, - 'start': '2025-07-06T21:00:00+00:00', + 'end': '2025-10-01T21:15:00+00:00', + 'price': 860.5, + 'start': '2025-10-01T21:00:00+00:00', }), dict({ - 'end': '2025-07-06T21:30:00+00:00', - 'price': 396.38, - 'start': '2025-07-06T21:15:00+00:00', + 'end': '2025-10-01T21:30:00+00:00', + 'price': 840.16, + 'start': '2025-10-01T21:15:00+00:00', }), dict({ - 'end': '2025-07-06T21:45:00+00:00', - 'price': 396.38, - 'start': '2025-07-06T21:30:00+00:00', + 'end': '2025-10-01T21:45:00+00:00', + 'price': 820.05, + 'start': '2025-10-01T21:30:00+00:00', }), dict({ - 'end': '2025-07-06T22:00:00+00:00', - 'price': 396.38, - 'start': '2025-07-06T21:45:00+00:00', + 'end': '2025-10-01T22:00:00+00:00', + 'price': 785.68, + 'start': '2025-10-01T21:45:00+00:00', }), ]), }) @@ -621,124 +981,124 @@ dict({ 'SE3': list([ dict({ - 'end': '2025-07-05T23:00:00+00:00', - 'price': 43.57, - 'start': '2025-07-05T22:00:00+00:00', + 'end': '2025-09-30T23:00:00+00:00', + 'price': 523.75, + 'start': '2025-09-30T22:00:00+00:00', }), dict({ - 'end': '2025-07-06T00:00:00+00:00', - 'price': 36.47, - 'start': '2025-07-05T23:00:00+00:00', + 'end': '2025-10-01T00:00:00+00:00', + 'price': 485.95, + 'start': '2025-09-30T23:00:00+00:00', }), dict({ - 'end': '2025-07-06T01:00:00+00:00', - 'price': 35.57, - 'start': '2025-07-06T00:00:00+00:00', + 'end': '2025-10-01T01:00:00+00:00', + 'price': 504.85, + 'start': '2025-10-01T00:00:00+00:00', }), dict({ - 'end': '2025-07-06T02:00:00+00:00', - 'price': 30.73, - 'start': '2025-07-06T01:00:00+00:00', + 'end': '2025-10-01T02:00:00+00:00', + 'price': 442.07, + 'start': '2025-10-01T01:00:00+00:00', }), dict({ - 'end': '2025-07-06T03:00:00+00:00', - 'price': 32.42, - 'start': '2025-07-06T02:00:00+00:00', + 'end': '2025-10-01T03:00:00+00:00', + 'price': 496.12, + 'start': '2025-10-01T02:00:00+00:00', }), dict({ - 'end': '2025-07-06T04:00:00+00:00', - 'price': 38.73, - 'start': '2025-07-06T03:00:00+00:00', + 'end': '2025-10-01T04:00:00+00:00', + 'price': 670.85, + 'start': '2025-10-01T03:00:00+00:00', }), dict({ - 'end': '2025-07-06T05:00:00+00:00', - 'price': 42.78, - 'start': '2025-07-06T04:00:00+00:00', + 'end': '2025-10-01T05:00:00+00:00', + 'price': 1149.72, + 'start': '2025-10-01T04:00:00+00:00', }), dict({ - 'end': '2025-07-06T06:00:00+00:00', - 'price': 54.71, - 'start': '2025-07-06T05:00:00+00:00', + 'end': '2025-10-01T06:00:00+00:00', + 'price': 1694.25, + 'start': '2025-10-01T05:00:00+00:00', }), dict({ - 'end': '2025-07-06T07:00:00+00:00', - 'price': 83.87, - 'start': '2025-07-06T06:00:00+00:00', + 'end': '2025-10-01T07:00:00+00:00', + 'price': 1378.06, + 'start': '2025-10-01T06:00:00+00:00', }), dict({ - 'end': '2025-07-06T08:00:00+00:00', - 'price': 78.8, - 'start': '2025-07-06T07:00:00+00:00', + 'end': '2025-10-01T08:00:00+00:00', + 'price': 1063.41, + 'start': '2025-10-01T07:00:00+00:00', }), dict({ - 'end': '2025-07-06T09:00:00+00:00', - 'price': 92.09, - 'start': '2025-07-06T08:00:00+00:00', + 'end': '2025-10-01T09:00:00+00:00', + 'price': 874.53, + 'start': '2025-10-01T08:00:00+00:00', }), dict({ - 'end': '2025-07-06T10:00:00+00:00', - 'price': 104.92, - 'start': '2025-07-06T09:00:00+00:00', + 'end': '2025-10-01T10:00:00+00:00', + 'price': 708.2, + 'start': '2025-10-01T09:00:00+00:00', }), dict({ - 'end': '2025-07-06T11:00:00+00:00', - 'price': 72.5, - 'start': '2025-07-06T10:00:00+00:00', + 'end': '2025-10-01T11:00:00+00:00', + 'price': 646.53, + 'start': '2025-10-01T10:00:00+00:00', }), dict({ - 'end': '2025-07-06T12:00:00+00:00', - 'price': 63.49, - 'start': '2025-07-06T11:00:00+00:00', + 'end': '2025-10-01T12:00:00+00:00', + 'price': 667.97, + 'start': '2025-10-01T11:00:00+00:00', }), dict({ - 'end': '2025-07-06T13:00:00+00:00', - 'price': 91.64, - 'start': '2025-07-06T12:00:00+00:00', + 'end': '2025-10-01T13:00:00+00:00', + 'price': 710.63, + 'start': '2025-10-01T12:00:00+00:00', }), dict({ - 'end': '2025-07-06T14:00:00+00:00', - 'price': 111.79, - 'start': '2025-07-06T13:00:00+00:00', + 'end': '2025-10-01T14:00:00+00:00', + 'price': 807.23, + 'start': '2025-10-01T13:00:00+00:00', }), dict({ - 'end': '2025-07-06T15:00:00+00:00', - 'price': 234.04, - 'start': '2025-07-06T14:00:00+00:00', + 'end': '2025-10-01T15:00:00+00:00', + 'price': 909.35, + 'start': '2025-10-01T14:00:00+00:00', }), dict({ - 'end': '2025-07-06T16:00:00+00:00', - 'price': 435.33, - 'start': '2025-07-06T15:00:00+00:00', + 'end': '2025-10-01T16:00:00+00:00', + 'price': 1388.22, + 'start': '2025-10-01T15:00:00+00:00', }), dict({ - 'end': '2025-07-06T17:00:00+00:00', - 'price': 431.84, - 'start': '2025-07-06T16:00:00+00:00', + 'end': '2025-10-01T17:00:00+00:00', + 'price': 2350.51, + 'start': '2025-10-01T16:00:00+00:00', }), dict({ - 'end': '2025-07-06T18:00:00+00:00', - 'price': 423.73, - 'start': '2025-07-06T17:00:00+00:00', + 'end': '2025-10-01T18:00:00+00:00', + 'price': 3125.13, + 'start': '2025-10-01T17:00:00+00:00', }), dict({ - 'end': '2025-07-06T19:00:00+00:00', - 'price': 437.92, - 'start': '2025-07-06T18:00:00+00:00', + 'end': '2025-10-01T19:00:00+00:00', + 'price': 1427.24, + 'start': '2025-10-01T18:00:00+00:00', }), dict({ - 'end': '2025-07-06T20:00:00+00:00', - 'price': 416.42, - 'start': '2025-07-06T19:00:00+00:00', + 'end': '2025-10-01T20:00:00+00:00', + 'price': 1056.89, + 'start': '2025-10-01T19:00:00+00:00', }), dict({ - 'end': '2025-07-06T21:00:00+00:00', - 'price': 414.39, - 'start': '2025-07-06T20:00:00+00:00', + 'end': '2025-10-01T21:00:00+00:00', + 'price': 907.69, + 'start': '2025-10-01T20:00:00+00:00', }), dict({ - 'end': '2025-07-06T22:00:00+00:00', - 'price': 396.38, - 'start': '2025-07-06T21:00:00+00:00', + 'end': '2025-10-01T22:00:00+00:00', + 'price': 826.57, + 'start': '2025-10-01T21:00:00+00:00', }), ]), }) diff --git a/tests/components/nordpool/test_config_flow.py b/tests/components/nordpool/test_config_flow.py index 1f0e99b65ff97..9756c909cf384 100644 --- a/tests/components/nordpool/test_config_flow.py +++ b/tests/components/nordpool/test_config_flow.py @@ -26,7 +26,7 @@ from tests.test_util.aiohttp import AiohttpClientMocker -@pytest.mark.freeze_time("2024-11-05T18:00:00+00:00") +@pytest.mark.freeze_time("2025-10-01T18:00:00+00:00") async def test_form(hass: HomeAssistant, get_client: NordPoolClient) -> None: """Test we get the form.""" @@ -48,7 +48,7 @@ async def test_form(hass: HomeAssistant, get_client: NordPoolClient) -> None: assert result["data"] == {"areas": ["SE3", "SE4"], "currency": "SEK"} -@pytest.mark.freeze_time("2024-11-05T18:00:00+00:00") +@pytest.mark.freeze_time("2025-10-01T18:00:00+00:00") async def test_single_config_entry( hass: HomeAssistant, load_int: None, get_client: NordPoolClient ) -> None: @@ -61,7 +61,7 @@ async def test_single_config_entry( assert result["reason"] == "single_instance_allowed" -@pytest.mark.freeze_time("2024-11-05T18:00:00+00:00") +@pytest.mark.freeze_time("2025-10-01T18:00:00+00:00") @pytest.mark.parametrize( ("error_message", "p_error"), [ @@ -107,7 +107,7 @@ async def test_cannot_connect( assert result["data"] == {"areas": ["SE3", "SE4"], "currency": "SEK"} -@pytest.mark.freeze_time("2024-11-05T18:00:00+00:00") +@pytest.mark.freeze_time("2025-10-01T18:00:00+00:00") async def test_reconfigure( hass: HomeAssistant, load_int: MockConfigEntry, @@ -134,7 +134,7 @@ async def test_reconfigure( } -@pytest.mark.freeze_time("2024-11-05T18:00:00+00:00") +@pytest.mark.freeze_time("2025-10-01T18:00:00+00:00") @pytest.mark.parametrize( ("error_message", "p_error"), [ diff --git a/tests/components/nordpool/test_coordinator.py b/tests/components/nordpool/test_coordinator.py index e9af70d05bc87..94d66a789cc50 100644 --- a/tests/components/nordpool/test_coordinator.py +++ b/tests/components/nordpool/test_coordinator.py @@ -31,7 +31,7 @@ from tests.common import MockConfigEntry, async_fire_time_changed -@pytest.mark.freeze_time("2024-11-05T10:00:00+00:00") +@pytest.mark.freeze_time("2025-10-01T10:00:00+00:00") async def test_coordinator( hass: HomeAssistant, get_client: NordPoolClient, @@ -50,7 +50,26 @@ async def test_coordinator( await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() state = hass.states.get("sensor.nord_pool_se3_current_price") - assert state.state == "0.92737" + assert state.state == "0.67405" + + assert "Next data update at 2025-10-01 11:00:00+00:00" in caplog.text + assert "Next listener update at 2025-10-01 10:15:00+00:00" in caplog.text + + with ( + patch( + "homeassistant.components.nordpool.coordinator.NordPoolClient.async_get_delivery_period", + wraps=get_client.async_get_delivery_period, + ) as mock_data, + ): + freezer.tick(timedelta(minutes=17)) + async_fire_time_changed(hass) + await hass.async_block_till_done(wait_background_tasks=True) + assert mock_data.call_count == 0 + state = hass.states.get("sensor.nord_pool_se3_current_price") + assert state.state == "0.63858" + + assert "Next data update at 2025-10-01 11:00:00+00:00" in caplog.text + assert "Next listener update at 2025-10-01 10:30:00+00:00" in caplog.text with ( patch( @@ -63,7 +82,7 @@ async def test_coordinator( await hass.async_block_till_done(wait_background_tasks=True) assert mock_data.call_count == 1 state = hass.states.get("sensor.nord_pool_se3_current_price") - assert state.state == "0.92505" + assert state.state == "0.66068" with ( patch( @@ -77,7 +96,7 @@ async def test_coordinator( await hass.async_block_till_done(wait_background_tasks=True) assert mock_data.call_count == 1 state = hass.states.get("sensor.nord_pool_se3_current_price") - assert state.state == "0.94949" + assert state.state == "0.68544" assert "Authentication error" in caplog.text with ( @@ -93,7 +112,7 @@ async def test_coordinator( # Empty responses does not raise assert mock_data.call_count == 3 state = hass.states.get("sensor.nord_pool_se3_current_price") - assert state.state == "1.04203" + assert state.state == "0.72953" assert "Empty response" in caplog.text with ( @@ -108,7 +127,7 @@ async def test_coordinator( await hass.async_block_till_done(wait_background_tasks=True) assert mock_data.call_count == 1 state = hass.states.get("sensor.nord_pool_se3_current_price") - assert state.state == "1.25889" + assert state.state == "0.90294" assert "error" in caplog.text with ( @@ -123,7 +142,7 @@ async def test_coordinator( await hass.async_block_till_done(wait_background_tasks=True) assert mock_data.call_count == 1 state = hass.states.get("sensor.nord_pool_se3_current_price") - assert state.state == "1.81645" + assert state.state == "1.16266" assert "error" in caplog.text with ( @@ -138,14 +157,14 @@ async def test_coordinator( await hass.async_block_till_done(wait_background_tasks=True) assert mock_data.call_count == 1 state = hass.states.get("sensor.nord_pool_se3_current_price") - assert state.state == "2.51265" + assert state.state == "1.90004" assert "Response error" in caplog.text freezer.tick(timedelta(hours=1)) async_fire_time_changed(hass) await hass.async_block_till_done() state = hass.states.get("sensor.nord_pool_se3_current_price") - assert state.state == "1.81983" + assert state.state == "3.42983" # Test manual polling hass.config_entries.async_update_entry( @@ -156,14 +175,14 @@ async def test_coordinator( async_fire_time_changed(hass) await hass.async_block_till_done() state = hass.states.get("sensor.nord_pool_se3_current_price") - assert state.state == "1.01177" + assert state.state == "1.42403" # Prices should update without any polling made (read from cache) freezer.tick(timedelta(hours=1)) async_fire_time_changed(hass) await hass.async_block_till_done() state = hass.states.get("sensor.nord_pool_se3_current_price") - assert state.state == "0.83553" + assert state.state == "1.1358" # Test manually updating the data with ( @@ -184,7 +203,7 @@ async def test_coordinator( async_fire_time_changed(hass) await hass.async_block_till_done() state = hass.states.get("sensor.nord_pool_se3_current_price") - assert state.state == "0.79619" + assert state.state == "0.933" hass.config_entries.async_update_entry( entry=config_entry, pref_disable_polling=False diff --git a/tests/components/nordpool/test_diagnostics.py b/tests/components/nordpool/test_diagnostics.py index a9dfdd5eca587..d38e921afbbfa 100644 --- a/tests/components/nordpool/test_diagnostics.py +++ b/tests/components/nordpool/test_diagnostics.py @@ -12,7 +12,7 @@ from tests.typing import ClientSessionGenerator -@pytest.mark.freeze_time("2024-11-05T10:00:00+00:00") +@pytest.mark.freeze_time("2025-10-01T10:00:00+00:00") async def test_diagnostics( hass: HomeAssistant, hass_client: ClientSessionGenerator, diff --git a/tests/components/nordpool/test_init.py b/tests/components/nordpool/test_init.py index 48ddc59d083da..e2b16d37bd63d 100644 --- a/tests/components/nordpool/test_init.py +++ b/tests/components/nordpool/test_init.py @@ -28,7 +28,7 @@ from tests.test_util.aiohttp import AiohttpClientMocker -@pytest.mark.freeze_time("2024-11-05T10:00:00+00:00") +@pytest.mark.freeze_time("2025-10-01T10:00:00+00:00") async def test_unload_entry(hass: HomeAssistant, get_client: NordPoolClient) -> None: """Test load and unload an entry.""" entry = MockConfigEntry( @@ -79,7 +79,7 @@ async def test_initial_startup_fails( assert entry.state is ConfigEntryState.SETUP_RETRY -@pytest.mark.freeze_time("2024-11-05T10:00:00+00:00") +@pytest.mark.freeze_time("2025-10-01T10:00:00+00:00") async def test_reconfigure_cleans_up_device( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, @@ -115,7 +115,7 @@ async def test_reconfigure_cleans_up_device( "GET", url=API + "/DayAheadPrices", params={ - "date": "2024-11-04", + "date": "2025-09-30", "market": "DayAhead", "deliveryArea": "NL", "currency": "EUR", @@ -126,7 +126,7 @@ async def test_reconfigure_cleans_up_device( "GET", url=API + "/DayAheadPrices", params={ - "date": "2024-11-05", + "date": "2025-10-01", "market": "DayAhead", "deliveryArea": "NL", "currency": "EUR", @@ -137,7 +137,7 @@ async def test_reconfigure_cleans_up_device( "GET", url=API + "/DayAheadPrices", params={ - "date": "2024-11-06", + "date": "2025-10-02", "market": "DayAhead", "deliveryArea": "NL", "currency": "EUR", diff --git a/tests/components/nordpool/test_sensor.py b/tests/components/nordpool/test_sensor.py index 082684a2a02b4..cedcb57c95ecd 100644 --- a/tests/components/nordpool/test_sensor.py +++ b/tests/components/nordpool/test_sensor.py @@ -20,7 +20,7 @@ from tests.test_util.aiohttp import AiohttpClientMocker -@pytest.mark.freeze_time("2024-11-05T18:00:00+00:00") +@pytest.mark.freeze_time("2025-10-01T18:00:00+00:00") @pytest.mark.usefixtures("entity_registry_enabled_by_default") async def test_sensor( hass: HomeAssistant, @@ -33,7 +33,7 @@ async def test_sensor( await snapshot_platform(hass, entity_registry, snapshot, load_int.entry_id) -@pytest.mark.freeze_time("2024-11-05T18:00:00+00:00") +@pytest.mark.freeze_time("2025-10-01T18:00:00+00:00") @pytest.mark.usefixtures("entity_registry_enabled_by_default") async def test_sensor_current_price_is_0( hass: HomeAssistant, load_int: ConfigEntry @@ -43,10 +43,10 @@ async def test_sensor_current_price_is_0( current_price = hass.states.get("sensor.nord_pool_se4_current_price") assert current_price is not None - assert current_price.state == "0.0" # SE4 2024-11-05T18:00:00Z + assert current_price.state == "0.0" # SE4 2025-10-01T18:00:00Z -@pytest.mark.freeze_time("2024-11-05T23:00:00+00:00") +@pytest.mark.freeze_time("2025-10-01T21:45:00+00:00") @pytest.mark.usefixtures("entity_registry_enabled_by_default") async def test_sensor_no_next_price(hass: HomeAssistant, load_int: ConfigEntry) -> None: """Test the Nord Pool sensor.""" @@ -58,12 +58,12 @@ async def test_sensor_no_next_price(hass: HomeAssistant, load_int: ConfigEntry) assert current_price is not None assert last_price is not None assert next_price is not None - assert current_price.state == "0.12666" # SE3 2024-11-05T23:00:00Z - assert last_price.state == "0.28914" # SE3 2024-11-05T22:00:00Z - assert next_price.state == "0.07406" # SE3 2024-11-06T00:00:00Z" + assert current_price.state == "0.78568" # SE3 2025-10-01T21:45:00Z + assert last_price.state == "0.82171" # SE3 2025-10-01T21:30:00Z + assert next_price.state == "0.81174" # SE3 2025-10-01T22:00:00Z -@pytest.mark.freeze_time("2024-11-06T00:00:00+01:00") +@pytest.mark.freeze_time("2025-10-02T00:00:00+02:00") @pytest.mark.usefixtures("entity_registry_enabled_by_default") async def test_sensor_no_previous_price( hass: HomeAssistant, load_int: ConfigEntry @@ -77,12 +77,12 @@ async def test_sensor_no_previous_price( assert current_price is not None assert last_price is not None assert next_price is not None - assert current_price.state == "0.12666" # SE3 2024-11-05T23:00:00Z - assert last_price.state == "0.28914" # SE3 2024-11-05T22:00:00Z - assert next_price.state == "0.07406" # SE3 2024-11-06T00:00:00Z + assert current_price.state == "0.93322" # SE3 2025-10-01T22:00:00Z + assert last_price.state == "0.8605" # SE3 2025-10-01T21:45:00Z + assert next_price.state == "0.83513" # SE3 2025-10-01T22:15:00Z -@pytest.mark.freeze_time("2024-11-05T11:00:01+01:00") +@pytest.mark.freeze_time("2025-10-01T11:00:01+01:00") @pytest.mark.usefixtures("entity_registry_enabled_by_default") async def test_sensor_empty_response( hass: HomeAssistant, @@ -101,16 +101,16 @@ async def test_sensor_empty_response( assert current_price is not None assert last_price is not None assert next_price is not None - assert current_price.state == "0.92737" - assert last_price.state == "1.03132" - assert next_price.state == "0.92505" + assert current_price.state == "0.67405" + assert last_price.state == "0.8616" + assert next_price.state == "0.63736" aioclient_mock.clear_requests() aioclient_mock.request( "GET", url=API + "/DayAheadPrices", params={ - "date": "2024-11-04", + "date": "2025-09-30", "market": "DayAhead", "deliveryArea": "SE3,SE4", "currency": "SEK", @@ -121,7 +121,7 @@ async def test_sensor_empty_response( "GET", url=API + "/DayAheadPrices", params={ - "date": "2024-11-05", + "date": "2025-10-01", "market": "DayAhead", "deliveryArea": "SE3,SE4", "currency": "SEK", @@ -133,7 +133,7 @@ async def test_sensor_empty_response( "GET", url=API + "/DayAheadPrices", params={ - "date": "2024-11-06", + "date": "2025-10-02", "market": "DayAhead", "deliveryArea": "SE3,SE4", "currency": "SEK", @@ -153,16 +153,16 @@ async def test_sensor_empty_response( assert current_price is not None assert last_price is not None assert next_price is not None - assert current_price.state == "0.92505" - assert last_price.state == "0.92737" - assert next_price.state == "0.94949" + assert current_price.state == "0.63736" + assert last_price.state == "0.67405" + assert next_price.state == "0.62233" aioclient_mock.clear_requests() aioclient_mock.request( "GET", url=API + "/DayAheadPrices", params={ - "date": "2024-11-04", + "date": "2025-09-30", "market": "DayAhead", "deliveryArea": "SE3,SE4", "currency": "SEK", @@ -173,7 +173,7 @@ async def test_sensor_empty_response( "GET", url=API + "/DayAheadPrices", params={ - "date": "2024-11-05", + "date": "2025-10-01", "market": "DayAhead", "deliveryArea": "SE3,SE4", "currency": "SEK", @@ -185,7 +185,7 @@ async def test_sensor_empty_response( "GET", url=API + "/DayAheadPrices", params={ - "date": "2024-11-06", + "date": "2025-10-02", "market": "DayAhead", "deliveryArea": "SE3,SE4", "currency": "SEK", @@ -193,7 +193,7 @@ async def test_sensor_empty_response( status=HTTPStatus.NO_CONTENT, ) - freezer.move_to("2024-11-05T22:00:01+00:00") + freezer.move_to("2025-10-01T21:45:01+00:00") async_fire_time_changed(hass) await hass.async_block_till_done(wait_background_tasks=True) @@ -206,6 +206,6 @@ async def test_sensor_empty_response( assert current_price is not None assert last_price is not None assert next_price is not None - assert current_price.state == "0.28914" - assert last_price.state == "0.5223" + assert current_price.state == "0.78568" + assert last_price.state == "0.82171" assert next_price.state == STATE_UNKNOWN diff --git a/tests/components/nordpool/test_services.py b/tests/components/nordpool/test_services.py index 1042783fee8cb..9d940af4ad77a 100644 --- a/tests/components/nordpool/test_services.py +++ b/tests/components/nordpool/test_services.py @@ -30,31 +30,31 @@ TEST_SERVICE_DATA = { ATTR_CONFIG_ENTRY: "to_replace", - ATTR_DATE: "2024-11-05", + ATTR_DATE: "2025-10-01", ATTR_AREAS: "SE3", ATTR_CURRENCY: "EUR", } TEST_SERVICE_DATA_USE_DEFAULTS = { ATTR_CONFIG_ENTRY: "to_replace", - ATTR_DATE: "2024-11-05", + ATTR_DATE: "2025-10-01", } TEST_SERVICE_INDICES_DATA_60 = { ATTR_CONFIG_ENTRY: "to_replace", - ATTR_DATE: "2025-07-06", + ATTR_DATE: "2025-10-01", ATTR_AREAS: "SE3", ATTR_CURRENCY: "SEK", ATTR_RESOLUTION: 60, } TEST_SERVICE_INDICES_DATA_15 = { ATTR_CONFIG_ENTRY: "to_replace", - ATTR_DATE: "2025-07-06", + ATTR_DATE: "2025-10-01", ATTR_AREAS: "SE3", ATTR_CURRENCY: "SEK", ATTR_RESOLUTION: 15, } -@pytest.mark.freeze_time("2024-11-05T18:00:00+00:00") +@pytest.mark.freeze_time("2025-10-01T18:00:00+00:00") async def test_service_call( hass: HomeAssistant, load_int: MockConfigEntry, @@ -96,7 +96,7 @@ async def test_service_call( (NordPoolError, "connection_error"), ], ) -@pytest.mark.freeze_time("2024-11-05T18:00:00+00:00") +@pytest.mark.freeze_time("2025-10-01T18:00:00+00:00") async def test_service_call_failures( hass: HomeAssistant, load_int: MockConfigEntry, @@ -124,7 +124,7 @@ async def test_service_call_failures( assert err.value.translation_key == key -@pytest.mark.freeze_time("2024-11-05T18:00:00+00:00") +@pytest.mark.freeze_time("2025-10-01T18:00:00+00:00") async def test_empty_response_returns_empty_list( hass: HomeAssistant, load_int: MockConfigEntry, @@ -151,7 +151,7 @@ async def test_empty_response_returns_empty_list( assert response == snapshot -@pytest.mark.freeze_time("2024-11-05T18:00:00+00:00") +@pytest.mark.freeze_time("2025-10-01T18:00:00+00:00") async def test_service_call_config_entry_bad_state( hass: HomeAssistant, load_int: MockConfigEntry, @@ -184,7 +184,7 @@ async def test_service_call_config_entry_bad_state( assert err.value.translation_key == "entry_not_loaded" -@pytest.mark.freeze_time("2024-11-05T18:00:00+00:00") +@pytest.mark.freeze_time("2025-10-01T18:00:00+00:00") async def test_service_call_for_price_indices( hass: HomeAssistant, load_int: MockConfigEntry, @@ -200,7 +200,7 @@ async def test_service_call_for_price_indices( "GET", url=API + "/DayAheadPriceIndices", params={ - "date": "2025-07-06", + "date": "2025-10-01", "market": "DayAhead", "indexNames": "SE3", "currency": "SEK", @@ -213,7 +213,7 @@ async def test_service_call_for_price_indices( "GET", url=API + "/DayAheadPriceIndices", params={ - "date": "2025-07-06", + "date": "2025-10-01", "market": "DayAhead", "indexNames": "SE3", "currency": "SEK", diff --git a/tests/components/recorder/common.py b/tests/components/recorder/common.py index 094ab11a112ef..0c1ad43823df2 100644 --- a/tests/components/recorder/common.py +++ b/tests/components/recorder/common.py @@ -16,6 +16,7 @@ from unittest.mock import MagicMock, patch, sentinel from freezegun import freeze_time +import pytest from sqlalchemy import create_engine, event as sqlalchemy_event from sqlalchemy.orm.session import Session @@ -583,3 +584,26 @@ def db_state_attributes_to_native(state_attrs: StateAttributes) -> dict[str, Any if shared_attrs is None: return {} return cast(dict[str, Any], json_loads(shared_attrs)) + + +async def async_drop_index( + recorder: Recorder, table: str, index: str, caplog: pytest.LogCaptureFixture +) -> None: + """Drop an index from the database. + + migration._drop_index does not return or raise, so we verify the result + by checking the log for success or failure messages. + """ + + finish_msg = f"Finished dropping index `{index}` from table `{table}`" + fail_msg = f"Failed to drop index `{index}` from table `{table}`" + + count_finish = caplog.text.count(finish_msg) + count_fail = caplog.text.count(fail_msg) + + await recorder.async_add_executor_job( + migration._drop_index, recorder.get_session, table, index + ) + + assert caplog.text.count(finish_msg) == count_finish + 1 + assert caplog.text.count(fail_msg) == count_fail diff --git a/tests/components/recorder/db_schema_42.py b/tests/components/recorder/db_schema_48.py similarity index 77% rename from tests/components/recorder/db_schema_42.py rename to tests/components/recorder/db_schema_48.py index b0cdecd88dc95..43587bd966db9 100644 --- a/tests/components/recorder/db_schema_42.py +++ b/tests/components/recorder/db_schema_48.py @@ -1,6 +1,6 @@ """Models for SQLAlchemy. -This file contains the model definitions for schema version 42. +This file contains the model definitions for schema version 48. It is used to test the schema migration logic. """ @@ -10,7 +10,7 @@ from datetime import datetime, timedelta import logging import time -from typing import Any, Self, cast +from typing import Any, Final, Self, cast import ciso8601 from fnv_hash_fast import fnv1a_32 @@ -64,7 +64,7 @@ MAX_LENGTH_STATE_ENTITY_ID, MAX_LENGTH_STATE_STATE, ) -from homeassistant.core import Context, Event, EventOrigin, State +from homeassistant.core import Context, Event, EventOrigin, EventStateChangedData, State from homeassistant.helpers.json import JSON_DUMP, json_bytes, json_bytes_strip_null from homeassistant.util import dt as dt_util from homeassistant.util.json import ( @@ -79,7 +79,11 @@ class Base(DeclarativeBase): """Base class for tables.""" -SCHEMA_VERSION = 42 +class LegacyBase(DeclarativeBase): + """Base class for tables, used for schema migration.""" + + +SCHEMA_VERSION = 48 _LOGGER = logging.getLogger(__name__) @@ -95,6 +99,7 @@ class Base(DeclarativeBase): TABLE_STATISTICS_META = "statistics_meta" TABLE_STATISTICS_RUNS = "statistics_runs" TABLE_STATISTICS_SHORT_TERM = "statistics_short_term" +TABLE_MIGRATION_CHANGES = "migration_changes" STATISTICS_TABLES = ("statistics", "statistics_short_term") @@ -111,6 +116,7 @@ class Base(DeclarativeBase): TABLE_EVENT_TYPES, TABLE_RECORDER_RUNS, TABLE_SCHEMA_CHANGES, + TABLE_MIGRATION_CHANGES, TABLE_STATES_META, TABLE_STATISTICS, TABLE_STATISTICS_META, @@ -130,7 +136,8 @@ class Base(DeclarativeBase): EVENTS_CONTEXT_ID_BIN_INDEX = "ix_events_context_id_bin" STATES_CONTEXT_ID_BIN_INDEX = "ix_states_context_id_bin" LEGACY_STATES_EVENT_ID_INDEX = "ix_states_event_id" -LEGACY_STATES_ENTITY_ID_LAST_UPDATED_INDEX = "ix_states_entity_id_last_updated_ts" +LEGACY_STATES_ENTITY_ID_LAST_UPDATED_TS_INDEX = "ix_states_entity_id_last_updated_ts" +LEGACY_MAX_LENGTH_EVENT_CONTEXT_ID: Final = 36 CONTEXT_ID_BIN_MAX_LENGTH = 16 MYSQL_COLLATE = "utf8mb4_unicode_ci" @@ -146,6 +153,13 @@ class Base(DeclarativeBase): "mariadb_engine": MYSQL_ENGINE, } +_MATCH_ALL_KEEP = { + ATTR_DEVICE_CLASS, + ATTR_STATE_CLASS, + ATTR_UNIT_OF_MEASUREMENT, + ATTR_FRIENDLY_NAME, +} + class UnusedDateTime(DateTime): """An unused column type that behaves like a datetime.""" @@ -155,14 +169,14 @@ class Unused(CHAR): """An unused column type that behaves like a string.""" -@compiles(UnusedDateTime, "mysql", "mariadb", "sqlite") # type: ignore[misc,no-untyped-call] -@compiles(Unused, "mysql", "mariadb", "sqlite") # type: ignore[misc,no-untyped-call] +@compiles(UnusedDateTime, "mysql", "mariadb", "sqlite") +@compiles(Unused, "mysql", "mariadb", "sqlite") def compile_char_zero(type_: TypeDecorator, compiler: Any, **kw: Any) -> str: """Compile UnusedDateTime and Unused as CHAR(0) on mysql, mariadb, and sqlite.""" return "CHAR(0)" # Uses 1 byte on MySQL (no change on sqlite) -@compiles(Unused, "postgresql") # type: ignore[misc,no-untyped-call] +@compiles(Unused, "postgresql") def compile_char_one(type_: TypeDecorator, compiler: Any, **kw: Any) -> str: """Compile Unused as CHAR(1) on postgresql.""" return "CHAR(1)" # Uses 1 byte @@ -184,6 +198,9 @@ def result_processor(self, dialect: Dialect, coltype: Any) -> Callable | None: return None +# Although all integers are same in SQLite, it does not allow an identity column to be BIGINT +# https://sqlite.org/forum/info/2dfa968a702e1506e885cb06d92157d492108b22bf39459506ab9f7125bca7fd +ID_TYPE = BigInteger().with_variant(sqlite.INTEGER, "sqlite") # For MariaDB and MySQL we can use an unsigned integer type since it will fit 2**32 # for sqlite and postgresql we use a bigint UINT_32_TYPE = BigInteger().with_variant( @@ -214,6 +231,7 @@ def result_processor(self, dialect: Dialect, coltype: Any) -> Callable | None: UNUSED_LEGACY_DATETIME_COLUMN = UnusedDateTime(timezone=True) UNUSED_LEGACY_INTEGER_COLUMN = SmallInteger() DOUBLE_PRECISION_TYPE_SQL = "DOUBLE PRECISION" +BIG_INTEGER_SQL = "BIGINT" CONTEXT_BINARY_TYPE = LargeBinary(CONTEXT_ID_BIN_MAX_LENGTH).with_variant( NativeLargeBinary(CONTEXT_ID_BIN_MAX_LENGTH), "mysql", "mariadb", "sqlite" ) @@ -235,7 +253,6 @@ def process(value: Any) -> str: EVENT_ORIGIN_ORDER = [EventOrigin.local, EventOrigin.remote] -EVENT_ORIGIN_TO_IDX = {origin: idx for idx, origin in enumerate(EVENT_ORIGIN_ORDER)} class Events(Base): @@ -256,7 +273,7 @@ class Events(Base): _DEFAULT_TABLE_ARGS, ) __tablename__ = TABLE_EVENTS - event_id: Mapped[int] = mapped_column(Integer, Identity(), primary_key=True) + event_id: Mapped[int] = mapped_column(ID_TYPE, Identity(), primary_key=True) event_type: Mapped[str | None] = mapped_column(UNUSED_LEGACY_COLUMN) event_data: Mapped[str | None] = mapped_column(UNUSED_LEGACY_COLUMN) origin: Mapped[str | None] = mapped_column(UNUSED_LEGACY_COLUMN) @@ -267,13 +284,13 @@ class Events(Base): context_user_id: Mapped[str | None] = mapped_column(UNUSED_LEGACY_COLUMN) context_parent_id: Mapped[str | None] = mapped_column(UNUSED_LEGACY_COLUMN) data_id: Mapped[int | None] = mapped_column( - Integer, ForeignKey("event_data.data_id"), index=True + ID_TYPE, ForeignKey("event_data.data_id"), index=True ) context_id_bin: Mapped[bytes | None] = mapped_column(CONTEXT_BINARY_TYPE) context_user_id_bin: Mapped[bytes | None] = mapped_column(CONTEXT_BINARY_TYPE) context_parent_id_bin: Mapped[bytes | None] = mapped_column(CONTEXT_BINARY_TYPE) event_type_id: Mapped[int | None] = mapped_column( - Integer, ForeignKey("event_types.event_type_id") + ID_TYPE, ForeignKey("event_types.event_type_id") ) event_data_rel: Mapped[EventData | None] = relationship("EventData") event_type_rel: Mapped[EventTypes | None] = relationship("EventTypes") @@ -302,18 +319,19 @@ def _time_fired_isotime(self) -> str | None: @staticmethod def from_event(event: Event) -> Events: """Create an event database object from a native event.""" + context = event.context return Events( event_type=None, event_data=None, - origin_idx=EVENT_ORIGIN_TO_IDX.get(event.origin), + origin_idx=event.origin.idx, time_fired=None, time_fired_ts=event.time_fired_timestamp, context_id=None, - context_id_bin=ulid_to_bytes_or_none(event.context.id), + context_id_bin=ulid_to_bytes_or_none(context.id), context_user_id=None, - context_user_id_bin=uuid_hex_to_bytes_or_none(event.context.user_id), + context_user_id_bin=uuid_hex_to_bytes_or_none(context.user_id), context_parent_id=None, - context_parent_id_bin=ulid_to_bytes_or_none(event.context.parent_id), + context_parent_id_bin=ulid_to_bytes_or_none(context.parent_id), ) def to_native(self, validate_entity_id: bool = True) -> Event | None: @@ -330,7 +348,7 @@ def to_native(self, validate_entity_id: bool = True) -> Event | None: EventOrigin(self.origin) if self.origin else EVENT_ORIGIN_ORDER[self.origin_idx or 0], - dt_util.utc_from_timestamp(self.time_fired_ts or 0), + self.time_fired_ts or 0, context=context, ) except JSON_DECODE_EXCEPTIONS: @@ -339,12 +357,23 @@ def to_native(self, validate_entity_id: bool = True) -> Event | None: return None +class LegacyEvents(LegacyBase): + """Event history data with event_id, used for schema migration.""" + + __table_args__ = (_DEFAULT_TABLE_ARGS,) + __tablename__ = TABLE_EVENTS + event_id: Mapped[int] = mapped_column(ID_TYPE, Identity(), primary_key=True) + context_id: Mapped[str | None] = mapped_column( + String(LEGACY_MAX_LENGTH_EVENT_CONTEXT_ID), index=True + ) + + class EventData(Base): """Event data history.""" __table_args__ = (_DEFAULT_TABLE_ARGS,) __tablename__ = TABLE_EVENT_DATA - data_id: Mapped[int] = mapped_column(Integer, Identity(), primary_key=True) + data_id: Mapped[int] = mapped_column(ID_TYPE, Identity(), primary_key=True) hash: Mapped[int | None] = mapped_column(UINT_32_TYPE, index=True) # Note that this is not named attributes to avoid confusion with the states table shared_data: Mapped[str | None] = mapped_column( @@ -364,9 +393,8 @@ def shared_data_bytes_from_event( event: Event, dialect: SupportedDialect | None ) -> bytes: """Create shared_data from an event.""" - if dialect == SupportedDialect.POSTGRESQL: - bytes_result = json_bytes_strip_null(event.data) - bytes_result = json_bytes(event.data) + encoder = json_bytes_strip_null if dialect == PSQL_DIALECT else json_bytes + bytes_result = encoder(event.data) if len(bytes_result) > MAX_EVENT_DATA_BYTES: _LOGGER.warning( "Event data for %s exceed maximum size of %s bytes. " @@ -400,7 +428,7 @@ class EventTypes(Base): __table_args__ = (_DEFAULT_TABLE_ARGS,) __tablename__ = TABLE_EVENT_TYPES - event_type_id: Mapped[int] = mapped_column(Integer, Identity(), primary_key=True) + event_type_id: Mapped[int] = mapped_column(ID_TYPE, Identity(), primary_key=True) event_type: Mapped[str | None] = mapped_column( String(MAX_LENGTH_EVENT_EVENT_TYPE), index=True, unique=True ) @@ -430,22 +458,23 @@ class States(Base): _DEFAULT_TABLE_ARGS, ) __tablename__ = TABLE_STATES - state_id: Mapped[int] = mapped_column(Integer, Identity(), primary_key=True) + state_id: Mapped[int] = mapped_column(ID_TYPE, Identity(), primary_key=True) entity_id: Mapped[str | None] = mapped_column(UNUSED_LEGACY_COLUMN) state: Mapped[str | None] = mapped_column(String(MAX_LENGTH_STATE_STATE)) attributes: Mapped[str | None] = mapped_column(UNUSED_LEGACY_COLUMN) event_id: Mapped[int | None] = mapped_column(UNUSED_LEGACY_INTEGER_COLUMN) last_changed: Mapped[datetime | None] = mapped_column(UNUSED_LEGACY_DATETIME_COLUMN) last_changed_ts: Mapped[float | None] = mapped_column(TIMESTAMP_TYPE) + last_reported_ts: Mapped[float | None] = mapped_column(TIMESTAMP_TYPE) last_updated: Mapped[datetime | None] = mapped_column(UNUSED_LEGACY_DATETIME_COLUMN) last_updated_ts: Mapped[float | None] = mapped_column( TIMESTAMP_TYPE, default=time.time, index=True ) old_state_id: Mapped[int | None] = mapped_column( - Integer, ForeignKey("states.state_id"), index=True + ID_TYPE, ForeignKey("states.state_id"), index=True ) attributes_id: Mapped[int | None] = mapped_column( - Integer, ForeignKey("state_attributes.attributes_id"), index=True + ID_TYPE, ForeignKey("state_attributes.attributes_id"), index=True ) context_id: Mapped[str | None] = mapped_column(UNUSED_LEGACY_COLUMN) context_user_id: Mapped[str | None] = mapped_column(UNUSED_LEGACY_COLUMN) @@ -459,7 +488,7 @@ class States(Base): context_user_id_bin: Mapped[bytes | None] = mapped_column(CONTEXT_BINARY_TYPE) context_parent_id_bin: Mapped[bytes | None] = mapped_column(CONTEXT_BINARY_TYPE) metadata_id: Mapped[int | None] = mapped_column( - Integer, ForeignKey("states_meta.metadata_id") + ID_TYPE, ForeignKey("states_meta.metadata_id") ) states_meta_rel: Mapped[StatesMeta | None] = relationship("StatesMeta") @@ -486,37 +515,44 @@ def _last_updated_isotime(self) -> str | None: return date_time.isoformat(sep=" ", timespec="seconds") @staticmethod - def from_event(event: Event) -> States: + def from_event(event: Event[EventStateChangedData]) -> States: """Create object from a state_changed event.""" - state: State | None = event.data.get("new_state") - dbstate = States( - entity_id=None, + state = event.data["new_state"] + # None state means the state was removed from the state machine + if state is None: + state_value = "" + last_updated_ts = event.time_fired_timestamp + last_changed_ts = None + last_reported_ts = None + else: + state_value = state.state + last_updated_ts = state.last_updated_timestamp + if state.last_updated == state.last_changed: + last_changed_ts = None + else: + last_changed_ts = state.last_changed_timestamp + if state.last_updated == state.last_reported: + last_reported_ts = None + else: + last_reported_ts = state.last_reported_timestamp + context = event.context + return States( + state=state_value, + entity_id=event.data["entity_id"], attributes=None, context_id=None, - context_id_bin=ulid_to_bytes_or_none(event.context.id), + context_id_bin=ulid_to_bytes_or_none(context.id), context_user_id=None, - context_user_id_bin=uuid_hex_to_bytes_or_none(event.context.user_id), + context_user_id_bin=uuid_hex_to_bytes_or_none(context.user_id), context_parent_id=None, - context_parent_id_bin=ulid_to_bytes_or_none(event.context.parent_id), - origin_idx=EVENT_ORIGIN_TO_IDX.get(event.origin), + context_parent_id_bin=ulid_to_bytes_or_none(context.parent_id), + origin_idx=event.origin.idx, last_updated=None, last_changed=None, + last_updated_ts=last_updated_ts, + last_changed_ts=last_changed_ts, + last_reported_ts=last_reported_ts, ) - # None state means the state was removed from the state machine - if state is None: - dbstate.state = "" - dbstate.last_updated_ts = event.time_fired_timestamp - dbstate.last_changed_ts = None - return dbstate - - dbstate.state = state.state - dbstate.last_updated_ts = state.last_updated_timestamp - if state.last_updated == state.last_changed: - dbstate.last_changed_ts = None - else: - dbstate.last_changed_ts = state.last_changed_timestamp - - return dbstate def to_native(self, validate_entity_id: bool = True) -> State | None: """Convert to an HA state object.""" @@ -531,32 +567,60 @@ def to_native(self, validate_entity_id: bool = True) -> State | None: # When json_loads fails _LOGGER.exception("Error converting row to state: %s", self) return None + last_updated = dt_util.utc_from_timestamp(self.last_updated_ts or 0) if self.last_changed_ts is None or self.last_changed_ts == self.last_updated_ts: - last_changed = last_updated = dt_util.utc_from_timestamp( - self.last_updated_ts or 0 - ) + last_changed = dt_util.utc_from_timestamp(self.last_updated_ts or 0) else: - last_updated = dt_util.utc_from_timestamp(self.last_updated_ts or 0) last_changed = dt_util.utc_from_timestamp(self.last_changed_ts or 0) + if ( + self.last_reported_ts is None + or self.last_reported_ts == self.last_updated_ts + ): + last_reported = dt_util.utc_from_timestamp(self.last_updated_ts or 0) + else: + last_reported = dt_util.utc_from_timestamp(self.last_reported_ts or 0) return State( self.entity_id or "", self.state, # type: ignore[arg-type] # Join the state_attributes table on attributes_id to get the attributes # for newer states attrs, - last_changed, - last_updated, + last_changed=last_changed, + last_reported=last_reported, + last_updated=last_updated, context=context, validate_entity_id=validate_entity_id, ) +class LegacyStates(LegacyBase): + """State change history with entity_id, used for schema migration.""" + + __table_args__ = ( + Index( + LEGACY_STATES_ENTITY_ID_LAST_UPDATED_TS_INDEX, + "entity_id", + "last_updated_ts", + ), + _DEFAULT_TABLE_ARGS, + ) + __tablename__ = TABLE_STATES + state_id: Mapped[int] = mapped_column(ID_TYPE, Identity(), primary_key=True) + entity_id: Mapped[str | None] = mapped_column(UNUSED_LEGACY_COLUMN) + last_updated_ts: Mapped[float | None] = mapped_column( + TIMESTAMP_TYPE, default=time.time, index=True + ) + context_id: Mapped[str | None] = mapped_column( + String(LEGACY_MAX_LENGTH_EVENT_CONTEXT_ID), index=True + ) + + class StateAttributes(Base): """State attribute change history.""" __table_args__ = (_DEFAULT_TABLE_ARGS,) __tablename__ = TABLE_STATE_ATTRIBUTES - attributes_id: Mapped[int] = mapped_column(Integer, Identity(), primary_key=True) + attributes_id: Mapped[int] = mapped_column(ID_TYPE, Identity(), primary_key=True) hash: Mapped[int | None] = mapped_column(UINT_32_TYPE, index=True) # Note that this is not named attributes to avoid confusion with the states table shared_attrs: Mapped[str | None] = mapped_column( @@ -572,13 +636,12 @@ def __repr__(self) -> str: @staticmethod def shared_attrs_bytes_from_event( - event: Event, + event: Event[EventStateChangedData], dialect: SupportedDialect | None, ) -> bytes: """Create shared_attrs from a state_changed event.""" - state: State | None = event.data.get("new_state") # None state means the state was removed from the state machine - if state is None: + if (state := event.data["new_state"]) is None: return b"{}" if state_info := state.state_info: unrecorded_attributes = state_info["unrecorded_attributes"] @@ -589,19 +652,8 @@ def shared_attrs_bytes_from_event( if MATCH_ALL in unrecorded_attributes: # Don't exclude device class, state class, unit of measurement # or friendly name when using the MATCH_ALL exclude constant - _exclude_attributes = { - k: v - for k, v in state.attributes.items() - if k - not in ( - ATTR_DEVICE_CLASS, - ATTR_STATE_CLASS, - ATTR_UNIT_OF_MEASUREMENT, - ATTR_FRIENDLY_NAME, - ) - } - exclude_attrs.update(_exclude_attributes) - + exclude_attrs.update(state.attributes) + exclude_attrs -= _MATCH_ALL_KEEP else: exclude_attrs = ALL_DOMAIN_EXCLUDE_ATTRS encoder = json_bytes_strip_null if dialect == PSQL_DIALECT else json_bytes @@ -642,7 +694,7 @@ class StatesMeta(Base): __table_args__ = (_DEFAULT_TABLE_ARGS,) __tablename__ = TABLE_STATES_META - metadata_id: Mapped[int] = mapped_column(Integer, Identity(), primary_key=True) + metadata_id: Mapped[int] = mapped_column(ID_TYPE, Identity(), primary_key=True) entity_id: Mapped[str | None] = mapped_column( String(MAX_LENGTH_STATE_ENTITY_ID), index=True, unique=True ) @@ -659,11 +711,11 @@ def __repr__(self) -> str: class StatisticsBase: """Statistics base class.""" - id: Mapped[int] = mapped_column(Integer, Identity(), primary_key=True) + id: Mapped[int] = mapped_column(ID_TYPE, Identity(), primary_key=True) created: Mapped[datetime | None] = mapped_column(UNUSED_LEGACY_DATETIME_COLUMN) created_ts: Mapped[float | None] = mapped_column(TIMESTAMP_TYPE, default=time.time) metadata_id: Mapped[int | None] = mapped_column( - Integer, + ID_TYPE, ForeignKey(f"{TABLE_STATISTICS_META}.id", ondelete="CASCADE"), ) start: Mapped[datetime | None] = mapped_column(UNUSED_LEGACY_DATETIME_COLUMN) @@ -679,12 +731,14 @@ class StatisticsBase: duration: timedelta @classmethod - def from_stats(cls, metadata_id: int, stats: StatisticData) -> Self: - """Create object from a statistics with datatime objects.""" + def from_stats( + cls, metadata_id: int, stats: StatisticData, now_timestamp: float | None = None + ) -> Self: + """Create object from a statistics with datetime objects.""" return cls( # type: ignore[call-arg] metadata_id=metadata_id, created=None, - created_ts=time.time(), + created_ts=now_timestamp or time.time(), start=None, start_ts=stats["start"].timestamp(), mean=stats.get("mean"), @@ -697,12 +751,17 @@ def from_stats(cls, metadata_id: int, stats: StatisticData) -> Self: ) @classmethod - def from_stats_ts(cls, metadata_id: int, stats: StatisticDataTimestamp) -> Self: + def from_stats_ts( + cls, + metadata_id: int, + stats: StatisticDataTimestamp, + now_timestamp: float | None = None, + ) -> Self: """Create object from a statistics with timestamps.""" return cls( # type: ignore[call-arg] metadata_id=metadata_id, created=None, - created_ts=time.time(), + created_ts=now_timestamp or time.time(), start=None, start_ts=stats["start_ts"], mean=stats.get("mean"), @@ -728,15 +787,22 @@ class Statistics(Base, StatisticsBase): "start_ts", unique=True, ), + _DEFAULT_TABLE_ARGS, ) __tablename__ = TABLE_STATISTICS -class StatisticsShortTerm(Base, StatisticsBase): +class _StatisticsShortTerm(StatisticsBase): """Short term statistics.""" duration = timedelta(minutes=5) + __tablename__ = TABLE_STATISTICS_SHORT_TERM + + +class StatisticsShortTerm(Base, _StatisticsShortTerm): + """Short term statistics.""" + __table_args__ = ( # Used for fetching statistics for a certain entity at a specific time Index( @@ -745,16 +811,37 @@ class StatisticsShortTerm(Base, StatisticsBase): "start_ts", unique=True, ), + _DEFAULT_TABLE_ARGS, + ) + + +class LegacyStatisticsShortTerm(LegacyBase, _StatisticsShortTerm): + """Short term statistics with 32-bit index, used for schema migration.""" + + __table_args__ = ( + # Used for fetching statistics for a certain entity at a specific time + Index( + "ix_statistics_short_term_statistic_id_start_ts", + "metadata_id", + "start_ts", + unique=True, + ), + _DEFAULT_TABLE_ARGS, ) - __tablename__ = TABLE_STATISTICS_SHORT_TERM + metadata_id: Mapped[int | None] = mapped_column( + Integer, + ForeignKey(f"{TABLE_STATISTICS_META}.id", ondelete="CASCADE"), + use_existing_column=True, + ) -class StatisticsMeta(Base): + +class _StatisticsMeta: """Statistics meta data.""" __table_args__ = (_DEFAULT_TABLE_ARGS,) __tablename__ = TABLE_STATISTICS_META - id: Mapped[int] = mapped_column(Integer, Identity(), primary_key=True) + id: Mapped[int] = mapped_column(ID_TYPE, Identity(), primary_key=True) statistic_id: Mapped[str | None] = mapped_column( String(255), index=True, unique=True ) @@ -770,12 +857,30 @@ def from_meta(meta: StatisticMetaData) -> StatisticsMeta: return StatisticsMeta(**meta) +class StatisticsMeta(Base, _StatisticsMeta): + """Statistics meta data.""" + + +class LegacyStatisticsMeta(LegacyBase, _StatisticsMeta): + """Statistics meta data with 32-bit index, used for schema migration.""" + + id: Mapped[int] = mapped_column( + Integer, + Identity(), + primary_key=True, + use_existing_column=True, + ) + + class RecorderRuns(Base): """Representation of recorder run.""" - __table_args__ = (Index("ix_recorder_runs_start_end", "start", "end"),) + __table_args__ = ( + Index("ix_recorder_runs_start_end", "start", "end"), + _DEFAULT_TABLE_ARGS, + ) __tablename__ = TABLE_RECORDER_RUNS - run_id: Mapped[int] = mapped_column(Integer, Identity(), primary_key=True) + run_id: Mapped[int] = mapped_column(ID_TYPE, Identity(), primary_key=True) start: Mapped[datetime] = mapped_column(DATETIME_TYPE, default=dt_util.utcnow) end: Mapped[datetime | None] = mapped_column(DATETIME_TYPE) closed_incorrect: Mapped[bool] = mapped_column(Boolean, default=False) @@ -798,11 +903,23 @@ def to_native(self, validate_entity_id: bool = True) -> Self: return self +class MigrationChanges(Base): + """Representation of migration changes.""" + + __tablename__ = TABLE_MIGRATION_CHANGES + __table_args__ = (_DEFAULT_TABLE_ARGS,) + + migration_id: Mapped[str] = mapped_column(String(255), primary_key=True) + version: Mapped[int] = mapped_column(SmallInteger) + + class SchemaChanges(Base): """Representation of schema version changes.""" __tablename__ = TABLE_SCHEMA_CHANGES - change_id: Mapped[int] = mapped_column(Integer, Identity(), primary_key=True) + __table_args__ = (_DEFAULT_TABLE_ARGS,) + + change_id: Mapped[int] = mapped_column(ID_TYPE, Identity(), primary_key=True) schema_version: Mapped[int | None] = mapped_column(Integer) changed: Mapped[datetime] = mapped_column(DATETIME_TYPE, default=dt_util.utcnow) @@ -820,7 +937,9 @@ class StatisticsRuns(Base): """Representation of statistics run.""" __tablename__ = TABLE_STATISTICS_RUNS - run_id: Mapped[int] = mapped_column(Integer, Identity(), primary_key=True) + __table_args__ = (_DEFAULT_TABLE_ARGS,) + + run_id: Mapped[int] = mapped_column(ID_TYPE, Identity(), primary_key=True) start: Mapped[datetime] = mapped_column(DATETIME_TYPE, index=True) def __repr__(self) -> str: diff --git a/tests/components/recorder/test_history_db_schema_42.py b/tests/components/recorder/test_history_db_schema_42.py deleted file mode 100644 index 20d0c162d35e6..0000000000000 --- a/tests/components/recorder/test_history_db_schema_42.py +++ /dev/null @@ -1,1022 +0,0 @@ -"""The tests the History component.""" - -from __future__ import annotations - -from collections.abc import Generator -from copy import copy -from datetime import datetime, timedelta -import json -from unittest.mock import sentinel - -from freezegun import freeze_time -import pytest - -from homeassistant import core as ha -from homeassistant.components import recorder -from homeassistant.components.recorder import Recorder, history -from homeassistant.components.recorder.filters import Filters -from homeassistant.components.recorder.models import process_timestamp -from homeassistant.components.recorder.util import session_scope -from homeassistant.core import HomeAssistant, State -from homeassistant.helpers.json import JSONEncoder -from homeassistant.util import dt as dt_util - -from .common import ( - assert_dict_of_states_equal_without_context_and_last_changed, - assert_multiple_states_equal_without_context, - assert_multiple_states_equal_without_context_and_last_changed, - assert_states_equal_without_context, - async_recorder_block_till_done, - async_wait_recording_done, - old_db_schema, -) -from .db_schema_42 import StateAttributes, States, StatesMeta - -from tests.typing import RecorderInstanceContextManager - - -@pytest.fixture -async def mock_recorder_before_hass( - async_test_recorder: RecorderInstanceContextManager, -) -> None: - """Set up recorder.""" - - -@pytest.fixture(autouse=True) -def db_schema_42(hass: HomeAssistant) -> Generator[None]: - """Fixture to initialize the db with the old schema 42.""" - with old_db_schema(hass, "42"): - yield - - -@pytest.fixture(autouse=True) -def setup_recorder(db_schema_42, recorder_mock: Recorder) -> recorder.Recorder: - """Set up recorder.""" - - -async def test_get_full_significant_states_with_session_entity_no_matches( - hass: HomeAssistant, -) -> None: - """Test getting states at a specific point in time for entities that never have been recorded.""" - now = dt_util.utcnow() - time_before_recorder_ran = now - timedelta(days=1000) - with session_scope(hass=hass, read_only=True) as session: - assert ( - history.get_full_significant_states_with_session( - hass, session, time_before_recorder_ran, now, entity_ids=["demo.id"] - ) - == {} - ) - assert ( - history.get_full_significant_states_with_session( - hass, - session, - time_before_recorder_ran, - now, - entity_ids=["demo.id", "demo.id2"], - ) - == {} - ) - - -async def test_significant_states_with_session_entity_minimal_response_no_matches( - hass: HomeAssistant, -) -> None: - """Test getting states at a specific point in time for entities that never have been recorded.""" - now = dt_util.utcnow() - time_before_recorder_ran = now - timedelta(days=1000) - with session_scope(hass=hass, read_only=True) as session: - assert ( - history.get_significant_states_with_session( - hass, - session, - time_before_recorder_ran, - now, - entity_ids=["demo.id"], - minimal_response=True, - ) - == {} - ) - assert ( - history.get_significant_states_with_session( - hass, - session, - time_before_recorder_ran, - now, - entity_ids=["demo.id", "demo.id2"], - minimal_response=True, - ) - == {} - ) - - -async def test_significant_states_with_session_single_entity( - hass: HomeAssistant, -) -> None: - """Test get_significant_states_with_session with a single entity.""" - hass.states.async_set("demo.id", "any", {"attr": True}) - hass.states.async_set("demo.id", "any2", {"attr": True}) - await async_wait_recording_done(hass) - now = dt_util.utcnow() - with session_scope(hass=hass, read_only=True) as session: - states = history.get_significant_states_with_session( - hass, - session, - now - timedelta(days=1), - now, - entity_ids=["demo.id"], - minimal_response=False, - ) - assert len(states["demo.id"]) == 2 - - -@pytest.mark.parametrize( - ("attributes", "no_attributes", "limit"), - [ - ({"attr": True}, False, 5000), - ({}, True, 5000), - ({"attr": True}, False, 3), - ({}, True, 3), - ], -) -async def test_state_changes_during_period( - hass: HomeAssistant, attributes, no_attributes, limit -) -> None: - """Test state change during period.""" - entity_id = "media_player.test" - - def set_state(state): - """Set the state.""" - hass.states.async_set(entity_id, state, attributes) - return hass.states.get(entity_id) - - start = dt_util.utcnow() - point = start + timedelta(seconds=1) - end = point + timedelta(seconds=1) - - with freeze_time(start) as freezer: - set_state("idle") - set_state("YouTube") - - freezer.move_to(point) - states = [ - set_state("idle"), - set_state("Netflix"), - set_state("Plex"), - set_state("YouTube"), - ] - - freezer.move_to(end) - set_state("Netflix") - set_state("Plex") - await async_wait_recording_done(hass) - - hist = history.state_changes_during_period( - hass, start, end, entity_id, no_attributes, limit=limit - ) - - assert_multiple_states_equal_without_context(states[:limit], hist[entity_id]) - - -async def test_state_changes_during_period_last_reported( - hass: HomeAssistant, -) -> None: - """Test state change during period.""" - entity_id = "media_player.test" - - def set_state(state): - """Set the state.""" - hass.states.async_set(entity_id, state) - return ha.State.from_dict(hass.states.get(entity_id).as_dict()) - - start = dt_util.utcnow() - point1 = start + timedelta(seconds=1) - point2 = point1 + timedelta(seconds=1) - end = point2 + timedelta(seconds=1) - - with freeze_time(start) as freezer: - set_state("idle") - - freezer.move_to(point1) - states = [set_state("YouTube")] - - freezer.move_to(point2) - set_state("YouTube") - - freezer.move_to(end) - set_state("Netflix") - await async_wait_recording_done(hass) - - hist = history.state_changes_during_period(hass, start, end, entity_id) - - assert_multiple_states_equal_without_context(states, hist[entity_id]) - - -async def test_state_changes_during_period_descending( - hass: HomeAssistant, -) -> None: - """Test state change during period descending.""" - entity_id = "media_player.test" - - def set_state(state): - """Set the state.""" - hass.states.async_set(entity_id, state, {"any": 1}) - return hass.states.get(entity_id) - - start = dt_util.utcnow().replace(microsecond=0) - point = start + timedelta(seconds=1) - point2 = start + timedelta(seconds=1, microseconds=100) - point3 = start + timedelta(seconds=1, microseconds=200) - point4 = start + timedelta(seconds=1, microseconds=300) - end = point + timedelta(seconds=1, microseconds=400) - - with freeze_time(start) as freezer: - set_state("idle") - set_state("YouTube") - - freezer.move_to(point) - states = [set_state("idle")] - - freezer.move_to(point2) - states.append(set_state("Netflix")) - - freezer.move_to(point3) - states.append(set_state("Plex")) - - freezer.move_to(point4) - states.append(set_state("YouTube")) - - freezer.move_to(end) - set_state("Netflix") - set_state("Plex") - await async_wait_recording_done(hass) - - hist = history.state_changes_during_period( - hass, start, end, entity_id, no_attributes=False, descending=False - ) - - assert_multiple_states_equal_without_context(states, hist[entity_id]) - - hist = history.state_changes_during_period( - hass, start, end, entity_id, no_attributes=False, descending=True - ) - assert_multiple_states_equal_without_context( - states, list(reversed(list(hist[entity_id]))) - ) - - start_time = point2 + timedelta(microseconds=10) - hist = history.state_changes_during_period( - hass, - start_time, # Pick a point where we will generate a start time state - end, - entity_id, - no_attributes=False, - descending=True, - include_start_time_state=True, - ) - hist_states = list(hist[entity_id]) - assert hist_states[-1].last_updated == start_time - assert hist_states[-1].last_changed == start_time - assert len(hist_states) == 3 - # Make sure they are in descending order - assert ( - hist_states[0].last_updated - > hist_states[1].last_updated - > hist_states[2].last_updated - ) - assert ( - hist_states[0].last_changed - > hist_states[1].last_changed - > hist_states[2].last_changed - ) - hist = history.state_changes_during_period( - hass, - start_time, # Pick a point where we will generate a start time state - end, - entity_id, - no_attributes=False, - descending=False, - include_start_time_state=True, - ) - hist_states = list(hist[entity_id]) - assert hist_states[0].last_updated == start_time - assert hist_states[0].last_changed == start_time - assert len(hist_states) == 3 - # Make sure they are in ascending order - assert ( - hist_states[0].last_updated - < hist_states[1].last_updated - < hist_states[2].last_updated - ) - assert ( - hist_states[0].last_changed - < hist_states[1].last_changed - < hist_states[2].last_changed - ) - - -async def test_get_last_state_changes(hass: HomeAssistant) -> None: - """Test number of state changes.""" - entity_id = "sensor.test" - - def set_state(state): - """Set the state.""" - hass.states.async_set(entity_id, state) - return hass.states.get(entity_id) - - start = dt_util.utcnow() - timedelta(minutes=2) - point = start + timedelta(minutes=1) - point2 = point + timedelta(minutes=1, seconds=1) - states = [] - - with freeze_time(start) as freezer: - set_state("1") - - freezer.move_to(point) - states.append(set_state("2")) - - freezer.move_to(point2) - states.append(set_state("3")) - await async_wait_recording_done(hass) - - hist = history.get_last_state_changes(hass, 2, entity_id) - - assert_multiple_states_equal_without_context(states, hist[entity_id]) - - -async def test_get_last_state_changes_last_reported( - hass: HomeAssistant, -) -> None: - """Test number of state changes.""" - entity_id = "sensor.test" - - def set_state(state): - """Set the state.""" - hass.states.async_set(entity_id, state) - return ha.State.from_dict(hass.states.get(entity_id).as_dict()) - - start = dt_util.utcnow() - timedelta(minutes=2) - point = start + timedelta(minutes=1) - point2 = point + timedelta(minutes=1, seconds=1) - states = [] - - with freeze_time(start) as freezer: - states.append(set_state("1")) - - freezer.move_to(point) - set_state("1") - - freezer.move_to(point2) - states.append(set_state("2")) - await async_wait_recording_done(hass) - - hist = history.get_last_state_changes(hass, 2, entity_id) - - assert_multiple_states_equal_without_context(states, hist[entity_id]) - - -async def test_get_last_state_change(hass: HomeAssistant) -> None: - """Test getting the last state change for an entity.""" - entity_id = "sensor.test" - - def set_state(state): - """Set the state.""" - hass.states.async_set(entity_id, state) - return hass.states.get(entity_id) - - start = dt_util.utcnow() - timedelta(minutes=2) - point = start + timedelta(minutes=1) - point2 = point + timedelta(minutes=1, seconds=1) - states = [] - - with freeze_time(start) as freezer: - set_state("1") - - freezer.move_to(point) - set_state("2") - - freezer.move_to(point2) - states.append(set_state("3")) - await async_wait_recording_done(hass) - - hist = history.get_last_state_changes(hass, 1, entity_id) - - assert_multiple_states_equal_without_context(states, hist[entity_id]) - - -async def test_ensure_state_can_be_copied( - hass: HomeAssistant, -) -> None: - """Ensure a state can pass though copy(). - - The filter integration uses copy() on states - from history. - """ - entity_id = "sensor.test" - - def set_state(state): - """Set the state.""" - hass.states.async_set(entity_id, state) - return hass.states.get(entity_id) - - start = dt_util.utcnow() - timedelta(minutes=2) - point = start + timedelta(minutes=1) - - with freeze_time(start) as freezer: - set_state("1") - - freezer.move_to(point) - set_state("2") - await async_wait_recording_done(hass) - - hist = history.get_last_state_changes(hass, 2, entity_id) - - assert_states_equal_without_context(copy(hist[entity_id][0]), hist[entity_id][0]) - assert_states_equal_without_context(copy(hist[entity_id][1]), hist[entity_id][1]) - - -async def test_get_significant_states(hass: HomeAssistant) -> None: - """Test that only significant states are returned. - - We should get back every thermostat change that - includes an attribute change, but only the state updates for - media player (attribute changes are not significant and not returned). - """ - zero, four, states = record_states(hass) - await async_wait_recording_done(hass) - - hist = history.get_significant_states(hass, zero, four, entity_ids=list(states)) - assert_dict_of_states_equal_without_context_and_last_changed(states, hist) - - -async def test_get_significant_states_minimal_response( - hass: HomeAssistant, -) -> None: - """Test that only significant states are returned. - - When minimal responses is set only the first and - last states return a complete state. - - We should get back every thermostat change that - includes an attribute change, but only the state updates for - media player (attribute changes are not significant and not returned). - """ - zero, four, states = record_states(hass) - await async_wait_recording_done(hass) - - hist = history.get_significant_states( - hass, zero, four, minimal_response=True, entity_ids=list(states) - ) - entites_with_reducable_states = [ - "media_player.test", - "media_player.test3", - ] - - # All states for media_player.test state are reduced - # down to last_changed and state when minimal_response - # is set except for the first state. - # is set. We use JSONEncoder to make sure that are - # pre-encoded last_changed is always the same as what - # will happen with encoding a native state - for entity_id in entites_with_reducable_states: - entity_states = states[entity_id] - for state_idx in range(1, len(entity_states)): - input_state = entity_states[state_idx] - orig_last_changed = json.dumps( - process_timestamp(input_state.last_changed), - cls=JSONEncoder, - ).replace('"', "") - orig_state = input_state.state - entity_states[state_idx] = { - "last_changed": orig_last_changed, - "state": orig_state, - } - - assert len(hist) == len(states) - assert_states_equal_without_context( - states["media_player.test"][0], hist["media_player.test"][0] - ) - assert states["media_player.test"][1] == hist["media_player.test"][1] - assert states["media_player.test"][2] == hist["media_player.test"][2] - - assert_multiple_states_equal_without_context( - states["media_player.test2"], hist["media_player.test2"] - ) - assert_states_equal_without_context( - states["media_player.test3"][0], hist["media_player.test3"][0] - ) - assert states["media_player.test3"][1] == hist["media_player.test3"][1] - - assert_multiple_states_equal_without_context( - states["script.can_cancel_this_one"], hist["script.can_cancel_this_one"] - ) - assert_multiple_states_equal_without_context_and_last_changed( - states["thermostat.test"], hist["thermostat.test"] - ) - assert_multiple_states_equal_without_context_and_last_changed( - states["thermostat.test2"], hist["thermostat.test2"] - ) - - -@pytest.mark.parametrize("time_zone", ["Europe/Berlin", "US/Hawaii", "UTC"]) -async def test_get_significant_states_with_initial( - time_zone, hass: HomeAssistant -) -> None: - """Test that only significant states are returned. - - We should get back every thermostat change that - includes an attribute change, but only the state updates for - media player (attribute changes are not significant and not returned). - """ - await hass.config.async_set_time_zone(time_zone) - zero, four, states = record_states(hass) - await async_wait_recording_done(hass) - - one_and_half = zero + timedelta(seconds=1.5) - for entity_id in states: - if entity_id == "media_player.test": - states[entity_id] = states[entity_id][1:] - for state in states[entity_id]: - # If the state is recorded before the start time - # start it will have its last_updated and last_changed - # set to the start time. - if state.last_updated < one_and_half: - state.last_updated = one_and_half - state.last_changed = one_and_half - - hist = history.get_significant_states( - hass, one_and_half, four, include_start_time_state=True, entity_ids=list(states) - ) - assert_dict_of_states_equal_without_context_and_last_changed(states, hist) - - -async def test_get_significant_states_without_initial( - hass: HomeAssistant, -) -> None: - """Test that only significant states are returned. - - We should get back every thermostat change that - includes an attribute change, but only the state updates for - media player (attribute changes are not significant and not returned). - """ - zero, four, states = record_states(hass) - await async_wait_recording_done(hass) - - one = zero + timedelta(seconds=1) - one_with_microsecond = zero + timedelta(seconds=1, microseconds=1) - one_and_half = zero + timedelta(seconds=1.5) - for entity_id in states: - states[entity_id] = [ - s - for s in states[entity_id] - if s.last_changed not in (one, one_with_microsecond) - ] - del states["media_player.test2"] - del states["thermostat.test3"] - - hist = history.get_significant_states( - hass, - one_and_half, - four, - include_start_time_state=False, - entity_ids=list(states), - ) - assert_dict_of_states_equal_without_context_and_last_changed(states, hist) - - -async def test_get_significant_states_entity_id( - hass: HomeAssistant, -) -> None: - """Test that only significant states are returned for one entity.""" - zero, four, states = record_states(hass) - await async_wait_recording_done(hass) - - del states["media_player.test2"] - del states["media_player.test3"] - del states["thermostat.test"] - del states["thermostat.test2"] - del states["thermostat.test3"] - del states["script.can_cancel_this_one"] - - hist = history.get_significant_states(hass, zero, four, ["media_player.test"]) - assert_dict_of_states_equal_without_context_and_last_changed(states, hist) - - -async def test_get_significant_states_multiple_entity_ids( - hass: HomeAssistant, -) -> None: - """Test that only significant states are returned for one entity.""" - zero, four, states = record_states(hass) - await async_wait_recording_done(hass) - - hist = history.get_significant_states( - hass, - zero, - four, - ["media_player.test", "thermostat.test"], - ) - - assert_multiple_states_equal_without_context_and_last_changed( - states["media_player.test"], hist["media_player.test"] - ) - assert_multiple_states_equal_without_context_and_last_changed( - states["thermostat.test"], hist["thermostat.test"] - ) - - -async def test_get_significant_states_are_ordered( - hass: HomeAssistant, -) -> None: - """Test order of results from get_significant_states. - - When entity ids are given, the results should be returned with the data - in the same order. - """ - zero, four, _states = record_states(hass) - await async_wait_recording_done(hass) - - entity_ids = ["media_player.test", "media_player.test2"] - hist = history.get_significant_states(hass, zero, four, entity_ids) - assert list(hist.keys()) == entity_ids - entity_ids = ["media_player.test2", "media_player.test"] - hist = history.get_significant_states(hass, zero, four, entity_ids) - assert list(hist.keys()) == entity_ids - - -async def test_get_significant_states_only( - hass: HomeAssistant, -) -> None: - """Test significant states when significant_states_only is set.""" - entity_id = "sensor.test" - - def set_state(state, **kwargs): - """Set the state.""" - hass.states.async_set(entity_id, state, **kwargs) - return hass.states.get(entity_id) - - start = dt_util.utcnow() - timedelta(minutes=4) - points = [start + timedelta(minutes=i) for i in range(1, 4)] - - states = [] - with freeze_time(start) as freezer: - set_state("123", attributes={"attribute": 10.64}) - - freezer.move_to(points[0]) - # Attributes are different, state not - states.append(set_state("123", attributes={"attribute": 21.42})) - - freezer.move_to(points[1]) - # state is different, attributes not - states.append(set_state("32", attributes={"attribute": 21.42})) - - freezer.move_to(points[2]) - # everything is different - states.append(set_state("412", attributes={"attribute": 54.23})) - await async_wait_recording_done(hass) - - hist = history.get_significant_states( - hass, - start, - significant_changes_only=True, - entity_ids=list({state.entity_id for state in states}), - ) - - assert len(hist[entity_id]) == 2 - assert not any( - state.last_updated == states[0].last_updated for state in hist[entity_id] - ) - assert any( - state.last_updated == states[1].last_updated for state in hist[entity_id] - ) - assert any( - state.last_updated == states[2].last_updated for state in hist[entity_id] - ) - - hist = history.get_significant_states( - hass, - start, - significant_changes_only=False, - entity_ids=list({state.entity_id for state in states}), - ) - - assert len(hist[entity_id]) == 3 - assert_multiple_states_equal_without_context_and_last_changed( - states, hist[entity_id] - ) - - -async def test_get_significant_states_only_minimal_response( - hass: HomeAssistant, -) -> None: - """Test significant states when significant_states_only is True.""" - now = dt_util.utcnow() - await async_recorder_block_till_done(hass) - hass.states.async_set("sensor.test", "on", attributes={"any": "attr"}) - await async_recorder_block_till_done(hass) - hass.states.async_set("sensor.test", "off", attributes={"any": "attr"}) - await async_recorder_block_till_done(hass) - hass.states.async_set("sensor.test", "off", attributes={"any": "changed"}) - await async_recorder_block_till_done(hass) - hass.states.async_set("sensor.test", "off", attributes={"any": "again"}) - await async_recorder_block_till_done(hass) - hass.states.async_set("sensor.test", "on", attributes={"any": "attr"}) - await async_wait_recording_done(hass) - - hist = history.get_significant_states( - hass, - now, - minimal_response=True, - significant_changes_only=False, - entity_ids=["sensor.test"], - ) - assert len(hist["sensor.test"]) == 3 - - -def record_states( - hass: HomeAssistant, -) -> tuple[datetime, datetime, dict[str, list[State]]]: - """Record some test states. - - We inject a bunch of state updates from media player, zone and - thermostat. - """ - mp = "media_player.test" - mp2 = "media_player.test2" - mp3 = "media_player.test3" - therm = "thermostat.test" - therm2 = "thermostat.test2" - therm3 = "thermostat.test3" - zone = "zone.home" - script_c = "script.can_cancel_this_one" - - def set_state(entity_id, state, **kwargs): - """Set the state.""" - hass.states.async_set(entity_id, state, **kwargs) - return hass.states.get(entity_id) - - zero = dt_util.utcnow() - one = zero + timedelta(seconds=1) - two = one + timedelta(seconds=1) - three = two + timedelta(seconds=1) - four = three + timedelta(seconds=1) - - states = {therm: [], therm2: [], therm3: [], mp: [], mp2: [], mp3: [], script_c: []} - with freeze_time(one) as freezer: - states[mp].append( - set_state(mp, "idle", attributes={"media_title": str(sentinel.mt1)}) - ) - states[mp2].append( - set_state(mp2, "YouTube", attributes={"media_title": str(sentinel.mt2)}) - ) - states[mp3].append( - set_state(mp3, "idle", attributes={"media_title": str(sentinel.mt1)}) - ) - states[therm].append( - set_state(therm, 20, attributes={"current_temperature": 19.5}) - ) - # This state will be updated - set_state(therm3, 20, attributes={"current_temperature": 19.5}) - - freezer.move_to(one + timedelta(microseconds=1)) - states[mp].append( - set_state(mp, "YouTube", attributes={"media_title": str(sentinel.mt2)}) - ) - - freezer.move_to(two) - # This state will be skipped only different in time - set_state(mp, "YouTube", attributes={"media_title": str(sentinel.mt3)}) - # This state will be skipped because domain is excluded - set_state(zone, "zoning") - states[script_c].append( - set_state(script_c, "off", attributes={"can_cancel": True}) - ) - states[therm].append( - set_state(therm, 21, attributes={"current_temperature": 19.8}) - ) - states[therm2].append( - set_state(therm2, 20, attributes={"current_temperature": 19}) - ) - # This state will be updated - set_state(therm3, 20, attributes={"current_temperature": 19.5}) - - freezer.move_to(three) - states[mp].append( - set_state(mp, "Netflix", attributes={"media_title": str(sentinel.mt4)}) - ) - states[mp3].append( - set_state(mp3, "Netflix", attributes={"media_title": str(sentinel.mt3)}) - ) - # Attributes changed even though state is the same - states[therm].append( - set_state(therm, 21, attributes={"current_temperature": 20}) - ) - states[therm3].append( - set_state(therm3, 20, attributes={"current_temperature": 19.5}) - ) - - return zero, four, states - - -async def test_get_full_significant_states_handles_empty_last_changed( - hass: HomeAssistant, -) -> None: - """Test getting states when last_changed is null.""" - now = dt_util.utcnow() - hass.states.async_set("sensor.one", "on", {"attr": "original"}) - state0 = hass.states.get("sensor.one") - await hass.async_block_till_done() - hass.states.async_set("sensor.one", "on", {"attr": "new"}) - state1 = hass.states.get("sensor.one") - - assert state0.last_changed == state1.last_changed - assert state0.last_updated != state1.last_updated - await async_wait_recording_done(hass) - - def _get_entries(): - with session_scope(hass=hass, read_only=True) as session: - return history.get_full_significant_states_with_session( - hass, - session, - now, - dt_util.utcnow(), - entity_ids=["sensor.one"], - significant_changes_only=False, - ) - - states = await recorder.get_instance(hass).async_add_executor_job(_get_entries) - sensor_one_states: list[State] = states["sensor.one"] - assert_states_equal_without_context(sensor_one_states[0], state0) - assert_states_equal_without_context(sensor_one_states[1], state1) - assert sensor_one_states[0].last_changed == sensor_one_states[1].last_changed - assert sensor_one_states[0].last_updated != sensor_one_states[1].last_updated - - def _fetch_native_states() -> list[State]: - with session_scope(hass=hass, read_only=True) as session: - native_states = [] - db_state_attributes = { - state_attributes.attributes_id: state_attributes - for state_attributes in session.query(StateAttributes) - } - metadata_id_to_entity_id = { - states_meta.metadata_id: states_meta - for states_meta in session.query(StatesMeta) - } - for db_state in session.query(States): - db_state.entity_id = metadata_id_to_entity_id[ - db_state.metadata_id - ].entity_id - state = db_state.to_native() - state.attributes = db_state_attributes[ - db_state.attributes_id - ].to_native() - native_states.append(state) - return native_states - - native_sensor_one_states = await recorder.get_instance(hass).async_add_executor_job( - _fetch_native_states - ) - assert_states_equal_without_context(native_sensor_one_states[0], state0) - assert_states_equal_without_context(native_sensor_one_states[1], state1) - assert ( - native_sensor_one_states[0].last_changed - == native_sensor_one_states[1].last_changed - ) - assert ( - native_sensor_one_states[0].last_updated - != native_sensor_one_states[1].last_updated - ) - - def _fetch_db_states() -> list[States]: - with session_scope(hass=hass, read_only=True) as session: - states = list(session.query(States)) - session.expunge_all() - return states - - db_sensor_one_states = await recorder.get_instance(hass).async_add_executor_job( - _fetch_db_states - ) - assert db_sensor_one_states[0].last_changed is None - assert db_sensor_one_states[0].last_changed_ts is None - - assert ( - process_timestamp( - dt_util.utc_from_timestamp(db_sensor_one_states[1].last_changed_ts) - ) - == state0.last_changed - ) - assert db_sensor_one_states[0].last_updated_ts is not None - assert db_sensor_one_states[1].last_updated_ts is not None - assert ( - db_sensor_one_states[0].last_updated_ts - != db_sensor_one_states[1].last_updated_ts - ) - - -async def test_state_changes_during_period_multiple_entities_single_test( - hass: HomeAssistant, -) -> None: - """Test state change during period with multiple entities in the same test. - - This test ensures the sqlalchemy query cache does not - generate incorrect results. - """ - start = dt_util.utcnow() - test_entites = {f"sensor.{i}": str(i) for i in range(30)} - for entity_id, value in test_entites.items(): - hass.states.async_set(entity_id, value) - - await async_wait_recording_done(hass) - end = dt_util.utcnow() - - for entity_id, value in test_entites.items(): - hist = history.state_changes_during_period(hass, start, end, entity_id) - assert len(hist) == 1 - assert hist[entity_id][0].state == value - - -@pytest.mark.freeze_time("2039-01-19 03:14:07.555555-00:00") -async def test_get_full_significant_states_past_year_2038( - hass: HomeAssistant, -) -> None: - """Test we can store times past year 2038.""" - past_2038_time = dt_util.parse_datetime("2039-01-19 03:14:07.555555-00:00") - hass.states.async_set("sensor.one", "on", {"attr": "original"}) - state0 = hass.states.get("sensor.one") - await hass.async_block_till_done() - - hass.states.async_set("sensor.one", "on", {"attr": "new"}) - state1 = hass.states.get("sensor.one") - - await async_wait_recording_done(hass) - - def _get_entries(): - with session_scope(hass=hass, read_only=True) as session: - return history.get_full_significant_states_with_session( - hass, - session, - past_2038_time - timedelta(days=365), - past_2038_time + timedelta(days=365), - entity_ids=["sensor.one"], - significant_changes_only=False, - ) - - states = await recorder.get_instance(hass).async_add_executor_job(_get_entries) - sensor_one_states: list[State] = states["sensor.one"] - assert_states_equal_without_context(sensor_one_states[0], state0) - assert_states_equal_without_context(sensor_one_states[1], state1) - assert sensor_one_states[0].last_changed == past_2038_time - assert sensor_one_states[0].last_updated == past_2038_time - - -async def test_get_significant_states_without_entity_ids_raises( - hass: HomeAssistant, -) -> None: - """Test at least one entity id is required for get_significant_states.""" - now = dt_util.utcnow() - with pytest.raises(ValueError, match="entity_ids must be provided"): - history.get_significant_states(hass, now, None) - - -async def test_state_changes_during_period_without_entity_ids_raises( - hass: HomeAssistant, -) -> None: - """Test at least one entity id is required for state_changes_during_period.""" - now = dt_util.utcnow() - with pytest.raises(ValueError, match="entity_id must be provided"): - history.state_changes_during_period(hass, now, None) - - -async def test_get_significant_states_with_filters_raises( - hass: HomeAssistant, -) -> None: - """Test passing filters is no longer supported.""" - now = dt_util.utcnow() - with pytest.raises(NotImplementedError, match="Filters are no longer supported"): - history.get_significant_states( - hass, now, None, ["media_player.test"], Filters() - ) - - -async def test_get_significant_states_with_non_existent_entity_ids_returns_empty( - hass: HomeAssistant, -) -> None: - """Test get_significant_states returns an empty dict when entities not in the db.""" - now = dt_util.utcnow() - assert history.get_significant_states(hass, now, None, ["nonexistent.entity"]) == {} - - -async def test_state_changes_during_period_with_non_existent_entity_ids_returns_empty( - hass: HomeAssistant, -) -> None: - """Test state_changes_during_period returns an empty dict when entities not in the db.""" - now = dt_util.utcnow() - assert ( - history.state_changes_during_period(hass, now, None, "nonexistent.entity") == {} - ) - - -async def test_get_last_state_changes_with_non_existent_entity_ids_returns_empty( - hass: HomeAssistant, -) -> None: - """Test get_last_state_changes returns an empty dict when entities not in the db.""" - assert history.get_last_state_changes(hass, 1, "nonexistent.entity") == {} diff --git a/tests/components/recorder/test_migrate.py b/tests/components/recorder/test_migrate.py index fe0c7454ebd1e..74d319bcd97a4 100644 --- a/tests/components/recorder/test_migrate.py +++ b/tests/components/recorder/test_migrate.py @@ -107,7 +107,7 @@ async def test_schema_update_calls( schema_errors=set(), start_version=0, ), - 42, + 48, ), call( instance, @@ -115,7 +115,7 @@ async def test_schema_update_calls( engine, session_maker, migration.SchemaValidationStatus( - current_version=42, + current_version=48, initial_version=0, migration_needed=True, non_live_data_migration_needed=True, @@ -233,7 +233,7 @@ async def test_database_migration_failed( # Test error handling in _modify_columns (12, "sqlalchemy.engine.base.Connection.execute", False, 1, 0), # Test error handling in _drop_foreign_key_constraints - (46, "homeassistant.components.recorder.migration.DropConstraint", False, 2, 1), + (46, "homeassistant.components.recorder.migration.DropConstraint", False, 1, 0), ], ) @pytest.mark.skip_on_db_engine(["sqlite"]) @@ -560,7 +560,8 @@ async def test_events_during_migration_queue_exhausted( (18, False), (22, False), (25, False), - (43, True), + (43, False), + (48, True), ], ) async def test_schema_migrate( diff --git a/tests/components/recorder/test_migration_from_schema_32.py b/tests/components/recorder/test_migration_from_schema_32.py index 2a24b30b7f556..6554bb57183ef 100644 --- a/tests/components/recorder/test_migration_from_schema_32.py +++ b/tests/components/recorder/test_migration_from_schema_32.py @@ -46,6 +46,7 @@ from .common import ( async_attach_db_engine, + async_drop_index, async_recorder_block_till_done, async_wait_recording_done, get_patched_live_version, @@ -132,6 +133,7 @@ def db_schema_32(): async def test_migrate_events_context_ids( async_test_recorder: RecorderInstanceContextManager, indices_to_drop: list[tuple[str, str]], + caplog: pytest.LogCaptureFixture, ) -> None: """Test we can migrate old uuid context ids and ulid context ids to binary format.""" importlib.import_module(SCHEMA_MODULE_32) @@ -236,7 +238,6 @@ def _insert_events(): get_patched_live_version(old_db_schema), ), patch.object(migration.EventsContextIDMigration, "migrate_data"), - patch.object(migration.EventIDPostMigration, "migrate_data"), patch(CREATE_ENGINE_TARGET, new=_create_engine_test), ): async with ( @@ -257,7 +258,7 @@ def _insert_events(): for table, index in indices_to_drop: with session_scope(hass=hass) as session: assert get_index_by_name(session, table, index) is not None - migration._drop_index(instance.get_session, table, index) + await async_drop_index(instance, table, index, caplog) await hass.async_stop() await hass.async_block_till_done() @@ -294,7 +295,6 @@ def _fetch_migrated_events(): patch( "sqlalchemy.schema.Index.create", autospec=True, wraps=Index.create ) as wrapped_idx_create, - patch.object(migration.EventIDPostMigration, "migrate_data"), ): # Stall migration when the last non-live schema migration is done instrumented_migration.stall_on_schema_version = ( @@ -448,13 +448,6 @@ def _insert_migration(): get_patched_live_version(old_db_schema), ), patch.object(migration.EventsContextIDMigration, "migrate_data"), - patch.object( - migration.EventIDPostMigration, - "needs_migrate_impl", - return_value=migration.DataMigrationStatus( - needs_migrate=False, migration_done=True - ), - ), patch(CREATE_ENGINE_TARGET, new=_create_engine_test), ): async with ( @@ -534,6 +527,7 @@ def _insert_migration(): async def test_migrate_states_context_ids( async_test_recorder: RecorderInstanceContextManager, indices_to_drop: list[tuple[str, str]], + caplog: pytest.LogCaptureFixture, ) -> None: """Test we can migrate old uuid context ids and ulid context ids to binary format.""" importlib.import_module(SCHEMA_MODULE_32) @@ -620,7 +614,6 @@ def _insert_states(): get_patched_live_version(old_db_schema), ), patch.object(migration.StatesContextIDMigration, "migrate_data"), - patch.object(migration.EventIDPostMigration, "migrate_data"), patch(CREATE_ENGINE_TARGET, new=_create_engine_test), ): async with ( @@ -637,7 +630,7 @@ def _insert_states(): for table, index in indices_to_drop: with session_scope(hass=hass) as session: assert get_index_by_name(session, table, index) is not None - migration._drop_index(instance.get_session, table, index) + await async_drop_index(instance, table, index, caplog) await hass.async_stop() await hass.async_block_till_done() @@ -673,7 +666,6 @@ def _fetch_migrated_states(): patch( "sqlalchemy.schema.Index.create", autospec=True, wraps=Index.create ) as wrapped_idx_create, - patch.object(migration.EventIDPostMigration, "migrate_data"), ): # Stall migration when the last non-live schema migration is done instrumented_migration.stall_on_schema_version = ( @@ -831,13 +823,6 @@ def _insert_migration(): get_patched_live_version(old_db_schema), ), patch.object(migration.StatesContextIDMigration, "migrate_data"), - patch.object( - migration.EventIDPostMigration, - "needs_migrate_impl", - return_value=migration.DataMigrationStatus( - needs_migrate=False, migration_done=True - ), - ), patch(CREATE_ENGINE_TARGET, new=_create_engine_test), ): async with ( @@ -1152,6 +1137,7 @@ def _fetch_migrated_states(): async def test_post_migrate_entity_ids( async_test_recorder: RecorderInstanceContextManager, indices_to_drop: list[tuple[str, str]], + caplog: pytest.LogCaptureFixture, ) -> None: """Test we can migrate entity_ids to the StatesMeta table.""" importlib.import_module(SCHEMA_MODULE_32) @@ -1190,7 +1176,6 @@ def _insert_events(): ), patch.object(migration.EntityIDMigration, "migrate_data"), patch.object(migration.EntityIDPostMigration, "migrate_data"), - patch.object(migration.EventIDPostMigration, "migrate_data"), patch(CREATE_ENGINE_TARGET, new=_create_engine_test), ): async with ( @@ -1207,7 +1192,7 @@ def _insert_events(): for table, index in indices_to_drop: with session_scope(hass=hass) as session: assert get_index_by_name(session, table, index) is not None - migration._drop_index(instance.get_session, table, index) + await async_drop_index(instance, table, index, caplog) await hass.async_stop() await hass.async_block_till_done() @@ -1228,7 +1213,6 @@ def _fetch_migrated_states(): patch( "sqlalchemy.schema.Index.create", autospec=True, wraps=Index.create ) as wrapped_idx_create, - patch.object(migration.EventIDPostMigration, "migrate_data"), ): # Stall migration when the last non-live schema migration is done instrumented_migration.stall_on_schema_version = ( diff --git a/tests/components/recorder/test_v32_migration.py b/tests/components/recorder/test_v32_migration.py index ca7be224381e0..dd707ad6056e2 100644 --- a/tests/components/recorder/test_v32_migration.py +++ b/tests/components/recorder/test_v32_migration.py @@ -19,7 +19,11 @@ from homeassistant.core import Event, EventOrigin, State from homeassistant.util import dt as dt_util -from .common import async_wait_recording_done, get_patched_live_version +from .common import ( + async_drop_index, + async_wait_recording_done, + get_patched_live_version, +) from .conftest import instrument_migration from tests.common import async_test_home_assistant @@ -70,6 +74,7 @@ def _create_engine_test(*args, **kwargs): @pytest.mark.parametrize("enable_migrate_state_context_ids", [True]) @pytest.mark.parametrize("enable_migrate_event_type_ids", [True]) @pytest.mark.parametrize("enable_migrate_entity_ids", [True]) +@pytest.mark.parametrize("enable_migrate_event_ids", [True]) @pytest.mark.parametrize("persistent_database", [True]) @pytest.mark.usefixtures("hass_storage") # Prevent test hass from writing to storage async def test_migrate_times( @@ -242,6 +247,7 @@ def _get_events_index_names(): @pytest.mark.parametrize("enable_migrate_entity_ids", [True]) +@pytest.mark.parametrize("enable_migrate_event_ids", [True]) @pytest.mark.parametrize("persistent_database", [True]) @pytest.mark.usefixtures("hass_storage") # Prevent test hass from writing to storage async def test_migrate_can_resume_entity_id_post_migration( @@ -430,6 +436,7 @@ def _get_states_index_names(): patch.object(core, "EventData", old_db_schema.EventData), patch.object(core, "States", old_db_schema.States), patch.object(core, "Events", old_db_schema.Events), + patch.object(migration, "Base", old_db_schema.Base), patch( CREATE_ENGINE_TARGET, new=_create_engine_test( @@ -455,12 +462,22 @@ def _add_data(): await hass.async_block_till_done() await instance.async_block_till_done() - await instance.async_add_executor_job( - migration._drop_index, - instance.get_session, - "states", - "ix_states_event_id", - ) + if not recorder_db_url.startswith("sqlite://"): + await instance.async_add_executor_job( + migration._drop_foreign_key_constraints, + instance.get_session, + instance.engine, + "states", + "event_id", + ) + await async_drop_index(instance, "states", "ix_states_event_id", caplog) + if not recorder_db_url.startswith("sqlite://"): + await instance.async_add_executor_job( + migration._restore_foreign_key_constraints, + instance.get_session, + instance.engine, + [("states", "event_id", "events", "event_id")], + ) states_indexes = await instance.async_add_executor_job( _get_states_index_names @@ -599,12 +616,7 @@ def _add_data(): await hass.async_block_till_done() await instance.async_block_till_done() - await instance.async_add_executor_job( - migration._drop_index, - instance.get_session, - "states", - "ix_states_event_id", - ) + await async_drop_index(instance, "states", "ix_states_event_id", caplog) states_indexes = await instance.async_add_executor_job( _get_states_index_names @@ -763,6 +775,7 @@ def _get_states_index_names(): patch.object(core, "EventData", old_db_schema.EventData), patch.object(core, "States", old_db_schema.States), patch.object(core, "Events", old_db_schema.Events), + patch.object(migration, "Base", old_db_schema.Base), patch( CREATE_ENGINE_TARGET, new=_create_engine_test( @@ -789,10 +802,18 @@ def _add_data(): await instance.async_block_till_done() await instance.async_add_executor_job( - migration._drop_index, + migration._drop_foreign_key_constraints, instance.get_session, + instance.engine, "states", - "ix_states_event_id", + "event_id", + ) + await async_drop_index(instance, "states", "ix_states_event_id", caplog) + await instance.async_add_executor_job( + migration._restore_foreign_key_constraints, + instance.get_session, + instance.engine, + [("states", "event_id", "events", "event_id")], ) states_indexes = await instance.async_add_executor_job( @@ -824,11 +845,28 @@ def _add_data(): instrumented_migration.live_migration_done.wait ) + # The states.event_id foreign key constraint was removed when + # migration to schema version 46 + assert ( + await instance.async_add_executor_job(_get_event_id_foreign_keys) + is None + ) + + # Re-add the foreign key constraint to simulate failure to remove it during + # schema migration + with patch.object(migration, "Base", old_db_schema.Base): + await instance.async_add_executor_job( + migration._restore_foreign_key_constraints, + instance.get_session, + instance.engine, + [("states", "event_id", "events", "event_id")], + ) + # Simulate out of disk space while removing the foreign key from the states table by # - patching DropConstraint to raise InternalError for MySQL and PostgreSQL with ( patch( - "homeassistant.components.recorder.migration.sqlalchemy.inspect", + "homeassistant.components.recorder.migration.DropConstraint.__init__", side_effect=OperationalError( None, None, OSError("No space left on device") ), @@ -846,14 +884,6 @@ def _add_data(): ) states_index_names = {index["name"] for index in states_indexes} assert instance.use_legacy_events_index is True - # The states.event_id foreign key constraint was removed when - # migration to schema version 46 - assert ( - await instance.async_add_executor_job( - _get_event_id_foreign_keys - ) - is None - ) await hass.async_stop() diff --git a/tests/components/reolink/test_init.py b/tests/components/reolink/test_init.py index 662469ebc0168..00ef9e59e3b97 100644 --- a/tests/components/reolink/test_init.py +++ b/tests/components/reolink/test_init.py @@ -338,24 +338,6 @@ async def test_remove_chime(*args, **key_args): "support_ch_uid", ), [ - ( - TEST_MAC, - f"{TEST_MAC}_firmware", - f"{TEST_MAC}", - f"{TEST_MAC}", - Platform.UPDATE, - False, - False, - ), - ( - TEST_MAC, - f"{TEST_UID}_firmware", - f"{TEST_MAC}", - f"{TEST_UID}", - Platform.UPDATE, - True, - False, - ), ( f"{TEST_MAC}_0_record_audio", f"{TEST_UID}_0_record_audio", diff --git a/tests/components/reolink/test_switch.py b/tests/components/reolink/test_switch.py index 97dfc622aed04..83840cace9776 100644 --- a/tests/components/reolink/test_switch.py +++ b/tests/components/reolink/test_switch.py @@ -8,7 +8,6 @@ from reolink_aio.exceptions import ReolinkError from homeassistant.components.reolink import DEVICE_UPDATE_INTERVAL -from homeassistant.components.reolink.const import DOMAIN from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN from homeassistant.config_entries import ConfigEntryState from homeassistant.const import ( @@ -22,9 +21,8 @@ ) from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError -from homeassistant.helpers import entity_registry as er, issue_registry as ir -from .conftest import TEST_CAM_NAME, TEST_NVR_NAME, TEST_UID +from .conftest import TEST_CAM_NAME, TEST_NVR_NAME from tests.common import MockConfigEntry, async_fire_time_changed @@ -228,141 +226,3 @@ async def test_chime_switch( {ATTR_ENTITY_ID: entity_id}, blocking=True, ) - - -@pytest.mark.parametrize( - ( - "original_id", - "capability", - ), - [ - ( - f"{TEST_UID}_record", - "recording", - ), - ( - f"{TEST_UID}_ftp_upload", - "ftp", - ), - ( - f"{TEST_UID}_push_notifications", - "push", - ), - ( - f"{TEST_UID}_email", - "email", - ), - ( - f"{TEST_UID}_buzzer", - "buzzer", - ), - ], -) -async def test_cleanup_hub_switches( - hass: HomeAssistant, - config_entry: MockConfigEntry, - reolink_host: MagicMock, - entity_registry: er.EntityRegistry, - original_id: str, - capability: str, -) -> None: - """Test entity ids that need to be migrated.""" - - def mock_supported(ch, cap): - if cap == capability: - return False - return True - - domain = Platform.SWITCH - - reolink_host.channels = [0] - reolink_host.is_hub = True - reolink_host.supported = mock_supported - - entity_registry.async_get_or_create( - domain=domain, - platform=DOMAIN, - unique_id=original_id, - config_entry=config_entry, - suggested_object_id=original_id, - disabled_by=er.RegistryEntryDisabler.USER, - ) - - assert entity_registry.async_get_entity_id(domain, DOMAIN, original_id) - - # setup CH 0 and host entities/device - with patch("homeassistant.components.reolink.PLATFORMS", [domain]): - assert await hass.config_entries.async_setup(config_entry.entry_id) - await hass.async_block_till_done() - - assert entity_registry.async_get_entity_id(domain, DOMAIN, original_id) is None - - -@pytest.mark.parametrize( - ( - "original_id", - "capability", - ), - [ - ( - f"{TEST_UID}_record", - "recording", - ), - ( - f"{TEST_UID}_ftp_upload", - "ftp", - ), - ( - f"{TEST_UID}_push_notifications", - "push", - ), - ( - f"{TEST_UID}_email", - "email", - ), - ( - f"{TEST_UID}_buzzer", - "buzzer", - ), - ], -) -async def test_hub_switches_repair_issue( - hass: HomeAssistant, - config_entry: MockConfigEntry, - reolink_host: MagicMock, - entity_registry: er.EntityRegistry, - issue_registry: ir.IssueRegistry, - original_id: str, - capability: str, -) -> None: - """Test entity ids that need to be migrated.""" - - def mock_supported(ch, cap): - if cap == capability: - return False - return True - - domain = Platform.SWITCH - - reolink_host.channels = [0] - reolink_host.is_hub = True - reolink_host.supported = mock_supported - - entity_registry.async_get_or_create( - domain=domain, - platform=DOMAIN, - unique_id=original_id, - config_entry=config_entry, - suggested_object_id=original_id, - disabled_by=None, - ) - - assert entity_registry.async_get_entity_id(domain, DOMAIN, original_id) - - # setup CH 0 and host entities/device - with patch("homeassistant.components.reolink.PLATFORMS", [domain]): - assert await hass.config_entries.async_setup(config_entry.entry_id) - await hass.async_block_till_done() - - assert entity_registry.async_get_entity_id(domain, DOMAIN, original_id) - assert (DOMAIN, "hub_switch_deprecated") in issue_registry.issues diff --git a/tests/components/smartthings/conftest.py b/tests/components/smartthings/conftest.py index c45417122e92d..a68bbba22d215 100644 --- a/tests/components/smartthings/conftest.py +++ b/tests/components/smartthings/conftest.py @@ -166,6 +166,7 @@ def mock_smartthings() -> Generator[AsyncMock]: "hw_q80r_soundbar", "gas_meter", "lumi", + "tesla_powerwall", ] ) def device_fixture( diff --git a/tests/components/smartthings/fixtures/device_status/tesla_powerwall.json b/tests/components/smartthings/fixtures/device_status/tesla_powerwall.json new file mode 100644 index 0000000000000..c9531314d5fee --- /dev/null +++ b/tests/components/smartthings/fixtures/device_status/tesla_powerwall.json @@ -0,0 +1,107 @@ +{ + "components": { + "charge": { + "powerMeter": { + "power": { + "value": 0, + "unit": "W", + "timestamp": "2025-10-02T12:21:29.196Z" + } + }, + "powerConsumptionReport": { + "powerConsumption": { + "value": { + "start": "2025-10-02T12:20:00Z", + "end": "2025-10-02T12:25:00Z", + "energy": 29765947, + "deltaEnergy": 0 + }, + "timestamp": "2025-10-02T12:26:24.729Z" + } + } + }, + "discharge": { + "powerMeter": { + "power": { + "value": 0, + "unit": "W", + "timestamp": "2025-10-02T11:41:20.556Z" + } + }, + "powerConsumptionReport": { + "powerConsumption": { + "value": { + "start": "2025-10-02T12:20:00Z", + "end": "2025-10-02T12:25:00Z", + "energy": 27827062, + "deltaEnergy": 0 + }, + "timestamp": "2025-10-02T12:26:24.729Z" + } + } + }, + "main": { + "healthCheck": { + "checkInterval": { + "value": 60, + "unit": "s", + "data": { + "deviceScheme": "UNTRACKED", + "protocol": "cloud" + }, + "timestamp": "2025-10-02T11:56:25.223Z" + }, + "healthStatus": { + "value": null + }, + "DeviceWatch-Enroll": { + "value": null + }, + "DeviceWatch-DeviceStatus": { + "value": "online", + "data": {}, + "timestamp": "2025-10-02T11:56:25.223Z" + } + }, + "rivertalent14263.adaptiveEnergyUsageState": { + "stormWatchEnabled": { + "value": true, + "timestamp": "2024-07-16T12:40:19.190Z" + }, + "stormWatchActive": { + "value": false, + "timestamp": "2024-07-16T12:40:19.190Z" + }, + "gridStatusSupport": { + "value": true, + "timestamp": "2024-07-16T12:40:19.190Z" + }, + "stormWatchSupport": { + "value": true, + "timestamp": "2025-09-17T18:31:31.669Z" + }, + "energyUsageState": { + "value": null + }, + "gridStatusStatus": { + "value": "on-grid", + "timestamp": "2025-09-17T18:31:31.669Z" + } + }, + "refresh": {}, + "battery": { + "quantity": { + "value": null + }, + "battery": { + "value": 35, + "unit": "%", + "timestamp": "2025-10-02T11:41:20.556Z" + }, + "type": { + "value": null + } + } + } + } +} diff --git a/tests/components/smartthings/fixtures/devices/tesla_powerwall.json b/tests/components/smartthings/fixtures/devices/tesla_powerwall.json new file mode 100644 index 0000000000000..20e11a353554b --- /dev/null +++ b/tests/components/smartthings/fixtures/devices/tesla_powerwall.json @@ -0,0 +1,103 @@ +{ + "items": [ + { + "deviceId": "d2595c45-df6e-41ac-a7af-8e275071c19b", + "name": "UDHN-TESLA-ENERGY-BATTERY", + "label": "Powerwall", + "manufacturerName": "0AHI", + "presentationId": "STES-1-PV-TESLA-ENERGY-BATTERY", + "locationId": "d22d6401-6070-4928-8e7b-b724e2dbf425", + "ownerId": "35445a41-3ae2-4bc0-6f51-31705de6b96f", + "components": [ + { + "id": "main", + "label": "main", + "capabilities": [ + { + "id": "healthCheck", + "version": 1 + }, + { + "id": "refresh", + "version": 1 + }, + { + "id": "rivertalent14263.adaptiveEnergyUsageState", + "version": 1 + }, + { + "id": "battery", + "version": 1 + } + ], + "categories": [ + { + "name": "Battery", + "categoryType": "manufacturer" + } + ], + "optional": false + }, + { + "id": "discharge", + "label": "discharge", + "capabilities": [ + { + "id": "powerConsumptionReport", + "version": 1 + }, + { + "id": "powerMeter", + "version": 1 + } + ], + "categories": [ + { + "name": "Other", + "categoryType": "manufacturer" + } + ], + "optional": false + }, + { + "id": "charge", + "label": "charge", + "capabilities": [ + { + "id": "powerConsumptionReport", + "version": 1 + }, + { + "id": "powerMeter", + "version": 1 + } + ], + "categories": [ + { + "name": "Other", + "categoryType": "manufacturer" + } + ], + "optional": false + } + ], + "createTime": "2024-07-16T12:40:18.632Z", + "profile": { + "id": "4f9998dc-e672-4baf-8521-5e9b853fc978" + }, + "app": { + "installedAppId": "e798c0a6-3e3b-4299-8463-438fc3f1e6b3", + "externalId": "TESLABATTERY_1689188152863574", + "profile": { + "id": "4f9998dc-e672-4baf-8521-5e9b853fc978" + } + }, + "type": "ENDPOINT_APP", + "restrictionTier": 0, + "allowed": null, + "executionContext": "CLOUD", + "relationships": [] + } + ], + "_links": {} +} diff --git a/tests/components/smartthings/snapshots/test_init.ambr b/tests/components/smartthings/snapshots/test_init.ambr index 5cd56c316839c..42eaf548b36dd 100644 --- a/tests/components/smartthings/snapshots/test_init.ambr +++ b/tests/components/smartthings/snapshots/test_init.ambr @@ -1893,6 +1893,37 @@ 'via_device_id': None, }) # --- +# name: test_devices[tesla_powerwall] + DeviceRegistryEntrySnapshot({ + 'area_id': None, + 'config_entries': , + 'config_entries_subentries': , + 'configuration_url': 'https://account.smartthings.com', + 'connections': set({ + }), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': None, + 'id': , + 'identifiers': set({ + tuple( + 'smartthings', + 'd2595c45-df6e-41ac-a7af-8e275071c19b', + ), + }), + 'labels': set({ + }), + 'manufacturer': None, + 'model': None, + 'model_id': None, + 'name': 'Powerwall', + 'name_by_user': None, + 'primary_config_entry': , + 'serial_number': None, + 'sw_version': None, + 'via_device_id': None, + }) +# --- # name: test_devices[tplink_p110] DeviceRegistryEntrySnapshot({ 'area_id': None, diff --git a/tests/components/smartthings/snapshots/test_sensor.ambr b/tests/components/smartthings/snapshots/test_sensor.ambr index 9e83fdacab910..c573ccbbc27a3 100644 --- a/tests/components/smartthings/snapshots/test_sensor.ambr +++ b/tests/components/smartthings/snapshots/test_sensor.ambr @@ -13969,6 +13969,56 @@ 'state': '20', }) # --- +# name: test_all_entities[tesla_powerwall][sensor.powerwall_battery-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.powerwall_battery', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery', + 'platform': 'smartthings', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': 'd2595c45-df6e-41ac-a7af-8e275071c19b_main_battery_battery_battery', + 'unit_of_measurement': '%', + }) +# --- +# name: test_all_entities[tesla_powerwall][sensor.powerwall_battery-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'battery', + 'friendly_name': 'Powerwall Battery', + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.powerwall_battery', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '35', + }) +# --- # name: test_all_entities[tplink_p110][sensor.spulmaschine_energy-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ diff --git a/tests/components/tuya/__init__.py b/tests/components/tuya/__init__.py index 8659f277ad5c4..13c24046d2f0f 100644 --- a/tests/components/tuya/__init__.py +++ b/tests/components/tuya/__init__.py @@ -236,6 +236,7 @@ "wk_fi6dne5tu4t1nm6j", # https://github.com/orgs/home-assistant/discussions/243 "wk_gc1bxoq2hafxpa35", # https://github.com/home-assistant/core/issues/145551 "wk_gogb05wrtredz3bs", # https://github.com/home-assistant/core/issues/136337 + "wk_tfbhw0mg", # https://github.com/home-assistant/core/issues/152282 "wk_y5obtqhuztqsf2mj", # https://github.com/home-assistant/core/issues/139735 "wkcz_gc4b1mdw7kebtuyz", # https://github.com/home-assistant/core/issues/135617 "wkf_9xfjixap", # https://github.com/home-assistant/core/issues/139966 diff --git a/tests/components/tuya/fixtures/wk_tfbhw0mg.json b/tests/components/tuya/fixtures/wk_tfbhw0mg.json new file mode 100644 index 0000000000000..4a9186314eaf1 --- /dev/null +++ b/tests/components/tuya/fixtures/wk_tfbhw0mg.json @@ -0,0 +1,109 @@ +{ + "endpoint": "https://apigw.tuyaeu.com", + "mqtt_connected": true, + "disabled_by": null, + "disabled_polling": false, + "name": "Salon", + "category": "wk", + "product_id": "tfbhw0mg", + "product_name": "ZX-5442", + "online": true, + "sub": true, + "time_zone": "+02:00", + "active_time": "2025-09-13T13:48:55+00:00", + "create_time": "2025-09-13T13:48:55+00:00", + "update_time": "2025-09-13T13:48:55+00:00", + "function": { + "temp_set": { + "type": "Integer", + "value": { + "unit": "\u00b0C", + "min": 1, + "max": 59, + "scale": 1, + "step": 5 + } + }, + "mode": { + "type": "Enum", + "value": { + "range": ["auto", "manual", "holiday"] + } + }, + "child_lock": { + "type": "Boolean", + "value": {} + }, + "holiday_set": { + "type": "String", + "value": { + "maxlen": 255 + } + } + }, + "status_range": { + "temp_set": { + "type": "Integer", + "value": { + "unit": "\u00b0C", + "min": 1, + "max": 59, + "scale": 1, + "step": 5 + } + }, + "temp_current": { + "type": "Integer", + "value": { + "unit": "\u00b0C", + "min": -50, + "max": 350, + "scale": 1, + "step": 5 + } + }, + "mode": { + "type": "Enum", + "value": { + "range": ["auto", "manual", "holiday"] + } + }, + "child_lock": { + "type": "Boolean", + "value": {} + }, + "fault": { + "type": "Bitmap", + "value": { + "label": ["fault1", "fault2", "fault3"] + } + }, + "battery_percentage": { + "type": "Integer", + "value": { + "unit": "V", + "min": 0, + "max": 1000, + "scale": 2, + "step": 1 + } + }, + "holiday_set": { + "type": "String", + "value": { + "maxlen": 255 + } + } + }, + "status": { + "temp_set": 59, + "temp_current": 203, + "mode": "manual", + "child_lock": false, + "fault": 0, + "battery_percentage": 117, + "holiday_set": "FAwZAAAiAAA=" + }, + "set_up": true, + "support_local": true +} diff --git a/tests/components/tuya/snapshots/test_climate.ambr b/tests/components/tuya/snapshots/test_climate.ambr index 2673383f4f2f5..87304e5e9adbd 100644 --- a/tests/components/tuya/snapshots/test_climate.ambr +++ b/tests/components/tuya/snapshots/test_climate.ambr @@ -860,6 +860,83 @@ 'state': 'off', }) # --- +# name: test_platform_setup_and_discovery[climate.salon-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'hvac_modes': list([ + , + , + , + , + ]), + 'max_temp': 5.9, + 'min_temp': 0.1, + 'preset_modes': list([ + 'holiday', + ]), + 'target_temp_step': 0.5, + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'climate', + 'entity_category': None, + 'entity_id': 'climate.salon', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': None, + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': , + 'translation_key': None, + 'unique_id': 'tuya.gm0whbftkw', + 'unit_of_measurement': None, + }) +# --- +# name: test_platform_setup_and_discovery[climate.salon-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'current_temperature': 20.3, + 'friendly_name': 'Salon', + 'hvac_modes': list([ + , + , + , + , + ]), + 'max_temp': 5.9, + 'min_temp': 0.1, + 'preset_mode': None, + 'preset_modes': list([ + 'holiday', + ]), + 'supported_features': , + 'target_temp_step': 0.5, + 'temperature': 5.9, + }), + 'context': , + 'entity_id': 'climate.salon', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'heat_cool', + }) +# --- # name: test_platform_setup_and_discovery[climate.smart_thermostats-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ diff --git a/tests/components/tuya/snapshots/test_init.ambr b/tests/components/tuya/snapshots/test_init.ambr index c8810beb0e230..67ca9ddec1a17 100644 --- a/tests/components/tuya/snapshots/test_init.ambr +++ b/tests/components/tuya/snapshots/test_init.ambr @@ -3657,6 +3657,37 @@ 'via_device_id': None, }) # --- +# name: test_device_registry[gm0whbftkw] + DeviceRegistryEntrySnapshot({ + 'area_id': None, + 'config_entries': , + 'config_entries_subentries': , + 'configuration_url': None, + 'connections': set({ + }), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': None, + 'id': , + 'identifiers': set({ + tuple( + 'tuya', + 'gm0whbftkw', + ), + }), + 'labels': set({ + }), + 'manufacturer': 'Tuya', + 'model': 'ZX-5442', + 'model_id': 'tfbhw0mg', + 'name': 'Salon', + 'name_by_user': None, + 'primary_config_entry': , + 'serial_number': None, + 'sw_version': None, + 'via_device_id': None, + }) +# --- # name: test_device_registry[gnZOKztbAtcBkEGPzc] DeviceRegistryEntrySnapshot({ 'area_id': None, diff --git a/tests/components/tuya/snapshots/test_sensor.ambr b/tests/components/tuya/snapshots/test_sensor.ambr index 442f6774a0aa7..6d20cc5c03da7 100644 --- a/tests/components/tuya/snapshots/test_sensor.ambr +++ b/tests/components/tuya/snapshots/test_sensor.ambr @@ -15293,6 +15293,59 @@ 'state': 'high', }) # --- +# name: test_platform_setup_and_discovery[sensor.salon_battery-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.salon_battery', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery', + 'unique_id': 'tuya.gm0whbftkwbattery_percentage', + 'unit_of_measurement': '%', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.salon_battery-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'battery', + 'friendly_name': 'Salon Battery', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.salon_battery', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '1.17', + }) +# --- # name: test_platform_setup_and_discovery[sensor.sapphire_current-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ diff --git a/tests/components/tuya/snapshots/test_switch.ambr b/tests/components/tuya/snapshots/test_switch.ambr index 1b30c6cabea44..041f0eda4f566 100644 --- a/tests/components/tuya/snapshots/test_switch.ambr +++ b/tests/components/tuya/snapshots/test_switch.ambr @@ -7016,6 +7016,54 @@ 'state': 'on', }) # --- +# name: test_platform_setup_and_discovery[switch.salon_child_lock-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'switch', + 'entity_category': , + 'entity_id': 'switch.salon_child_lock', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Child lock', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'child_lock', + 'unique_id': 'tuya.gm0whbftkwchild_lock', + 'unit_of_measurement': None, + }) +# --- +# name: test_platform_setup_and_discovery[switch.salon_child_lock-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Salon Child lock', + }), + 'context': , + 'entity_id': 'switch.salon_child_lock', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- # name: test_platform_setup_and_discovery[switch.sapphire_socket-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ diff --git a/tests/components/websocket_api/test_commands.py b/tests/components/websocket_api/test_commands.py index 07a433754ff03..43a4fb0e53931 100644 --- a/tests/components/websocket_api/test_commands.py +++ b/tests/components/websocket_api/test_commands.py @@ -1433,28 +1433,50 @@ async def test_subscribe_unsubscribe_entities( } +@pytest.mark.parametrize("unserializable_states", [[], ["light.cannot_serialize"]]) async def test_subscribe_unsubscribe_entities_specific_entities( hass: HomeAssistant, websocket_client: MockHAClientWebSocket, hass_admin_user: MockUser, + unserializable_states: list[str], ) -> None: """Test subscribe/unsubscribe entities with a list of entity ids.""" + class CannotSerializeMe: + """Cannot serialize this.""" + + def __init__(self) -> None: + """Init cannot serialize this.""" + + for entity_id in unserializable_states: + hass.states.async_set( + entity_id, + "off", + {"color": "red", "cannot_serialize": CannotSerializeMe()}, + ) + hass.states.async_set("light.permitted", "off", {"color": "red"}) - hass.states.async_set("light.not_intrested", "off", {"color": "blue"}) + hass.states.async_set("light.not_interested", "off", {"color": "blue"}) original_state = hass.states.get("light.permitted") assert isinstance(original_state, State) hass_admin_user.groups = [] hass_admin_user.mock_policy( { "entities": { - "entity_ids": {"light.permitted": True, "light.not_intrested": True} + "entity_ids": { + "light.permitted": True, + "light.not_interested": True, + "light.cannot_serialize": True, + } } } ) await websocket_client.send_json_auto_id( - {"type": "subscribe_entities", "entity_ids": ["light.permitted"]} + { + "type": "subscribe_entities", + "entity_ids": ["light.permitted", "light.cannot_serialize"], + } ) msg = await websocket_client.receive_json() @@ -1476,7 +1498,7 @@ async def test_subscribe_unsubscribe_entities_specific_entities( } } } - hass.states.async_set("light.not_intrested", "on", {"effect": "help"}) + hass.states.async_set("light.not_interested", "on", {"effect": "help"}) hass.states.async_set("light.not_permitted", "on") hass.states.async_set("light.permitted", "on", {"color": "blue"}) @@ -1497,12 +1519,28 @@ async def test_subscribe_unsubscribe_entities_specific_entities( } +@pytest.mark.parametrize("unserializable_states", [[], ["light.cannot_serialize"]]) async def test_subscribe_unsubscribe_entities_with_filter( hass: HomeAssistant, websocket_client: MockHAClientWebSocket, hass_admin_user: MockUser, + unserializable_states: list[str], ) -> None: """Test subscribe/unsubscribe entities with an entity filter.""" + + class CannotSerializeMe: + """Cannot serialize this.""" + + def __init__(self) -> None: + """Init cannot serialize this.""" + + for entity_id in unserializable_states: + hass.states.async_set( + entity_id, + "off", + {"color": "red", "cannot_serialize": CannotSerializeMe()}, + ) + hass.states.async_set("switch.not_included", "off") hass.states.async_set("light.include", "off") await websocket_client.send_json_auto_id( diff --git a/tests/components/workday/test_calendar.py b/tests/components/workday/test_calendar.py index 5e5417362a34f..6aa454c860f0e 100644 --- a/tests/components/workday/test_calendar.py +++ b/tests/components/workday/test_calendar.py @@ -70,6 +70,11 @@ async def test_holiday_calendar_entity( async_fire_time_changed(hass) await hass.async_block_till_done() + # Binary sensor added to ensure same state for both entities + state = hass.states.get("binary_sensor.workday_sensor") + assert state is not None + assert state.state == "on" + state = hass.states.get("calendar.workday_sensor_calendar") assert state is not None assert state.state == "on" @@ -78,6 +83,10 @@ async def test_holiday_calendar_entity( async_fire_time_changed(hass) await hass.async_block_till_done() + state = hass.states.get("binary_sensor.workday_sensor") + assert state is not None + assert state.state == "off" + state = hass.states.get("calendar.workday_sensor_calendar") assert state is not None assert state.state == "off" diff --git a/tests/components/zwave_js/test_light.py b/tests/components/zwave_js/test_light.py index 954d642239948..f58f8427cf2b2 100644 --- a/tests/components/zwave_js/test_light.py +++ b/tests/components/zwave_js/test_light.py @@ -1073,6 +1073,16 @@ async def update_color(red: int, green: int, blue: int) -> None: ) await update_color(0, 0, 0) + # Turn off again and make sure last color/brightness is still preserved + # when turning on light again in the next step + await hass.services.async_call( + LIGHT_DOMAIN, + SERVICE_TURN_OFF, + {ATTR_ENTITY_ID: HSM200_V1_ENTITY}, + blocking=True, + ) + await update_color(0, 0, 0) + client.async_send_command.reset_mock() # Assert that the brightness is preserved when turning on with color @@ -1095,6 +1105,92 @@ async def update_color(red: int, green: int, blue: int) -> None: client.async_send_command.reset_mock() + await update_color(0, 0, 123) + + # Turn off twice + await hass.services.async_call( + LIGHT_DOMAIN, + SERVICE_TURN_OFF, + {ATTR_ENTITY_ID: HSM200_V1_ENTITY}, + blocking=True, + ) + await update_color(0, 0, 0) + + await hass.services.async_call( + LIGHT_DOMAIN, + SERVICE_TURN_OFF, + {ATTR_ENTITY_ID: HSM200_V1_ENTITY}, + blocking=True, + ) + await update_color(0, 0, 0) + + state = hass.states.get(HSM200_V1_ENTITY) + assert state.state == STATE_OFF + + client.async_send_command.reset_mock() + + # Assert that turning on after successive off calls works and keeps the last color + await hass.services.async_call( + LIGHT_DOMAIN, + SERVICE_TURN_ON, + {ATTR_ENTITY_ID: HSM200_V1_ENTITY, ATTR_BRIGHTNESS: 150}, + blocking=True, + ) + assert len(client.async_send_command.call_args_list) == 1 + args = client.async_send_command.call_args_list[0][0][0] + assert args["command"] == "node.set_value" + assert args["nodeId"] == node.node_id + assert args["valueId"] == { + "commandClass": 51, + "endpoint": 0, + "property": "targetColor", + } + assert args["value"] == {"red": 0, "green": 0, "blue": 150} + + client.async_send_command.reset_mock() + + await update_color(0, 0, 150) + + # Force the light to turn off + await update_color(0, 0, 0) + + # Turn off already off light, we won't be aware of last color and brightness + await hass.services.async_call( + LIGHT_DOMAIN, + SERVICE_TURN_OFF, + {ATTR_ENTITY_ID: HSM200_V1_ENTITY}, + blocking=True, + ) + await update_color(0, 0, 0) + + state = hass.states.get(HSM200_V1_ENTITY) + assert state.state == STATE_OFF + + client.async_send_command.reset_mock() + + # Assert that turning on light after off call with unknown off color/brightness state + # works and that light turns on to white with specified brightness + await hass.services.async_call( + LIGHT_DOMAIN, + SERVICE_TURN_ON, + {ATTR_ENTITY_ID: HSM200_V1_ENTITY, ATTR_BRIGHTNESS: 160}, + blocking=True, + ) + assert len(client.async_send_command.call_args_list) == 1 + args = client.async_send_command.call_args_list[0][0][0] + assert args["command"] == "node.set_value" + assert args["nodeId"] == node.node_id + assert args["valueId"] == { + "commandClass": 51, + "endpoint": 0, + "property": "targetColor", + } + assert args["value"] == {"red": 160, "green": 160, "blue": 160} + + client.async_send_command.reset_mock() + + await update_color(160, 160, 160) + # Clear the color value to trigger an unknown state event = Event( type="value updated", diff --git a/tests/conftest.py b/tests/conftest.py index 50bf0c40e10f5..205396a5d949b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1659,10 +1659,12 @@ def debug_session_scope( migrate_entity_ids = ( migration.EntityIDMigration.migrate_data if enable_migrate_entity_ids else None ) - legacy_event_id_foreign_key_exists = ( - migration.EventIDPostMigration._legacy_event_id_foreign_key_exists + post_migrate_event_ids = ( + migration.EventIDPostMigration.needs_migrate_impl if enable_migrate_event_ids - else lambda _: None + else lambda _1, _2, _3: migration.DataMigrationStatus( + needs_migrate=False, migration_done=True + ) ) with ( patch( @@ -1701,8 +1703,8 @@ def debug_session_scope( autospec=True, ), patch( - "homeassistant.components.recorder.migration.EventIDPostMigration._legacy_event_id_foreign_key_exists", - side_effect=legacy_event_id_foreign_key_exists, + "homeassistant.components.recorder.migration.EventIDPostMigration.needs_migrate_impl", + side_effect=post_migrate_event_ids, autospec=True, ), patch(