light.py (4674B)
1 """Light platform for in-lite integration. 2 3 Creates one LightEntity per zone per transformer. 4 """ 5 6 from __future__ import annotations 7 8 import logging 9 from typing import Any 10 11 from homeassistant.components.light import ColorMode, LightEntity 12 from homeassistant.core import HomeAssistant 13 from homeassistant.helpers.entity import DeviceInfo 14 from homeassistant.helpers.entity_platform import AddEntitiesCallback 15 from homeassistant.helpers.update_coordinator import CoordinatorEntity 16 17 from . import InliteConfigEntry 18 from .const import CONF_GARDEN_ID, CONF_TRANSFORMERS, DOMAIN 19 from .coordinator import InliteCoordinator 20 21 _LOGGER = logging.getLogger(__name__) 22 23 24 async def async_setup_entry( 25 hass: HomeAssistant, 26 entry: InliteConfigEntry, 27 async_add_entities: AddEntitiesCallback, 28 ) -> None: 29 """Set up in-lite light entities from a config entry.""" 30 coordinator = entry.runtime_data 31 garden_id = entry.data[CONF_GARDEN_ID] 32 33 entities: list[InliteLightEntity] = [] 34 for tx_data in entry.data[CONF_TRANSFORMERS]: 35 device_id = tx_data["device_id"] 36 hub = coordinator.hubs[device_id] 37 tx_name = tx_data["name"] 38 firmware = tx_data.get("firmware_version", "unknown") 39 40 for zone_data in tx_data["zones"]: 41 if not hub.is_output_visible(zone_data["output_id"]): 42 continue 43 entities.append( 44 InliteLightEntity( 45 coordinator=coordinator, 46 garden_id=garden_id, 47 device_id=device_id, 48 tx_name=tx_name, 49 firmware=firmware, 50 output_id=zone_data["output_id"], 51 zone_name=zone_data["name"], 52 ) 53 ) 54 55 async_add_entities(entities) 56 57 58 class InliteLightEntity(CoordinatorEntity[InliteCoordinator], LightEntity): 59 """Represents a single in-lite light zone.""" 60 61 _attr_has_entity_name = True 62 _attr_translation_key = "zone" 63 _attr_color_mode = ColorMode.ONOFF 64 _attr_supported_color_modes = {ColorMode.ONOFF} 65 66 def __init__( 67 self, 68 coordinator: InliteCoordinator, 69 garden_id: str, 70 device_id: int, 71 tx_name: str, 72 firmware: Any, 73 output_id: int, 74 zone_name: str, 75 ) -> None: 76 """Initialize the light entity.""" 77 super().__init__(coordinator) 78 self._device_id = device_id 79 self._output_id = output_id 80 self._attr_name = zone_name 81 self._attr_unique_id = f"{garden_id}_{device_id}_{output_id}" 82 83 # Device groups zones under the transformer 84 self._attr_device_info = DeviceInfo( 85 identifiers={(DOMAIN, f"{garden_id}_{device_id}")}, 86 name=tx_name, 87 manufacturer="in-lite", 88 model=tx_name, 89 sw_version=str(firmware), 90 ) 91 92 @property 93 def is_on(self) -> bool | None: 94 """Return True if the light is on.""" 95 if self.coordinator.data is None: 96 return None 97 hub_states = self.coordinator.data.get(self._device_id, {}) 98 zone_state = hub_states.get(self._output_id) 99 if zone_state is None: 100 return None 101 return zone_state.is_on 102 103 @property 104 def available(self) -> bool: 105 """Return True if the hub is reachable.""" 106 return self.coordinator.available and super().available 107 108 async def async_turn_on(self, **kwargs: Any) -> None: 109 """Turn the light on.""" 110 previous_state = self.is_on 111 self._attr_is_on = True 112 self.async_write_ha_state() 113 114 success = await self.coordinator.async_send_command( 115 self._device_id, self._output_id, True 116 ) 117 if success: 118 # Update coordinator data directly from hub's internal state 119 self.coordinator.async_set_updated_data(self.coordinator.data) 120 else: 121 # Roll back optimistic update on failure 122 self._attr_is_on = previous_state 123 self.async_write_ha_state() 124 125 async def async_turn_off(self, **kwargs: Any) -> None: 126 """Turn the light off.""" 127 previous_state = self.is_on 128 self._attr_is_on = False 129 self.async_write_ha_state() 130 131 success = await self.coordinator.async_send_command( 132 self._device_id, self._output_id, False 133 ) 134 if success: 135 # Update coordinator data directly from hub's internal state 136 self.coordinator.async_set_updated_data(self.coordinator.data) 137 else: 138 # Roll back optimistic update on failure 139 self._attr_is_on = previous_state 140 self.async_write_ha_state()