"""The Polaris IQ Home component.""" from __future__ import annotations import json import re import logging from typing import Iterable import copy from homeassistant.components import mqtt from homeassistant.components.mqtt.models import ReceiveMessage from homeassistant.helpers.entity import DeviceInfo, EntityCategory from homeassistant.util import slugify from homeassistant.core import HomeAssistant, callback from homeassistant.config_entries import ConfigEntry from homeassistant.helpers.entity_platform import AddEntitiesCallback from .common import PolarisBaseEntity from homeassistant.util import color as color_util from homeassistant.components.light import ( DOMAIN, ATTR_BRIGHTNESS, ATTR_RGB_COLOR, ColorMode, LightEntity, LightEntityDescription, ) # Import global values. from .const import ( MANUFACTURER, MQTT_ROOT_TOPIC, DEVICEID, DEVICETYPE, POLARIS_DEVICE, LIGHTS, LIGHTS_DOUBLE, PolarisLightEntityDescription, POLARIS_KETTLE_TYPE, POLARIS_KETTLE_WITH_WEIGHT_TYPE, POLARIS_KETTLE_WITH_NIGHT_TYPE, POLARIS_HUMIDDIFIER_TYPE, ) _LOGGER = logging.getLogger(__name__) _LOGGER.setLevel(logging.DEBUG) async def async_setup_entry( hass: HomeAssistant, config: ConfigEntry, async_add_entities: AddEntitiesCallback ) -> None: integrationUniqueID = config.unique_id mqtt_root = config.data[MQTT_ROOT_TOPIC] device_id = config.data["DEVICEID"] device_type = config.data[DEVICETYPE] device_prefix_topic = config.data["DEVPREFIXTOPIC"] lightList = [] if device_type in POLARIS_KETTLE_WITH_NIGHT_TYPE: # Create water heater for kettle devices LIGHTS_LC = copy.deepcopy(LIGHTS) for description in LIGHTS_LC: description.mqttTopicCurrentColor = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentColor}" description.mqttTopicCommandColor = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandColor}" description.mqttTopicCurrentState = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentState}" description.mqttTopicCommandState = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandState}" description.device_prefix_topic = device_prefix_topic lightList.append( PolarisLight( description=description, device_friendly_name=device_id, mqtt_root=mqtt_root, device_type=device_type, device_id=device_id ) ) if device_type == "835": # Create humidifier double lights LIGHTS_DOUBLE_LC = copy.deepcopy(LIGHTS_DOUBLE) for description in LIGHTS_DOUBLE_LC: description.mqttTopicCurrentColor = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentColor}" description.mqttTopicCommandColor = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandColor}" description.mqttTopicCurrentState = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentState}" description.mqttTopicCommandState = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandState}" description.device_prefix_topic = device_prefix_topic lightList.append( PolarisLight( description=description, device_friendly_name=device_id, mqtt_root=mqtt_root, device_type=device_type, device_id=device_id ) ) async_add_entities(lightList, update_before_add=True) class PolarisLight(PolarisBaseEntity, LightEntity): entity_description: PolarisLightEntityDescription def __init__( self, device_friendly_name: str, description: PolarisLightEntityDescription, mqtt_root: str, device_id: str | None=None, device_type: str | None=None, ) -> None: super().__init__( device_friendly_name=device_friendly_name, mqtt_root=mqtt_root, device_type=device_type, device_id=device_id, ) self.entity_description = description self._attr_unique_id = slugify(f"{device_id}_{description.name}") self.entity_id = f"{DOMAIN}.{POLARIS_DEVICE[int(device_type)]['class']}_{POLARIS_DEVICE[int(device_type)]['model']}_{description.name}" self._attr_color_mode = ColorMode.RGB self._attr_supported_color_modes = {ColorMode.RGB} self._attr_has_entity_name = True self._attr_rgb_color = [255, 255, 255] self._attr_brightness = 100 self._attr_is_on = False self._attr_available = False self._double_color = [[255, 255, 255],[255, 255, 255]] self._double_state = ["0","0"] async def async_added_to_hass(self): if self.device_type == "835": @callback def message_received_double_state(message): if message.payload[1] == "0" and self.entity_description.key == "night_up": self._attr_is_on = False # self._double_state[0] = "0" elif message.payload[3] == "0" and self.entity_description.key == "night_down": self._attr_is_on = False # self._double_state[1] = "0" elif message.payload[1] in {"1","2","3"} and self.entity_description.key == "night_up": self._attr_is_on = True elif message.payload[3] in {"1","2","3"} and self.entity_description.key == "night_down": self._attr_is_on = True else: self._attr_is_on = None self._double_state[0] = message.payload[1] self._double_state[1] = message.payload[3] rgb_up = color_util.rgb_hex_to_rgb_list(message.payload[4:10]) rgb_down = color_util.rgb_hex_to_rgb_list(message.payload[10:]) self._double_color = [rgb_up, rgb_down] if self.entity_description.key == "night_up": rgb = rgb_up else: rgb = rgb_down level = int(max(rgb)/255*100) self._attr_brightness = level rgb_color = rgb bright_factor_old = max(rgb)/255 bright_factor_new = level / 100 / bright_factor_old self._attr_rgb_color = [int(value / bright_factor_new) for value in rgb_color] self.async_write_ha_state() await mqtt.async_subscribe( self.hass, self.entity_description.mqttTopicCurrentState, message_received_double_state, 1, ) else: @callback def message_received_rgb(message): rgb = color_util.rgb_hex_to_rgb_list(message.payload) level = int(max(rgb)/255*100) self._attr_brightness = level if (self.device_type == "176" or self.device_type == "255"): rgb_color = [rgb[0], rgb[1], rgb[2]] else: rgb_color = rgb bright_factor_old = max(rgb)/255 bright_factor_new = level / 100 / bright_factor_old self._attr_rgb_color = [int(value / bright_factor_new) for value in rgb_color] self.async_write_ha_state() @callback def message_received_state(message): if str(message.payload).lower() in ("1", "true"): self._attr_is_on = True elif str(message.payload).lower() in ("0", "false"): self._attr_is_on = False else: self._attr_is_on = None self.async_write_ha_state() await mqtt.async_subscribe( self.hass, self.entity_description.mqttTopicCurrentColor, message_received_rgb, 1, ) await mqtt.async_subscribe( self.hass, self.entity_description.mqttTopicCurrentState, message_received_state, 1, ) @callback async def entity_availability(message): if self.entity_description.name != "available": if str(message.payload).lower() in ("1", "true"): self._attr_available = False else: self._attr_available = True self.async_write_ha_state() await mqtt.async_subscribe(self.hass, f"{self.mqtt_root}/{self.entity_description.device_prefix_topic}/state/error/connection", entity_availability, 1) async def async_turn_on(self, **kwargs: Any) -> None: topic = self.entity_description.mqttTopicCommandColor if ATTR_RGB_COLOR in kwargs: color = color_util.color_rgb_to_hex(*kwargs[ATTR_RGB_COLOR]) self._attr_rgb_color = color_util.rgb_hex_to_rgb_list(color) elif ATTR_BRIGHTNESS in kwargs: level = int((kwargs.get(ATTR_BRIGHTNESS, 100) * 100) / 255) self._attr_brightness = level bright_factor_old = max(self._attr_rgb_color)/255 bright_factor_new = self._attr_brightness/ 100 / bright_factor_old self._attr_rgb_color = [int(value * bright_factor_new) for value in self._attr_rgb_color] if (self.device_type == "176" or self.device_type == "255"): mqtt.publish(self.hass, topic, f"{self._attr_rgb_color[0]:02x}{self._attr_rgb_color[1]:02x}{self._attr_rgb_color[2]:02x}00") elif self.device_type == "835": if self.entity_description.key == "night_up": mqtt.publish(self.hass, topic, f"030{self._double_state[1]}{color_util.color_rgb_to_hex(self._attr_rgb_color[0], self._attr_rgb_color[1],self._attr_rgb_color[2])}{self._double_color[1][0]:02x}{self._double_color[1][1]:02x}{self._double_color[1][2]:02x}") if self.entity_description.key == "night_down": mqtt.publish(self.hass, topic, f"0{self._double_state[0]}03{self._double_color[0][0]:02x}{self._double_color[0][1]:02x}{self._double_color[0][2]:02x}{color_util.color_rgb_to_hex(self._attr_rgb_color[0], self._attr_rgb_color[1],self._attr_rgb_color[2])}") else: mqtt.publish(self.hass, topic, color_util.color_rgb_to_hex(self._attr_rgb_color[0], self._attr_rgb_color[1],self._attr_rgb_color[2])) if self.device_type != "835": topic = self.entity_description.mqttTopicCommandState mqtt.publish(self.hass, topic, "true") self._attr_is_on = True async def async_turn_off(self, **kwargs: Any) -> None: topic = self.entity_description.mqttTopicCommandState if self.device_type == "835": if self.entity_description.key == "night_up": mess = f"000{self._double_state[1]}{self._double_color[0][0]:02x}{self._double_color[0][1]:02x}{self._double_color[0][2]:02x}{self._double_color[1][0]:02x}{self._double_color[1][1]:02x}{self._double_color[1][2]:02x}" if self.entity_description.key == "night_down": mess = f"0{self._double_state[0]}00{self._double_color[0][0]:02x}{self._double_color[0][1]:02x}{self._double_color[0][2]:02x}{self._double_color[1][0]:02x}{self._double_color[1][1]:02x}{self._double_color[1][2]:02x}" mqtt.publish(self.hass, topic, mess) else: mqtt.publish(self.hass, topic, "false") self._attr_is_on = False @property def is_on(self) -> bool: return self._attr_is_on @property def brightness(self) -> int: return int((self._attr_brightness * 255) / 100) @property def rgb_color(self) -> tuple[int, int, int] | None: return self._attr_rgb_color