from __future__ import annotations from homeassistant.components.number import NumberEntity, NumberMode from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.restore_state import RestoreEntity from .const import DOMAIN from .coordinator import AlbumCoordinator from .store import SlideshowStore async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback) -> None: store: SlideshowStore = hass.data[DOMAIN][entry.entry_id]["store"] coordinator: AlbumCoordinator = hass.data[DOMAIN][entry.entry_id]["coordinator"] async_add_entities( [ SlideIntervalNumber(entry, store), RefreshHoursNumber(entry, store, coordinator), PairDividerWidthNumber(entry, store), ImageCacheMbNumber(entry, store), ] ) class _BaseNumber(NumberEntity, RestoreEntity): _attr_has_entity_name = True _attr_should_poll = False _attr_mode = NumberMode.BOX def __init__(self, entry: ConfigEntry, store: SlideshowStore) -> None: self.entry = entry self.store = store async def async_added_to_hass(self) -> None: await super().async_added_to_hass() self.store.add_listener(self.async_write_ha_state) @property def device_info(self): return { "identifiers": {(DOMAIN, self.entry.entry_id)}, "name": f"Album Slideshow {self.entry.title}", "manufacturer": "Album Slideshow", } class SlideIntervalNumber(_BaseNumber): _attr_icon = "mdi:timer-outline" _attr_native_min_value = 3 _attr_native_max_value = 3600 _attr_native_step = 1 def __init__(self, entry: ConfigEntry, store: SlideshowStore) -> None: super().__init__(entry, store) self._attr_unique_id = f"{entry.entry_id}_interval" self._attr_name = "Slide interval (seconds)" @property def native_value(self): return int(self.store.slide_interval) async def async_set_native_value(self, value: float) -> None: self.store.slide_interval = int(value) self.store.notify() async def async_added_to_hass(self) -> None: await super().async_added_to_hass() old = await self.async_get_last_state() if old and old.state not in (None, "unknown", "unavailable"): try: self.store.slide_interval = int(float(old.state)) self.store.notify() except Exception: return class RefreshHoursNumber(_BaseNumber): _attr_icon = "mdi:refresh" _attr_native_min_value = 1 _attr_native_max_value = 168 _attr_native_step = 1 def __init__(self, entry: ConfigEntry, store: SlideshowStore, coordinator: AlbumCoordinator) -> None: super().__init__(entry, store) self.coordinator = coordinator self._attr_unique_id = f"{entry.entry_id}_refresh_minutes" self._attr_name = "Album refresh (hours)" @property def native_value(self): return int(self.store.refresh_hours) async def async_set_native_value(self, value: float) -> None: self.store.refresh_hours = int(value) self.store.notify() await self.coordinator.async_request_refresh() async def async_added_to_hass(self) -> None: await super().async_added_to_hass() old = await self.async_get_last_state() if old and old.state not in (None, "unknown", "unavailable"): try: val = int(float(old.state)) # Migration: old values were in minutes; convert if above max hours if val > self._attr_native_max_value: val = max(int(val / 60), int(self._attr_native_min_value)) self.store.refresh_hours = val self.store.notify() except Exception: return class PairDividerWidthNumber(_BaseNumber): _attr_icon = "mdi:border-vertical" _attr_native_min_value = 0 _attr_native_max_value = 64 _attr_native_step = 1 def __init__(self, entry: ConfigEntry, store: SlideshowStore) -> None: super().__init__(entry, store) self._attr_unique_id = f"{entry.entry_id}_pair_divider_px" self._attr_name = "Pair divider size (px)" @property def native_value(self): return int(self.store.pair_divider_px) async def async_set_native_value(self, value: float) -> None: self.store.pair_divider_px = max(0, int(value)) self.store.notify() async def async_added_to_hass(self) -> None: await super().async_added_to_hass() old = await self.async_get_last_state() if old and old.state not in (None, "unknown", "unavailable"): try: self.store.pair_divider_px = max(0, int(float(old.state))) self.store.notify() except Exception: return class ImageCacheMbNumber(_BaseNumber): _attr_icon = "mdi:database-outline" _attr_native_min_value = 50 _attr_native_max_value = 1000 _attr_native_step = 50 _attr_native_unit_of_measurement = "MB" def __init__(self, entry: ConfigEntry, store: SlideshowStore) -> None: super().__init__(entry, store) self._attr_unique_id = f"{entry.entry_id}_image_cache_mb" self._attr_name = "Image cache size (MB)" @property def native_value(self): return int(self.store.image_cache_mb) async def async_set_native_value(self, value: float) -> None: self.store.image_cache_mb = max(50, int(value)) self.store.notify() async def async_added_to_hass(self) -> None: await super().async_added_to_hass() old = await self.async_get_last_state() if old and old.state not in (None, "unknown", "unavailable"): try: self.store.image_cache_mb = max(50, int(float(old.state))) self.store.notify() except Exception: return