ha-inlite

Home Assistant integration for in-lite
git clone https://git.stephank.nl/ha-inlite
Log | Files | Refs | README | LICENSE | ZIP

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()