393 files

This commit is contained in:
Home Assistant Version Control
2026-09-27 17:16:54 +00:00
parent b05b7a897e
commit 39d97ac2db
404 changed files with 54006 additions and 11034 deletions
+21 -75
View File
@@ -1,16 +1,14 @@
from __future__ import annotations
import logging
from datetime import timedelta
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from homeassistant.util import slugify
from .api import SeaTemperatureAPI, SeaTemperatureError
from .api import SeaTemperatureAPI
from .const import (
CONF_AREA,
CONF_CONTINENT,
@@ -18,12 +16,9 @@ from .const import (
CONF_PATH,
CONF_PLACE,
CONF_PLACE_ID,
CONF_SCAN_INTERVAL_HOURS,
DEFAULT_SCAN_INTERVAL_HOURS,
DOMAIN,
MAX_SCAN_INTERVAL_HOURS,
MIN_SCAN_INTERVAL_HOURS,
)
from .coordinator import SeaTemperatureConfigEntry, SeaTemperatureCoordinator
PLATFORMS = [Platform.SENSOR]
_LOGGER = logging.getLogger(__name__)
@@ -127,21 +122,6 @@ async def async_setup(hass: HomeAssistant, config: dict) -> bool:
return True
def async_scan_interval(entry: ConfigEntry) -> timedelta:
"""Return the poll interval for an entry, honouring the options flow."""
hours = entry.options.get(CONF_SCAN_INTERVAL_HOURS, DEFAULT_SCAN_INTERVAL_HOURS)
try:
hours = int(hours)
except (TypeError, ValueError):
hours = DEFAULT_SCAN_INTERVAL_HOURS
if not MIN_SCAN_INTERVAL_HOURS <= hours <= MAX_SCAN_INTERVAL_HOURS:
# The options flow bounds the form, but a hand-edited or older stored
# value reaches this reader directly - clamp both ends, not just the
# one that would hammer the site.
hours = DEFAULT_SCAN_INTERVAL_HOURS
return timedelta(hours=hours)
def entry_location_key(entry: ConfigEntry) -> str:
"""Return the key an entry's entity unique_ids are built from.
@@ -243,11 +223,17 @@ async def _async_migrate_unique_ids(hass: HomeAssistant, entry: ConfigEntry) ->
async def async_migrate_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Migrate legacy config entries from place IDs to path-based locations."""
if entry.version > 4:
_LOGGER.error("Unsupported SeaTemperatures config entry version: %s", entry.version)
_LOGGER.error(
"Unsupported SeaTemperatures config entry version: %s", entry.version
)
return False
if entry.version < 2:
_LOGGER.debug("Migrating SeaTemperatures entry %s from version %s", entry.entry_id, entry.version)
_LOGGER.debug(
"Migrating SeaTemperatures entry %s from version %s",
entry.entry_id,
entry.version,
)
data = dict(entry.data)
location_path = data.get(CONF_PATH)
@@ -291,30 +277,6 @@ async def async_migrate_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
return True
async def _async_fetch(
api: SeaTemperatureAPI, location_path: str | None, place_name: str
) -> dict:
"""Fetch one refresh, turning an API failure into a single logged one.
The coordinator logs an UpdateFailed once and stays quiet while the failure
persists, so the API layer deliberately reports nothing of its own.
"""
if not location_path:
raise UpdateFailed(
"No location path configured. Remove and re-add the integration."
)
try:
data = await api.get_temperatures(location_path)
except SeaTemperatureError as err:
raise UpdateFailed(str(err)) from err
if not data:
raise UpdateFailed(f"Failed to fetch data for place {place_name}")
return data
async def _async_options_updated(hass: HomeAssistant, entry: ConfigEntry) -> None:
"""Reload the entry after the options flow saved a new poll interval.
@@ -327,45 +289,29 @@ async def _async_options_updated(hass: HomeAssistant, entry: ConfigEntry) -> Non
await hass.config_entries.async_reload(entry.entry_id)
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
async def async_setup_entry(
hass: HomeAssistant, entry: SeaTemperatureConfigEntry
) -> bool:
"""Set up Sea Temperature from a config entry."""
hass.data.setdefault(DOMAIN, {})
# Registered before the first refresh so an options save during a slow or
# failing setup is not silently dropped; async_on_unload drops the
# subscription with the entry rather than stacking one per reload.
entry.async_on_unload(entry.add_update_listener(_async_options_updated))
place_name = entry.data.get(CONF_PLACE, "Unknown")
location_path = entry.data.get(CONF_PATH)
location_key = entry_location_key(entry)
api = SeaTemperatureAPI(hass)
async def async_update_data():
"""Fetch data from API."""
return await _async_fetch(api, location_path, place_name)
coordinator = DataUpdateCoordinator(
hass,
_LOGGER,
name=f"seatemperatures_{location_key}",
update_method=async_update_data,
update_interval=async_scan_interval(entry),
)
coordinator = SeaTemperatureCoordinator(hass, entry, entry_location_key(entry))
await coordinator.async_config_entry_first_refresh()
hass.data[DOMAIN][entry.entry_id] = coordinator
entry.runtime_data = coordinator
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
return True
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
async def async_unload_entry(
hass: HomeAssistant, entry: SeaTemperatureConfigEntry
) -> bool:
"""Unload a config entry."""
if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS):
hass.data[DOMAIN].pop(entry.entry_id)
return unload_ok
# Core drops entry.runtime_data once the unload succeeded, so there is no
# hass.data bookkeeping left to undo here.
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)