261 lines
12 KiB
Python
261 lines
12 KiB
Python
"""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
|