Initialize docker stack repo
This commit is contained in:
42
homeassistant/config/custom_components/polaris/__init__.py
Normal file
42
homeassistant/config/custom_components/polaris/__init__.py
Normal file
@@ -0,0 +1,42 @@
|
||||
"""The Polaris IQ Home component."""
|
||||
|
||||
import logging
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
|
||||
# Import global values.
|
||||
from .const import PLATFORMS
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
_LOGGER.setLevel(logging.DEBUG)
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Trigger the creation of sensors."""
|
||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||
|
||||
# Активация всех деактивированных устройств при загрузке
|
||||
await async_enable_disabled_devices(hass, entry)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Unload all sensor entities and services if integration is removed via UI.
|
||||
No restart of home assistant is required.
|
||||
"""
|
||||
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
||||
|
||||
return unload_ok
|
||||
|
||||
|
||||
async def async_enable_disabled_devices(hass: HomeAssistant, entry: ConfigEntry):
|
||||
"""Enable all disabled devices associated with this integration."""
|
||||
device_registry = dr.async_get(hass)
|
||||
devices = dr.async_entries_for_config_entry(device_registry, entry.entry_id)
|
||||
|
||||
for device in devices:
|
||||
if device.disabled:
|
||||
_LOGGER.debug("Enabling disabled device: %s (%s)", device.name, device.id)
|
||||
device_registry.async_update_device(device.id, disabled_by = None) # Убираем disabled
|
||||
324
homeassistant/config/custom_components/polaris/binary_sensor.py
Normal file
324
homeassistant/config/custom_components/polaris/binary_sensor.py
Normal file
@@ -0,0 +1,324 @@
|
||||
"""The Polaris IQ Home component."""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
import logging
|
||||
from typing import Iterable, List
|
||||
import copy
|
||||
from datetime import datetime
|
||||
|
||||
from homeassistant.components import mqtt
|
||||
from homeassistant.components.mqtt.models import ReceiveMessage
|
||||
from homeassistant.components.binary_sensor import (
|
||||
DOMAIN,
|
||||
BinarySensorDeviceClass,
|
||||
BinarySensorEntity,
|
||||
BinarySensorEntityDescription,
|
||||
)
|
||||
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
|
||||
# Device
|
||||
from homeassistant.helpers.device_registry import DeviceEntry, DeviceEntryDisabler
|
||||
from homeassistant.helpers import device_registry as dev_reg
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from homeassistant.helpers import entity_registry as ent_reg
|
||||
from homeassistant.const import STATE_UNAVAILABLE
|
||||
|
||||
from .common import PolarisBaseEntity
|
||||
|
||||
# Import global values.
|
||||
from .const import (
|
||||
MANUFACTURER,
|
||||
MQTT_ROOT_TOPIC,
|
||||
DEVICEID,
|
||||
DEVICETYPE,
|
||||
POLARIS_DEVICE,
|
||||
BINARYSENSOR_KETTLE,
|
||||
BINARYSENSOR_LID,
|
||||
BINARYSENSOR_WATER_TANK,
|
||||
BINARYSENSOR_CAPPUCCINATOR,
|
||||
BINARYSENSOR_AVAILABLE,
|
||||
BINARYSENSOR_THERMOSTAT,
|
||||
PolarisBinarySensorEntityDescription,
|
||||
POLARIS_KETTLE_TYPE,
|
||||
POLARIS_KETTLE_WITH_WEIGHT_TYPE,
|
||||
POLARIS_HUMIDDIFIER_TYPE,
|
||||
POLARIS_COOKER_TYPE,
|
||||
POLARIS_COOKER_WITH_LID_TYPE,
|
||||
POLARIS_COFFEEMAKER_TYPE,
|
||||
POLARIS_COFFEEMAKER_ROG_TYPE,
|
||||
POLARIS_CLIMATE_TYPE,
|
||||
POLARIS_AIRCLEANER_TYPE,
|
||||
POLARIS_AIRCLEANER_EAP_TYPE,
|
||||
POLARIS_BOILER_TYPE,
|
||||
POLARIS_VACUUM_TYPE,
|
||||
POLARIS_IRRIGATOR_TYPE,
|
||||
POLARIS_HEATER_TYPE,
|
||||
POLARIS_AIRCONDITIONER_TYPE,
|
||||
POLARIS_THERMOSTAT_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"]
|
||||
binarysensorList = []
|
||||
|
||||
if (device_type in POLARIS_KETTLE_WITH_WEIGHT_TYPE):
|
||||
BINARYSENSOR_KETTLE_LC = copy.deepcopy(BINARYSENSOR_KETTLE)
|
||||
for description in BINARYSENSOR_KETTLE_LC:
|
||||
description.mqttTopicStatus = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicStatus}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
binarysensorList.append(
|
||||
PolarisBinarySensor(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_COOKER_WITH_LID_TYPE):
|
||||
BINARYSENSOR_LID_LC = copy.deepcopy(BINARYSENSOR_LID)
|
||||
for description in BINARYSENSOR_LID_LC:
|
||||
description.mqttTopicStatus = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicStatus}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
binarysensorList.append(
|
||||
PolarisBinarySensor(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_HUMIDDIFIER_TYPE and device_type not in {"835","881"}):
|
||||
BINARYSENSOR_WATER_TANK_LC = copy.deepcopy(BINARYSENSOR_WATER_TANK)
|
||||
for description in BINARYSENSOR_WATER_TANK_LC:
|
||||
description.mqttTopicStatus = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicStatus}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
binarysensorList.append(
|
||||
PolarisBinarySensor(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_COFFEEMAKER_ROG_TYPE):
|
||||
BINARYSENSOR_CAPPUCCINATOR_LC = copy.deepcopy(BINARYSENSOR_CAPPUCCINATOR)
|
||||
for description in BINARYSENSOR_CAPPUCCINATOR_LC:
|
||||
description.mqttTopicStatus = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicStatus}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
binarysensorList.append(
|
||||
PolarisBinarySensor(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_THERMOSTAT_TYPE):
|
||||
BINARYSENSOR_THERMOSTAT_LC = copy.deepcopy(BINARYSENSOR_THERMOSTAT)
|
||||
for description in BINARYSENSOR_THERMOSTAT_LC:
|
||||
description.mqttTopicStatus = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicStatus}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
binarysensorList.append(
|
||||
PolarisBinarySensor(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_KETTLE_TYPE or
|
||||
device_type in POLARIS_KETTLE_WITH_WEIGHT_TYPE or
|
||||
device_type in POLARIS_HUMIDDIFIER_TYPE or
|
||||
device_type in POLARIS_COOKER_TYPE or
|
||||
device_type in POLARIS_COFFEEMAKER_ROG_TYPE or
|
||||
device_type in POLARIS_COFFEEMAKER_TYPE or
|
||||
device_type in POLARIS_CLIMATE_TYPE or
|
||||
device_type in POLARIS_AIRCLEANER_TYPE or
|
||||
device_type in POLARIS_AIRCLEANER_EAP_TYPE or
|
||||
device_type in POLARIS_BOILER_TYPE or
|
||||
device_type in POLARIS_VACUUM_TYPE or
|
||||
device_type in POLARIS_IRRIGATOR_TYPE or
|
||||
device_type in POLARIS_HEATER_TYPE or
|
||||
device_type in POLARIS_AIRCONDITIONER_TYPE or
|
||||
device_type in POLARIS_THERMOSTAT_TYPE):
|
||||
BINARYSENSOR_AVAILABLE_LC = copy.deepcopy(BINARYSENSOR_AVAILABLE)
|
||||
for description in BINARYSENSOR_AVAILABLE_LC:
|
||||
description.mqttTopicStatus = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicStatus}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
binarysensorList.append(
|
||||
PolarisBinarySensor(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
|
||||
async_add_entities(binarysensorList, update_before_add=True)
|
||||
|
||||
|
||||
class PolarisBinarySensor(PolarisBaseEntity, BinarySensorEntity, ConfigEntry):
|
||||
|
||||
entity_description: PolarisBinarySensorEntityDescription
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
device_friendly_name: str,
|
||||
description: PolarisBinarySensorEntityDescription,
|
||||
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_has_entity_name = True
|
||||
self._attr_is_on = False
|
||||
self.device_entities = []
|
||||
if self.entity_description.name != "available":
|
||||
self._attr_available = False
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
@callback
|
||||
async def message_received_base(message):
|
||||
if int(self.device_type) == 45 and self.entity_description.key == "cappuccinator":
|
||||
if int(message.payload) == 255:
|
||||
self._attr_is_on = False
|
||||
service_data = {}
|
||||
service_data["entity_id"] = f"number.{POLARIS_DEVICE[int(self.device_type)]['class']}_{POLARIS_DEVICE[int(self.device_type)]['model'].replace('-', '_')}_tank"
|
||||
service_data["value"] = 7.777
|
||||
await self.hass.services.async_call("number", "set_value", service_data)
|
||||
else:
|
||||
self._attr_is_on = True
|
||||
elif str(message.payload).lower() in ("1", "true"):
|
||||
if self.entity_description.name == "available":
|
||||
self._attr_is_on = False
|
||||
# await self.update_device_availability(False)
|
||||
# await self.get_device_entities(False)
|
||||
else:
|
||||
self._attr_is_on = True
|
||||
elif str(message.payload).lower() in ("0", "false"):
|
||||
if self.entity_description.name == "available":
|
||||
self._attr_is_on = True
|
||||
# await self.update_device_availability(True)
|
||||
# await self.get_device_entities(True)
|
||||
else:
|
||||
self._attr_is_on = False
|
||||
self.async_write_ha_state()
|
||||
|
||||
|
||||
await mqtt.async_subscribe(
|
||||
self.hass,
|
||||
self.entity_description.mqttTopicStatus,
|
||||
message_received_base,
|
||||
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 get_device_entities(self, available: bool): # -> List[Entity]:
|
||||
"""Return a list of entities that belong to the same device as this binary sensor"""
|
||||
entities = []
|
||||
entity_registry = ent_reg.async_get(self.hass)
|
||||
entity_entry = entity_registry.async_get(self.entity_id)
|
||||
_LOGGER.debug("-------------------------------------------------")
|
||||
_LOGGER.debug("entity_id 0 %s", self.entity_id)
|
||||
if entity_entry:
|
||||
_LOGGER.debug("entity_entry 0 %s", entity_entry)
|
||||
dev_id = entity_entry.device_id
|
||||
_LOGGER.debug("dev_id 0 %s", dev_id)
|
||||
entity_ids = [
|
||||
entry.entity_id for entry in entity_registry.entities.values()
|
||||
if entry.device_id == dev_id
|
||||
]
|
||||
_LOGGER.debug("entity_ids 0 %s", entity_ids)
|
||||
for entity_id_av in entity_ids:
|
||||
entity_av = self.hass.states.get(entity_id_av)
|
||||
if entity_av:
|
||||
_LOGGER.debug("entity off: %s", entity_av)
|
||||
# entity_av.attributes["_attr_available"] = available
|
||||
self.hass.states.async_set(entity_id_av, entity_av.state, entity_av.attributes)
|
||||
|
||||
# return entities
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# async def get_device_entities(self) -> List[Entity]:
|
||||
# """Return a list of entities that belong to the same device as this binary sensor"""
|
||||
# entities = []
|
||||
# for entity in self.hass.entities:
|
||||
# dev_find = f"{POLARIS_DEVICE[int(self.device_type)]['class'].replace('-', '_').lower()}_{POLARIS_DEVICE[int(self.device_type)]['model'].replace('-', '_').lower()}"
|
||||
# if dev_find in entity.entity_id:
|
||||
# entities.append(entity.entity_id)
|
||||
# return entities
|
||||
|
||||
|
||||
|
||||
|
||||
# async def update_device_availability(self, available: bool):
|
||||
# """Обновляет статус устройства в Device Registry."""
|
||||
# dev_registry = dev_reg.async_get(self.hass)
|
||||
# device = dev_registry.async_get_device(self.device_info["identifiers"])
|
||||
|
||||
# if device:
|
||||
# for entry in self.hass.config_entries.async_entries():
|
||||
# if entry.domain == "polaris" and entry.unique_id == f"{POLARIS_DEVICE[int(self.device_type)]['class']}-{POLARIS_DEVICE[int(self.device_type)]['model']}-{self.device_id}":
|
||||
# config_entries = entry
|
||||
# if available:
|
||||
# dev_registry.async_update_device(device.id, disabled_by = None)
|
||||
# state = self.hass.states.get(self.entity_id)
|
||||
# if state == None:
|
||||
# delta_time = 1000
|
||||
# else:
|
||||
# self._new_time_available = datetime.now().timestamp()
|
||||
# delta_time = self._new_time_available - state.last_changed.timestamp()
|
||||
# if delta_time > 5:
|
||||
# await self.hass.config_entries.async_reload(config_entries.entry_id)
|
||||
# else:
|
||||
# dev_registry.async_update_device(device.id, disabled_by = DeviceEntryDisabler.INTEGRATION)
|
||||
|
||||
364
homeassistant/config/custom_components/polaris/button.py
Normal file
364
homeassistant/config/custom_components/polaris/button.py
Normal file
@@ -0,0 +1,364 @@
|
||||
"""The Polaris IQ Home component."""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
import logging
|
||||
from typing import Iterable
|
||||
import copy
|
||||
from datetime import datetime
|
||||
import os
|
||||
|
||||
from homeassistant.components import mqtt
|
||||
from homeassistant.components.mqtt.models import ReceiveMessage
|
||||
from homeassistant.components.button import (
|
||||
DOMAIN,
|
||||
ButtonDeviceClass,
|
||||
ButtonEntity,
|
||||
ButtonEntityDescription,
|
||||
)
|
||||
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 homeassistant.helpers import entity_registry as er
|
||||
from .common import PolarisBaseEntity
|
||||
# Import global values.
|
||||
from .const import (
|
||||
MANUFACTURER,
|
||||
MQTT_ROOT_TOPIC,
|
||||
DEVICEID,
|
||||
DEVICETYPE,
|
||||
POLARIS_DEVICE,
|
||||
CUSTOM_SELECT_FILE_PATH,
|
||||
BUTTON_HUMIDIFIER,
|
||||
BUTTON_COOKER,
|
||||
SELECT_COOKER,
|
||||
BUTTON_COFFEEMAKER,
|
||||
SELECT_COFFEEMAKER,
|
||||
SELECT_COFFEEMAKER_ROG,
|
||||
BUTTON_CLIMATES,
|
||||
BUTTON_CLIMATES_200,
|
||||
BUTTON_AIRCLEANER,
|
||||
PolarisButtonEntityDescription,
|
||||
POLARIS_KETTLE_TYPE,
|
||||
POLARIS_KETTLE_WITH_WEIGHT_TYPE,
|
||||
POLARIS_HUMIDDIFIER_TYPE,
|
||||
POLARIS_COOKER_TYPE,
|
||||
POLARIS_COFFEEMAKER_TYPE,
|
||||
POLARIS_COFFEEMAKER_ROG_TYPE,
|
||||
POLARIS_CLIMATE_TYPE,
|
||||
POLARIS_AIRCLEANER_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"]
|
||||
buttonList = []
|
||||
|
||||
if (device_type in POLARIS_HUMIDDIFIER_TYPE and device_type not in {"835","881"}):
|
||||
BUTTON_HUMIDIFIER_LC = copy.deepcopy(BUTTON_HUMIDIFIER)
|
||||
for description in BUTTON_HUMIDIFIER_LC:
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
buttonList.append(
|
||||
PolarisButton(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id,
|
||||
device_prefix_topic=device_prefix_topic,
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_COOKER_TYPE):
|
||||
BUTTON_COOKER_LC = copy.deepcopy(BUTTON_COOKER)
|
||||
for description in BUTTON_COOKER_LC:
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
buttonList.append(
|
||||
PolarisButton(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id,
|
||||
device_prefix_topic=device_prefix_topic,
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_COFFEEMAKER_TYPE):
|
||||
BUTTON_COFFEEMAKER_LC = copy.deepcopy(BUTTON_COFFEEMAKER)
|
||||
for description in BUTTON_COFFEEMAKER_LC:
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
buttonList.append(
|
||||
PolarisButton(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id,
|
||||
device_prefix_topic=device_prefix_topic,
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_COFFEEMAKER_ROG_TYPE):
|
||||
BUTTON_COFFEEMAKER_LC = copy.deepcopy(BUTTON_COFFEEMAKER)
|
||||
for description in BUTTON_COFFEEMAKER_LC:
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
buttonList.append(
|
||||
PolarisButton(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id,
|
||||
device_prefix_topic=device_prefix_topic,
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_CLIMATE_TYPE):
|
||||
if (device_type == "859"):
|
||||
BUTTON_CLIMATES_200_LC = copy.deepcopy(BUTTON_CLIMATES_200)
|
||||
for description in BUTTON_CLIMATES_200_LC:
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
buttonList.append(
|
||||
PolarisButton(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id,
|
||||
device_prefix_topic=device_prefix_topic,
|
||||
)
|
||||
)
|
||||
else:
|
||||
BUTTON_CLIMATES_LC = copy.deepcopy(BUTTON_CLIMATES)
|
||||
for description in BUTTON_CLIMATES_LC:
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
buttonList.append(
|
||||
PolarisButton(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id,
|
||||
device_prefix_topic=device_prefix_topic,
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_AIRCLEANER_TYPE):
|
||||
BUTTON_AIRCLEANER_LC = copy.deepcopy(BUTTON_AIRCLEANER)
|
||||
for description in BUTTON_AIRCLEANER_LC:
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
buttonList.append(
|
||||
PolarisButton(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id,
|
||||
device_prefix_topic=device_prefix_topic,
|
||||
)
|
||||
)
|
||||
async_add_entities(buttonList, update_before_add=True)
|
||||
|
||||
|
||||
class PolarisButton(PolarisBaseEntity, ButtonEntity):
|
||||
|
||||
entity_description: PolarisButtonDescription
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
device_friendly_name: str,
|
||||
description: PolarisButtonEntityDescription,
|
||||
mqtt_root: str,
|
||||
device_id: str | None=None,
|
||||
device_type: str | None=None,
|
||||
device_prefix_topic: 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_available = False
|
||||
self._attr_has_entity_name = True
|
||||
self.device_prefix_topic = device_prefix_topic
|
||||
|
||||
|
||||
|
||||
if POLARIS_DEVICE[int(self.device_type)]['class'] == "cooker":
|
||||
self._select_options = json.loads(json.dumps(SELECT_COOKER[0].options))
|
||||
if POLARIS_DEVICE[int(self.device_type)]['class'] == "coffeemaker":
|
||||
if int(self.device_type) == 45:
|
||||
self._select_options = json.loads(json.dumps(SELECT_COFFEEMAKER_ROG[0].options))
|
||||
else:
|
||||
self._select_options = json.loads(json.dumps(SELECT_COFFEEMAKER[0].options))
|
||||
|
||||
self._custom_data_select = self._read_file()
|
||||
if self._custom_data_select is not None:
|
||||
if POLARIS_DEVICE[int(self.device_type)]['class'] == "cooker" and "SELECT_COOKER_options" in self._custom_data_select:
|
||||
# self._select_options = json.loads(json.dumps(SELECT_COOKER[0].options))
|
||||
for key, value in self._custom_data_select["SELECT_COOKER_options"].items():
|
||||
self._select_options[key] = json.dumps([value])
|
||||
# _LOGGER.debug("cooker %s", self._select_options)
|
||||
if POLARIS_DEVICE[int(self.device_type)]['class'] == "coffeemaker":
|
||||
if int(self.device_type) == 45 and "SELECT_COFFEEMAKER_ROG_options" in self._custom_data_select:
|
||||
# self._select_options = json.loads(json.dumps(SELECT_COFFEEMAKER_ROG[0].options))
|
||||
for key, value in self._custom_data_select["SELECT_COFFEEMAKER_ROG_options"].items():
|
||||
self._select_options[key] = json.dumps([value])
|
||||
# _LOGGER.debug("coffee_rog %s", self._select_options)
|
||||
elif "SELECT_COFFEEMAKER_options" in self._custom_data_select:
|
||||
# self._select_options = json.loads(json.dumps(SELECT_COFFEEMAKER[0].options))
|
||||
for key, value in self._custom_data_select["SELECT_COFFEEMAKER_options"].items():
|
||||
self._select_options[key] = json.dumps([value])
|
||||
# _LOGGER.debug("coffee %s", self._select_options)
|
||||
|
||||
|
||||
# self._attr_options = list(self._select_options.keys())
|
||||
# self._attr_current_option = self._attr_options[0]
|
||||
|
||||
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
@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)
|
||||
|
||||
|
||||
def _read_file(self):
|
||||
file_path = CUSTOM_SELECT_FILE_PATH
|
||||
if os.path.exists(file_path):
|
||||
with open(file_path, 'r', encoding='utf-8') as file:
|
||||
content = json.loads(file.read())
|
||||
else:
|
||||
content = None
|
||||
return content
|
||||
|
||||
|
||||
def get_state_by_unique_id(self, entity_domain, entity_name):
|
||||
entity_unique_id = f"{self.device_id}_{entity_name}"
|
||||
entity_registry = er.async_get(self.hass)
|
||||
entity_id = entity_registry.async_get_entity_id(entity_domain, "polaris", entity_unique_id)
|
||||
return self.hass.states.get(entity_id).state
|
||||
|
||||
|
||||
async def async_press(self) -> None:
|
||||
if (self.device_type in POLARIS_COFFEEMAKER_TYPE):
|
||||
if self.entity_description.key == "button_stop":
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommand+"mode", "0")
|
||||
|
||||
# Get entity_id by unique_id
|
||||
# Работает
|
||||
zzzz = self.get_state_by_unique_id("number", "amount")
|
||||
_LOGGER.debug("state %s", zzzz)
|
||||
|
||||
else:
|
||||
state_amount = self.hass.states.get(f"number.{POLARIS_DEVICE[int(self.device_type)]['class']}_{POLARIS_DEVICE[int(self.device_type)]['model'].replace('-', '_')}_amount").state
|
||||
state_weight = self.hass.states.get(f"number.{POLARIS_DEVICE[int(self.device_type)]['class']}_{POLARIS_DEVICE[int(self.device_type)]['model'].replace('-', '_')}_weight").state
|
||||
state_tank = self.hass.states.get(f"number.{POLARIS_DEVICE[int(self.device_type)]['class']}_{POLARIS_DEVICE[int(self.device_type)]['model'].replace('-', '_')}_tank").state
|
||||
state_pressure = self.hass.states.get(f"number.{POLARIS_DEVICE[int(self.device_type)]['class']}_{POLARIS_DEVICE[int(self.device_type)]['model'].replace('-', '_')}_pressure").state
|
||||
state_speed = self.hass.states.get(f"number.{POLARIS_DEVICE[int(self.device_type)]['class']}_{POLARIS_DEVICE[int(self.device_type)]['model'].replace('-', '_')}_speed").state
|
||||
state_temp = self.hass.states.get(f"number.{POLARIS_DEVICE[int(self.device_type)]['class']}_{POLARIS_DEVICE[int(self.device_type)]['model'].replace('-', '_')}_temperature").state
|
||||
state_mode = self.hass.states.get(f"select.{POLARIS_DEVICE[int(self.device_type)]['class']}_{POLARIS_DEVICE[int(self.device_type)]['model'].replace('-', '_')}_select_mode_cofeemaker").state
|
||||
state_coffee_maker = self.hass.states.get(f"switch.{POLARIS_DEVICE[int(self.device_type)]['class']}_{POLARIS_DEVICE[int(self.device_type)]['model'].replace('-', '_')}_power").state
|
||||
if state_coffee_maker != "off":
|
||||
if state_amount != "unavailable":
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommand+"amount", state_amount)
|
||||
if state_weight != "unavailable":
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommand+"weight", state_weight)
|
||||
if state_tank != "unavailable":
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommand+"tank", state_tank)
|
||||
if state_pressure != "unavailable":
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommand+"pressure", state_pressure)
|
||||
if state_speed != "unavailable":
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommand+"speed", state_speed)
|
||||
if state_temp != "unavailable":
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommand+"temperature", state_temp)
|
||||
if state_mode != "not_selected":
|
||||
# !!!
|
||||
command_mode = self._select_options[state_mode]
|
||||
coffee_mode = json.loads(command_mode)
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommand+"mode", coffee_mode[0]["mode"])
|
||||
|
||||
if (self.device_type in POLARIS_COFFEEMAKER_ROG_TYPE):
|
||||
if self.entity_description.key == "button_stop":
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommand+"mode", "0")
|
||||
else:
|
||||
state_amount = self.hass.states.get(f"number.{POLARIS_DEVICE[int(self.device_type)]['class']}_{POLARIS_DEVICE[int(self.device_type)]['model'].replace('-', '_')}_amount").state
|
||||
state_tank = self.hass.states.get(f"number.{POLARIS_DEVICE[int(self.device_type)]['class']}_{POLARIS_DEVICE[int(self.device_type)]['model'].replace('-', '_')}_tank").state
|
||||
state_temp = self.hass.states.get(f"number.{POLARIS_DEVICE[int(self.device_type)]['class']}_{POLARIS_DEVICE[int(self.device_type)]['model'].replace('-', '_')}_temperature").state
|
||||
state_mode = self.hass.states.get(f"select.{POLARIS_DEVICE[int(self.device_type)]['class']}_{POLARIS_DEVICE[int(self.device_type)]['model'].replace('-', '_')}_select_mode_cofeemaker").state
|
||||
state_cappuccinator = self.hass.states.get(f"binary_sensor.{POLARIS_DEVICE[int(self.device_type)]['class']}_{POLARIS_DEVICE[int(self.device_type)]['model'].replace('-', '_')}_cappuccinator").state
|
||||
state_power = self.hass.states.get(f"switch.{POLARIS_DEVICE[int(self.device_type)]['class']}_{POLARIS_DEVICE[int(self.device_type)]['model'].replace('-', '_')}_power").state
|
||||
if state_power == "off":
|
||||
mqtt.publish(self.hass, f"{self.mqtt_root}/{self.device_prefix_topic}/control/mode", 5)
|
||||
if state_cappuccinator == "off" and state_mode in ("cappuccino", "double_cappuccino", "latte", "double_latte", "flat_white", "hot_milk"):
|
||||
mqtt.publish(self.hass, f"{self.mqtt_root}/{self.device_prefix_topic}/state/error/code", "99")
|
||||
return
|
||||
elif state_mode == "not_selected":
|
||||
mqtt.publish(self.hass, f"{self.mqtt_root}/{self.device_prefix_topic}/state/error/code", "98")
|
||||
return
|
||||
else:
|
||||
if state_amount == "unavailable":
|
||||
state_amount = "0"
|
||||
if state_tank == "unavailable":
|
||||
state_tank = "0"
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommand+"amount", state_amount)
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommand+"temperature", state_temp)
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommand+"tank", state_tank)
|
||||
# !!!
|
||||
command_mode = self._select_options[state_mode]
|
||||
coffee_mode = json.loads(command_mode)
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommand+"mode", coffee_mode[0]["mode"])
|
||||
mqtt.publish(self.hass, f"{self.mqtt_root}/{self.device_prefix_topic}/state/error/code", "00")
|
||||
|
||||
|
||||
if POLARIS_DEVICE[int(self.device_type)]['class'] == "cooker":
|
||||
if self.entity_description.key == "button_stop":
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommand, "[]")
|
||||
else:
|
||||
state_temp = self.hass.states.get(f"number.{POLARIS_DEVICE[int(self.device_type)]['class']}_{POLARIS_DEVICE[int(self.device_type)]['model'].replace('-', '_')}_set_temperature").state
|
||||
state_time = self.hass.states.get(f"time.{POLARIS_DEVICE[int(self.device_type)]['class']}_{POLARIS_DEVICE[int(self.device_type)]['model'].replace('-', '_')}_cooking_time").state
|
||||
state_time_obj = datetime.strptime(state_time, "%H:%M:%S")
|
||||
state_time_seconds = state_time_obj.hour * 3600 + state_time_obj.minute * 60 + state_time_obj.second
|
||||
state_mode = self.hass.states.get(f"select.{POLARIS_DEVICE[int(self.device_type)]['class']}_{POLARIS_DEVICE[int(self.device_type)]['model'].replace('-', '_')}_select_mode_cooker").state
|
||||
# !!!
|
||||
command_mode = self._select_options[state_mode]
|
||||
cook_mode = json.loads(command_mode)
|
||||
payload = "[{" + f'"mode":{cook_mode[0]["mode"]}, "time":{state_time_seconds}, "temperature":{state_temp}' + "}]"
|
||||
state_time_delay = self.hass.states.get(f"time.{POLARIS_DEVICE[int(self.device_type)]['class']}_{POLARIS_DEVICE[int(self.device_type)]['model'].replace('-', '_')}_delay_start").state
|
||||
state_time_delay_obj = datetime.strptime(state_time_delay, "%H:%M:%S")
|
||||
state_time_delay_seconds = state_time_delay_obj.hour * 3600 + state_time_delay_obj.minute * 60 + state_time_delay_obj.second
|
||||
if state_time_delay_seconds > 59:
|
||||
mqtt.publish(self.hass, f"{self.mqtt_root}/{self.device_prefix_topic}/control/delay_start", state_time_delay_seconds)
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommand, payload)
|
||||
if POLARIS_DEVICE[int(self.device_type)]['class'] == "humidifier":
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommand, self.entity_description.payloads)
|
||||
if (self.device_type in POLARIS_CLIMATE_TYPE):
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommand, self.entity_description.payloads)
|
||||
if (self.device_type in POLARIS_AIRCLEANER_TYPE):
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommand, self.entity_description.payloads)
|
||||
493
homeassistant/config/custom_components/polaris/climate.py
Normal file
493
homeassistant/config/custom_components/polaris/climate.py
Normal file
@@ -0,0 +1,493 @@
|
||||
"""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.const import ATTR_TEMPERATURE, UnitOfTemperature
|
||||
from homeassistant.components.climate import (
|
||||
DOMAIN,
|
||||
ATTR_HVAC_MODE,
|
||||
ATTR_TARGET_TEMP_HIGH,
|
||||
ATTR_TARGET_TEMP_LOW,
|
||||
ClimateEntity,
|
||||
ClimateEntityFeature,
|
||||
HVACAction,
|
||||
HVACMode,
|
||||
)
|
||||
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
|
||||
# Import global values.
|
||||
from .const import (
|
||||
MANUFACTURER,
|
||||
MQTT_ROOT_TOPIC,
|
||||
DEVICEID,
|
||||
DEVICETYPE,
|
||||
POLARIS_DEVICE,
|
||||
CLIMATES,
|
||||
CLIMATES_200,
|
||||
AIRCLEANER,
|
||||
AIRCLEANER_EAP,
|
||||
CLIMATES_HEATER,
|
||||
CLIMATES_AIRCONDITIONER,
|
||||
CLIMATES_THERMOSTAT,
|
||||
PolarisClimateEntityDescription,
|
||||
POLARIS_CLIMATE_TYPE,
|
||||
POLARIS_AIRCLEANER_TYPE,
|
||||
POLARIS_AIRCLEANER_EAP_TYPE,
|
||||
POLARIS_HEATER_TYPE,
|
||||
POLARIS_AIRCONDITIONER_TYPE,
|
||||
POLARIS_THERMOSTAT_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"]
|
||||
climateList = []
|
||||
|
||||
if (device_type in POLARIS_CLIMATE_TYPE):
|
||||
# Create humidifier
|
||||
if (device_type == "859"):
|
||||
CLIMATES_LC = copy.deepcopy(CLIMATES_200)
|
||||
else:
|
||||
CLIMATES_LC = copy.deepcopy(CLIMATES)
|
||||
for description in CLIMATES_LC:
|
||||
description.mqttTopicStateTemperature = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicStateTemperature}"
|
||||
description.mqttTopicCommandTemperature = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandTemperature}"
|
||||
description.mqttTopicCurrentTemperature = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentTemperature}"
|
||||
description.mqttTopicStateFanMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicStateFanMode}"
|
||||
description.mqttTopicCommandFanMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandFanMode}"
|
||||
description.mqttTopicCommandPower = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandPower}"
|
||||
description.mqttTopicCurrentPresetMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentPresetMode}"
|
||||
description.mqttTopicCommandPresetMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandPresetMode}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
climateList.append(
|
||||
PolarisClimate(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_AIRCLEANER_TYPE):
|
||||
# Create humidifier
|
||||
AIRCLEANER_LC = copy.deepcopy(AIRCLEANER)
|
||||
for description in AIRCLEANER_LC:
|
||||
description.mqttTopicStateFanMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicStateFanMode}"
|
||||
description.mqttTopicCommandFanMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandFanMode}"
|
||||
description.mqttTopicCommandPower = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandPower}"
|
||||
description.mqttTopicCurrentPresetMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentPresetMode}"
|
||||
description.mqttTopicCommandPresetMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandPresetMode}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
climateList.append(
|
||||
PolarisClimate(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_AIRCLEANER_EAP_TYPE):
|
||||
# Create aircleaner
|
||||
AIRCLEANER_EAP_LC = copy.deepcopy(AIRCLEANER_EAP)
|
||||
for description in AIRCLEANER_EAP_LC:
|
||||
description.mqttTopicStateFanMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicStateFanMode}"
|
||||
description.mqttTopicCommandFanMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandFanMode}"
|
||||
description.mqttTopicCommandPower = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandPower}"
|
||||
description.mqttTopicCurrentPresetMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentPresetMode}"
|
||||
description.mqttTopicCommandPresetMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandPresetMode}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
climateList.append(
|
||||
PolarisClimate(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_HEATER_TYPE):
|
||||
# Create Heater
|
||||
CLIMATES_HEATER_LC = copy.deepcopy(CLIMATES_HEATER)
|
||||
for description in CLIMATES_HEATER_LC:
|
||||
description.mqttTopicStateTemperature = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicStateTemperature}"
|
||||
description.mqttTopicCommandTemperature = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandTemperature}"
|
||||
description.mqttTopicCurrentTemperature = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentTemperature}"
|
||||
description.mqttTopicStateFanMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicStateFanMode}"
|
||||
description.mqttTopicCommandFanMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandFanMode}"
|
||||
description.mqttTopicCommandPower = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandPower}"
|
||||
description.mqttTopicCurrentPresetMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentPresetMode}"
|
||||
description.mqttTopicCommandPresetMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandPresetMode}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
climateList.append(
|
||||
PolarisClimate(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_AIRCONDITIONER_TYPE):
|
||||
# Create AIRCONDITIONER
|
||||
CLIMATES_AIRCONDITIONER_LC = copy.deepcopy(CLIMATES_AIRCONDITIONER)
|
||||
for description in CLIMATES_AIRCONDITIONER_LC:
|
||||
description.mqttTopicStateTemperature = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicStateTemperature}"
|
||||
description.mqttTopicCommandTemperature = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandTemperature}"
|
||||
description.mqttTopicCurrentTemperature = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentTemperature}"
|
||||
description.mqttTopicStateFanMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicStateFanMode}"
|
||||
description.mqttTopicCommandFanMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandFanMode}"
|
||||
description.mqttTopicCommandPower = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandPower}"
|
||||
description.mqttTopicCurrentPresetMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentPresetMode}"
|
||||
description.mqttTopicCommandPresetMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandPresetMode}"
|
||||
description.mqttTopicStateSwingMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicStateSwingMode}"
|
||||
description.mqttTopicCommandSwingMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandSwingMode}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
climateList.append(
|
||||
PolarisClimate(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_THERMOSTAT_TYPE):
|
||||
# Create THERMOSTAT
|
||||
CLIMATES_THERMOSTAT_LC = copy.deepcopy(CLIMATES_THERMOSTAT)
|
||||
for description in CLIMATES_THERMOSTAT_LC:
|
||||
description.mqttTopicStateTemperature = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicStateTemperature}"
|
||||
description.mqttTopicCommandTemperature = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandTemperature}"
|
||||
description.mqttTopicCurrentTemperature = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentTemperature}"
|
||||
description.mqttTopicCommandPower = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandPower}"
|
||||
description.mqttTopicCurrentPresetMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentPresetMode}"
|
||||
description.mqttTopicCommandPresetMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandPresetMode}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
climateList.append(
|
||||
PolarisClimate(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
async_add_entities(climateList, update_before_add=True)
|
||||
|
||||
|
||||
class PolarisClimate(PolarisBaseEntity, ClimateEntity):
|
||||
|
||||
entity_description: PolarisClimateEntityDescription
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
device_friendly_name: str,
|
||||
description: PolarisClimateEntityDescription,
|
||||
mqtt_root: str,
|
||||
device_id: str | None=None,
|
||||
device_type: str | None=None,
|
||||
device_class: ClimateDeviceClass | 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.payload_on=description.payload_on
|
||||
self.payload_off=description.payload_off
|
||||
self._attr_has_entity_name = True
|
||||
|
||||
self._attr_precision = 1.0
|
||||
self._attr_target_temperature_step = 1.0
|
||||
self._attr_hvac_modes = self.entity_description.hvac_modes
|
||||
self._attr_preset_modes = list(self.entity_description.preset_modes.keys())
|
||||
if device_type in {"806","847"}:
|
||||
self.entity_description.fan_modes = {"auto": "0", "20_5_percent": "1", "40_5_percent": "2", "60_5_percent": "3", "80_5_percent": "4", "100_5_percent": "5"}
|
||||
if device_type == "820":
|
||||
self.entity_description.fan_modes = {"auto": "0", "low": "1", "middle": "2", "high": "3"}
|
||||
if self.entity_description.fan_modes is not None:
|
||||
self._attr_fan_modes = list(self.entity_description.fan_modes.keys())
|
||||
self._attr_fan_mode = self.entity_description.fan_mode
|
||||
self._attr_supported_features = self.entity_description.supported_features
|
||||
self._enable_turn_on_off_backwards_compatibility = False
|
||||
self._attr_temperature_unit = UnitOfTemperature.CELSIUS
|
||||
|
||||
self._attr_precision = self.entity_description.temp_step
|
||||
self._attr_target_temperature = 20
|
||||
if device_type == "820":
|
||||
self._attr_max_temp = 32
|
||||
else:
|
||||
self._attr_max_temp = self.entity_description.max_temp
|
||||
self._attr_min_temp = self.entity_description.min_temp
|
||||
self._attr_preset_mode = self.entity_description.preset_mode
|
||||
self._attr_hvac_mode = HVACMode.OFF
|
||||
self._attr_available = False
|
||||
|
||||
if self.entity_description.swing_mode is not None:
|
||||
self._attr_swing_mode = self.entity_description.swing_mode
|
||||
self._attr_swing_modes = list(self.entity_description.swing_modes.keys())
|
||||
# self._attr_supported_features |= ClimateEntityFeature.SWING_MODE
|
||||
self._swing_message = "00000000"
|
||||
if device_type == "826":
|
||||
self._EAP_data0 = "0000"
|
||||
if device_type == "882":
|
||||
self._swing_message = "000000000000"
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
@callback
|
||||
def message_received_curr_temp(message):
|
||||
self._attr_current_temperature = float(message.payload)
|
||||
self.async_write_ha_state()
|
||||
@callback
|
||||
def message_received_targ_temp(message):
|
||||
if float(message.payload) < self._attr_min_temp:
|
||||
self._attr_target_temperature = self._attr_min_temp
|
||||
else:
|
||||
self._attr_target_temperature = float(message.payload)
|
||||
self.async_write_ha_state()
|
||||
@callback
|
||||
def message_received_mode(message):
|
||||
payload = message.payload
|
||||
if int(payload)==0:
|
||||
self._attr_hvac_mode = HVACMode.OFF
|
||||
elif (self.device_type in POLARIS_AIRCLEANER_TYPE):
|
||||
self._attr_hvac_mode = HVACMode.DRY
|
||||
elif (self.device_type in POLARIS_AIRCLEANER_EAP_TYPE):
|
||||
self._attr_hvac_mode = HVACMode.DRY
|
||||
elif (self.device_type in POLARIS_HEATER_TYPE):
|
||||
self._attr_hvac_mode = HVACMode.HEAT
|
||||
elif (self.device_type in POLARIS_THERMOSTAT_TYPE):
|
||||
self._attr_hvac_mode = HVACMode.HEAT
|
||||
elif (self.device_type in POLARIS_AIRCONDITIONER_TYPE):
|
||||
match int(payload):
|
||||
case 1:
|
||||
self._attr_hvac_mode = HVACMode.AUTO
|
||||
case 3:
|
||||
self._attr_hvac_mode = HVACMode.DRY
|
||||
case 5:
|
||||
self._attr_hvac_mode = HVACMode.FAN_ONLY
|
||||
case 4:
|
||||
self._attr_hvac_mode = HVACMode.HEAT
|
||||
case 2:
|
||||
self._attr_hvac_mode = HVACMode.COOL
|
||||
else:
|
||||
self._attr_hvac_mode = HVACMode.FAN_ONLY
|
||||
self.async_write_ha_state()
|
||||
@callback
|
||||
def message_received_preset_mode(message):
|
||||
payload = message.payload
|
||||
if int(payload) > 0:
|
||||
self._attr_preset_mode = list(self.entity_description.preset_modes.keys())[list(self.entity_description.preset_modes.values()).index(payload)]
|
||||
if self.device_type == "826":
|
||||
self._EAP_data0 = "0" + payload + self._EAP_data0[-2:]
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandPresetMode.replace("mode", "program_data/0"), self._EAP_data0)
|
||||
self.async_write_ha_state()
|
||||
@callback
|
||||
def message_received_fan_mode(message):
|
||||
self._attr_fan_mode = list(self.entity_description.fan_modes.keys())[list(self.entity_description.fan_modes.values()).index(message.payload)]
|
||||
self.async_write_ha_state()
|
||||
@callback
|
||||
def message_received_swing_mode(message):
|
||||
# _LOGGER.debug("swing message %s", message.payload)
|
||||
self._swing_message = message.payload # 00112233 00-качание верх/низ 11-качание влево/вправо 22-эко режим охлаждения 33-автообогрев
|
||||
match self._swing_message[:4]:
|
||||
case "0000":
|
||||
swmode = "off"
|
||||
case "0001":
|
||||
swmode = "horizontal"
|
||||
case "0100":
|
||||
swmode = "vertical"
|
||||
case "0101":
|
||||
swmode = "both"
|
||||
# _LOGGER.debug("swing mode %s", swmode)
|
||||
self._attr_swing_mode = swmode
|
||||
self.async_write_ha_state()
|
||||
|
||||
@callback
|
||||
def EAP_data_message_received(message):
|
||||
self._EAP_data0 = message.payload
|
||||
# _LOGGER.debug("EAP mode data0 message %s", self._EAP_data0)
|
||||
|
||||
|
||||
if self.device_type == "826":
|
||||
await mqtt.async_subscribe(
|
||||
self.hass,
|
||||
self.entity_description.mqttTopicCurrentPresetMode.replace("mode", "program_data/0"),
|
||||
EAP_data_message_received,
|
||||
1,
|
||||
)
|
||||
|
||||
|
||||
if self.entity_description.mqttTopicCurrentTemperature is not None:
|
||||
await mqtt.async_subscribe(
|
||||
self.hass,
|
||||
self.entity_description.mqttTopicCurrentTemperature,
|
||||
message_received_curr_temp,
|
||||
1,
|
||||
)
|
||||
if self.entity_description.mqttTopicStateTemperature is not None:
|
||||
await mqtt.async_subscribe(
|
||||
self.hass,
|
||||
self.entity_description.mqttTopicStateTemperature,
|
||||
message_received_targ_temp,
|
||||
1,
|
||||
)
|
||||
await mqtt.async_subscribe(
|
||||
self.hass,
|
||||
self.entity_description.mqttTopicCurrentPresetMode,
|
||||
message_received_mode,
|
||||
1,
|
||||
)
|
||||
await mqtt.async_subscribe(
|
||||
self.hass,
|
||||
self.entity_description.mqttTopicCurrentPresetMode,
|
||||
message_received_preset_mode,
|
||||
1,
|
||||
)
|
||||
if self.entity_description.mqttTopicStateFanMode is not None:
|
||||
await mqtt.async_subscribe(
|
||||
self.hass,
|
||||
self.entity_description.mqttTopicStateFanMode,
|
||||
message_received_fan_mode,
|
||||
1,
|
||||
)
|
||||
if self.entity_description.mqttTopicStateSwingMode is not None:
|
||||
await mqtt.async_subscribe(
|
||||
self.hass,
|
||||
self.entity_description.mqttTopicStateSwingMode,
|
||||
message_received_swing_mode,
|
||||
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) -> None:
|
||||
if (self.device_type in POLARIS_AIRCLEANER_TYPE):
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandPower, 1)
|
||||
await self.async_set_hvac_mode(HVACMode.DRY)
|
||||
elif (self.device_type in POLARIS_AIRCLEANER_EAP_TYPE):
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandPower, 1)
|
||||
await self.async_set_hvac_mode(HVACMode.DRY)
|
||||
elif (self.device_type in POLARIS_HEATER_TYPE):
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandPower, 1)
|
||||
await self.async_set_hvac_mode(HVACMode.HEAT)
|
||||
elif (self.device_type in POLARIS_THERMOSTAT_TYPE):
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandPower, 1)
|
||||
await self.async_set_hvac_mode(HVACMode.HEAT)
|
||||
else:
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandPower, 5)
|
||||
await self.async_set_hvac_mode(HVACMode.FAN_ONLY)
|
||||
|
||||
async def async_turn_off(self) -> None:
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandPower, 0)
|
||||
await self.async_set_hvac_mode(HVACMode.OFF)
|
||||
|
||||
async def async_set_temperature(self, **kwargs: Any) -> None:
|
||||
"""Set new target temperatures."""
|
||||
if kwargs.get(ATTR_TEMPERATURE) is not None:
|
||||
self._attr_target_temperature = kwargs.get(ATTR_TEMPERATURE)
|
||||
if (kwargs.get(ATTR_TARGET_TEMP_HIGH) is not None and kwargs.get(ATTR_TARGET_TEMP_LOW) is not None):
|
||||
self._attr_target_temperature_high = kwargs.get(ATTR_TARGET_TEMP_HIGH)
|
||||
self._attr_target_temperature_low = kwargs.get(ATTR_TARGET_TEMP_LOW)
|
||||
if (hvac_mode := kwargs.get(ATTR_HVAC_MODE)) is not None:
|
||||
self._attr_hvac_mode = hvac_mode
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandTemperature, int(self._attr_target_temperature))
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_set_fan_mode(self, fan_mode: str) -> None:
|
||||
"""Set new fan mode."""
|
||||
if (fan_mode == "9_speed"):
|
||||
fan_mode = "8_speed"
|
||||
if (self.device_type == "826" and fan_mode == "off"):
|
||||
fan_mode = "low"
|
||||
self._attr_fan_mode = fan_mode
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandFanMode, self.entity_description.fan_modes[fan_mode])
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
||||
"""Set new operation mode."""
|
||||
self._attr_hvac_mode = hvac_mode
|
||||
if hvac_mode == "off":
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandPresetMode, 0)
|
||||
elif ((self.device_type in POLARIS_AIRCLEANER_TYPE) or (self.device_type in POLARIS_HEATER_TYPE) or (self.device_type in POLARIS_AIRCLEANER_EAP_TYPE)):
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandPower, 1)
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandFanMode, self.entity_description.fan_modes[self._attr_fan_mode]) # add for on fan after off heater
|
||||
elif (self.device_type in POLARIS_AIRCONDITIONER_TYPE):
|
||||
match hvac_mode:
|
||||
case "auto":
|
||||
command = 1
|
||||
case "dry":
|
||||
command = 3
|
||||
case "fan_only":
|
||||
command = 5
|
||||
case "heat":
|
||||
command = 4
|
||||
case "cool":
|
||||
command = 2
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandPresetMode, command)
|
||||
else:
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandPresetMode, 5) # 5 = FAN_ONLY for AIRCLEANER and HEATER_TYPE
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_set_preset_mode(self, preset_mode: str) -> None:
|
||||
"""Update preset_mode on."""
|
||||
self._attr_preset_mode = preset_mode
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandPresetMode, self.entity_description.preset_modes[preset_mode])
|
||||
if self.device_type == "826":
|
||||
if (preset_mode != "night" and int(self._EAP_data0[-2:]) > 1):
|
||||
self._EAP_data0 = "0" + self.entity_description.preset_modes[preset_mode] + "01"
|
||||
else:
|
||||
self._EAP_data0 = "0" + self.entity_description.preset_modes[preset_mode] + self._EAP_data0[-2:]
|
||||
# _LOGGER.debug("EAP data0 mode select %s", self._EAP_data0) # отправить в prog_data
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandPresetMode.replace("mode", "program_data/0"), self._EAP_data0)
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_set_swing_mode(self, swing_mode: str) -> None:
|
||||
"""Set new swing mode."""
|
||||
self._attr_swing_mode = swing_mode
|
||||
# _LOGGER.debug("set swing mode %s", swing_mode)
|
||||
match swing_mode:
|
||||
case "off":
|
||||
swmessage = "0000"
|
||||
case "horizontal":
|
||||
swmessage = "0001"
|
||||
case "vertical":
|
||||
swmessage = "0100"
|
||||
case "both":
|
||||
swmessage = "0101"
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandSwingMode, swmessage + self._swing_message[4:])
|
||||
self.async_write_ha_state()
|
||||
35
homeassistant/config/custom_components/polaris/common.py
Normal file
35
homeassistant/config/custom_components/polaris/common.py
Normal file
@@ -0,0 +1,35 @@
|
||||
"""The Polaris IQ Home component."""
|
||||
|
||||
import logging
|
||||
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from .const import DOMAIN, MANUFACTURER, POLARIS_DEVICE
|
||||
|
||||
#_LOGGER = logging.getLogger(__name__)
|
||||
#_LOGGER.setLevel(logging.DEBUG)
|
||||
|
||||
class PolarisBaseEntity:
|
||||
|
||||
deviceID: str | None = None
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
device_friendly_name: str,
|
||||
mqtt_root: str,
|
||||
device_type: str,
|
||||
device_id: str
|
||||
) -> None:
|
||||
self.device_friendly_name = device_friendly_name
|
||||
self.mqtt_root = mqtt_root
|
||||
self.device_type=device_type
|
||||
self.device_id=device_id
|
||||
|
||||
|
||||
@property
|
||||
def device_info(self) -> DeviceInfo:
|
||||
return DeviceInfo(
|
||||
name=POLARIS_DEVICE[int(self.device_type)]["class"]+" "+ POLARIS_DEVICE[int(self.device_type)]["model"],
|
||||
identifiers={(DOMAIN, self.device_id, self.mqtt_root)},
|
||||
manufacturer=MANUFACTURER,
|
||||
model=POLARIS_DEVICE[int(self.device_type)]["class"]+" - "+ POLARIS_DEVICE[int(self.device_type)]["model"],
|
||||
)
|
||||
194
homeassistant/config/custom_components/polaris/config_flow.py
Normal file
194
homeassistant/config/custom_components/polaris/config_flow.py
Normal file
@@ -0,0 +1,194 @@
|
||||
"""The Polaris IQ Home component."""
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
import time
|
||||
import voluptuous as vol
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
from homeassistant.config_entries import ConfigFlow
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.components import mqtt
|
||||
from homeassistant.helpers.translation import async_get_translations
|
||||
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
from homeassistant.helpers.selector import (
|
||||
SelectOptionDict,
|
||||
SelectSelector,
|
||||
SelectSelectorConfig,
|
||||
SelectSelectorMode,
|
||||
)
|
||||
|
||||
from .const import DEVICEID, DEVICETYPE, DOMAIN, MQTT_ROOT_TOPIC, MQTT_ROOT_TOPIC_DEFAULT, POLARIS_DEVICE
|
||||
from homeassistant.helpers.service_info.mqtt import MqttServiceInfo
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
_LOGGER.setLevel(logging.DEBUG)
|
||||
|
||||
|
||||
class PolarisConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
|
||||
VERSION = 1
|
||||
|
||||
def __init__(self) -> None:
|
||||
"""Initialize flow."""
|
||||
self._serial_number = None
|
||||
self._topic_prefix = {}
|
||||
self._device_found = {}
|
||||
self._device_prefix_topic = {}
|
||||
self._unknown_devtype = 0
|
||||
|
||||
|
||||
async def _get_devtypes_from_mqtt(self):
|
||||
await mqtt.async_subscribe(self.hass, "polaris/+/state/mac", self._mqtt_message_newdev)
|
||||
await mqtt.async_subscribe(self.hass, "polaris/+/+/state/mac", self._mqtt_message_olddev)
|
||||
await mqtt.async_subscribe(self.hass, "rusclimate/+/+/state/mac", self._mqtt_message_rusclidev)
|
||||
|
||||
@callback
|
||||
async def _mqtt_message_newdev(self, message: ReceiveMessage):
|
||||
topic = message.topic
|
||||
device_id = topic.split("/")[1]
|
||||
topic_check = f"polaris/{device_id}/state/devtype"
|
||||
topic_bool = await self.topic_exists(topic_check)
|
||||
if not topic_bool:
|
||||
self._device_type = "0"
|
||||
if int(self._device_type) not in POLARIS_DEVICE:
|
||||
# _LOGGER.debug("newdevice unknown - %s", self._device_type)
|
||||
self._unknown_devtype = int(self._device_type)
|
||||
if device_id not in self._device_found:
|
||||
self._device_found[device_id] = self._device_type
|
||||
self._device_prefix_topic[device_id] = device_id
|
||||
self._topic_prefix[device_id] = "polaris"
|
||||
|
||||
@callback
|
||||
async def _mqtt_message_olddev(self, message: ReceiveMessage):
|
||||
topic = message.topic
|
||||
device_id = message.payload
|
||||
device_type = topic.split("/")[1]
|
||||
device_oldid = topic.split("/")[2]
|
||||
if int(device_type) not in POLARIS_DEVICE:
|
||||
# _LOGGER.debug("olddevice unknown - %s", device_type)
|
||||
self._unknown_devtype = int(device_type)
|
||||
if device_id not in self._device_found:
|
||||
self._device_found[device_id] = device_type
|
||||
self._device_prefix_topic[device_id] = f"{device_type}/{device_oldid}"
|
||||
self._topic_prefix[device_id] = "polaris"
|
||||
|
||||
@callback
|
||||
async def _mqtt_message_rusclidev(self, message: ReceiveMessage):
|
||||
topic = message.topic
|
||||
device_id = message.payload
|
||||
device_type = str(int(topic.split("/")[1]) + 800)
|
||||
device_oldid = topic.split("/")[2]
|
||||
if int(device_type) not in POLARIS_DEVICE:
|
||||
# _LOGGER.debug("rusclidevice unknown - %s", device_type)
|
||||
self._unknown_devtype = int(device_type)
|
||||
if device_id not in self._device_found:
|
||||
self._device_found[device_id] = device_type
|
||||
self._device_prefix_topic[device_id] = f"{topic.split("/")[1]}/{device_oldid}"
|
||||
self._topic_prefix[device_id] = "rusclimate"
|
||||
|
||||
async def topic_exists(self, topic: str, timeout: float = 1.0) -> bool:
|
||||
loop = asyncio.get_running_loop()
|
||||
future: asyncio.Future = loop.create_future()
|
||||
|
||||
def message_received(msg):
|
||||
if not future.done():
|
||||
future.set_result(msg)
|
||||
unsub = await mqtt.async_subscribe(self.hass, topic, message_received, qos=0)
|
||||
try:
|
||||
msg = await asyncio.wait_for(future, timeout)
|
||||
self._device_type = msg.payload
|
||||
except asyncio.TimeoutError:
|
||||
return False
|
||||
finally:
|
||||
unsub()
|
||||
return bool(msg.retain)
|
||||
|
||||
async def get_translated_type(self, device_type_lang):
|
||||
language = self.hass.config.language
|
||||
translations = await async_get_translations(self.hass, language, "common", {DOMAIN})
|
||||
key = f"component.polaris.common.{device_type_lang}"
|
||||
return translations.get(key, device_type_lang)
|
||||
|
||||
async def async_step_user(self, user_input=None):
|
||||
await self._get_devtypes_from_mqtt()
|
||||
await self.hass.async_add_executor_job(time.sleep, 2)
|
||||
errors = {}
|
||||
if user_input is None:
|
||||
return self.async_show_form(
|
||||
step_id="user",
|
||||
data_schema=vol.Schema(
|
||||
{
|
||||
vol.Required(DEVICEID): SelectSelector(
|
||||
SelectSelectorConfig(
|
||||
options=[
|
||||
SelectOptionDict(
|
||||
value=dev_mac,
|
||||
label=f"{POLARIS_DEVICE[int(dev_type) if int(dev_type) in POLARIS_DEVICE else 0]["model"]} (mac: {dev_mac})",
|
||||
)
|
||||
for dev_mac, dev_type in self._device_found.items()
|
||||
],
|
||||
mode=SelectSelectorMode.DROPDOWN,
|
||||
translation_key="config_selector_devicetype",
|
||||
)
|
||||
),
|
||||
}
|
||||
),
|
||||
errors=errors,
|
||||
)
|
||||
user_input[MQTT_ROOT_TOPIC] = self._topic_prefix[user_input[DEVICEID]]
|
||||
user_input[DEVICETYPE] = self._device_found[user_input[DEVICEID]]
|
||||
user_input["DEVPREFIXTOPIC"] = self._device_prefix_topic[user_input[DEVICEID]]
|
||||
self.oldstep = user_input
|
||||
# _LOGGER.debug("input1 %s", user_input)
|
||||
if user_input[DEVICETYPE] == "0" or self._unknown_devtype > 0:
|
||||
return self.async_show_form(
|
||||
step_id="undef",
|
||||
data_schema=vol.Schema(
|
||||
{
|
||||
vol.Required(DEVICETYPE): SelectSelector(
|
||||
SelectSelectorConfig(
|
||||
options=[
|
||||
SelectOptionDict(
|
||||
value=str(dev_id),
|
||||
label=f'{str(dev_id)} {await self.get_translated_type(POLARIS_DEVICE[int(dev_id)]["class"])} ({POLARIS_DEVICE[int(dev_id)]["model"]})',
|
||||
)
|
||||
for dev_id in POLARIS_DEVICE
|
||||
],
|
||||
mode=SelectSelectorMode.DROPDOWN,
|
||||
)
|
||||
)
|
||||
}
|
||||
),
|
||||
)
|
||||
|
||||
# _LOGGER.debug("input3 %s", user_input)
|
||||
title = f"{POLARIS_DEVICE[int(user_input[DEVICETYPE])]['class']}-{POLARIS_DEVICE[int(user_input[DEVICETYPE])]['model']}-{user_input[DEVICEID]}"
|
||||
await self.async_set_unique_id(title)
|
||||
self._abort_if_unique_id_configured(error="already_configured")
|
||||
# Create entities
|
||||
return self.async_create_entry(
|
||||
title=title,
|
||||
data=user_input,
|
||||
)
|
||||
|
||||
async def async_step_undef(self, user_input):
|
||||
if user_input[DEVICETYPE] == "0":
|
||||
error = "no_dev"
|
||||
return self.async_abort(reason="not_supported")
|
||||
self.oldstep[DEVICETYPE] = user_input[DEVICETYPE]
|
||||
user_input = self.oldstep
|
||||
user_input[MQTT_ROOT_TOPIC] = self._topic_prefix[user_input[DEVICEID]]
|
||||
# _LOGGER.debug("input2 %s", user_input)
|
||||
mqtt.publish(self.hass, f'{user_input[MQTT_ROOT_TOPIC]}/{user_input["DEVPREFIXTOPIC"]}/state/devtype', user_input[DEVICETYPE], 0, True)
|
||||
title = f"{POLARIS_DEVICE[int(user_input[DEVICETYPE])]['class']}-{POLARIS_DEVICE[int(user_input[DEVICETYPE])]['model']}-{user_input[DEVICEID]}"
|
||||
await self.async_set_unique_id(title)
|
||||
self._abort_if_unique_id_configured(error="already_configured")
|
||||
# Create entities
|
||||
return self.async_create_entry(
|
||||
title=title,
|
||||
data=user_input,
|
||||
)
|
||||
|
||||
3524
homeassistant/config/custom_components/polaris/const.py
Normal file
3524
homeassistant/config/custom_components/polaris/const.py
Normal file
File diff suppressed because it is too large
Load Diff
224
homeassistant/config/custom_components/polaris/humidifier.py
Normal file
224
homeassistant/config/custom_components/polaris/humidifier.py
Normal file
@@ -0,0 +1,224 @@
|
||||
"""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.const import ATTR_TEMPERATURE, UnitOfTemperature # ?????
|
||||
from homeassistant.components.humidifier import (
|
||||
DOMAIN,
|
||||
HumidifierAction,
|
||||
HumidifierDeviceClass,
|
||||
HumidifierEntity,
|
||||
HumidifierEntityFeature,
|
||||
)
|
||||
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
|
||||
# Import global values.
|
||||
from .const import (
|
||||
MANUFACTURER,
|
||||
MQTT_ROOT_TOPIC,
|
||||
DEVICEID,
|
||||
DEVICETYPE,
|
||||
POLARIS_DEVICE,
|
||||
HUMIDIFIERS,
|
||||
PolarisHumidifierEntityDescription,
|
||||
POLARIS_HUMIDDIFIER_TYPE,
|
||||
POLARIS_HUMIDDIFIER_7_MODE_TYPE,
|
||||
POLARIS_HUMIDDIFIER_5A_MODE_TYPE,
|
||||
POLARIS_HUMIDDIFIER_5B_MODE_TYPE,
|
||||
POLARIS_HUMIDDIFIER_4_MODE_TYPE,
|
||||
POLARIS_HUMIDDIFIER_3A_MODE_TYPE,
|
||||
POLARIS_HUMIDDIFIER_3B_MODE_TYPE,
|
||||
POLARIS_HUMIDDIFIER_2_MODE_TYPE,
|
||||
POLARIS_HUMIDDIFIER_1_MODE_TYPE,
|
||||
POLARIS_HUMIDDIFIER_11_MODE_TYPE,
|
||||
HUMIDDIFIER_5A_AVAILABLE_MODES,
|
||||
HUMIDDIFIER_5B_AVAILABLE_MODES,
|
||||
HUMIDDIFIER_4_AVAILABLE_MODES,
|
||||
HUMIDDIFIER_3A_AVAILABLE_MODES,
|
||||
HUMIDDIFIER_3B_AVAILABLE_MODES,
|
||||
HUMIDDIFIER_2_AVAILABLE_MODES,
|
||||
HUMIDDIFIER_1_AVAILABLE_MODES,
|
||||
HUMIDDIFIER_11_AVAILABLE_MODES,
|
||||
)
|
||||
|
||||
SUPPORT_FLAGS = HumidifierEntityFeature(1)
|
||||
|
||||
#_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"]
|
||||
humidifierList = []
|
||||
|
||||
if (device_type in POLARIS_HUMIDDIFIER_TYPE):
|
||||
# Create humidifier
|
||||
HUMIDIFIERS_LC = copy.deepcopy(HUMIDIFIERS)
|
||||
for description in HUMIDIFIERS_LC:
|
||||
description.mqttTopicCurrentState = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentState}"
|
||||
description.mqttTopicCommandState = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandState}"
|
||||
description.mqttTopicCurrentMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentMode}"
|
||||
description.mqttTopicCommandMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandMode}"
|
||||
description.mqttTopicCurrentHumidity = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentHumidity}"
|
||||
description.mqttTopicCurrentTargetHumidity = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentTargetHumidity}"
|
||||
description.mqttTopicCommandTargetHumidity = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandTargetHumidity}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
humidifierList.append(
|
||||
PolarisHumidifier(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
async_add_entities(humidifierList, update_before_add=True)
|
||||
|
||||
|
||||
class PolarisHumidifier(PolarisBaseEntity, HumidifierEntity):
|
||||
|
||||
entity_description: PolarisHumidifierEntityDescription
|
||||
_attr_supported_features = HumidifierEntityFeature.MODES
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
device_friendly_name: str,
|
||||
description: PolarisHumidifierEntityDescription,
|
||||
mqtt_root: str,
|
||||
device_id: str | None=None,
|
||||
device_type: str | None=None,
|
||||
device_class: HumidifierDeviceClass | 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_is_on = True
|
||||
self._attr_max_humidity = description.max_humidity
|
||||
self._attr_min_humidity = description.min_humidity
|
||||
if device_type in POLARIS_HUMIDDIFIER_7_MODE_TYPE:
|
||||
self.my_operation_list = description.available_modes
|
||||
elif device_type in POLARIS_HUMIDDIFIER_5A_MODE_TYPE:
|
||||
self.my_operation_list = HUMIDDIFIER_5A_AVAILABLE_MODES
|
||||
elif device_type in POLARIS_HUMIDDIFIER_5B_MODE_TYPE:
|
||||
self.my_operation_list = HUMIDDIFIER_5B_AVAILABLE_MODES
|
||||
elif device_type in POLARIS_HUMIDDIFIER_4_MODE_TYPE:
|
||||
self.my_operation_list = HUMIDDIFIER_4_AVAILABLE_MODES
|
||||
elif device_type in POLARIS_HUMIDDIFIER_3A_MODE_TYPE:
|
||||
self.my_operation_list = HUMIDDIFIER_3A_AVAILABLE_MODES
|
||||
elif device_type in POLARIS_HUMIDDIFIER_3B_MODE_TYPE:
|
||||
self.my_operation_list = HUMIDDIFIER_3B_AVAILABLE_MODES
|
||||
elif device_type in POLARIS_HUMIDDIFIER_2_MODE_TYPE:
|
||||
self.my_operation_list = HUMIDDIFIER_2_AVAILABLE_MODES
|
||||
elif device_type in POLARIS_HUMIDDIFIER_1_MODE_TYPE:
|
||||
self.my_operation_list = HUMIDDIFIER_1_AVAILABLE_MODES
|
||||
elif device_type in POLARIS_HUMIDDIFIER_11_MODE_TYPE:
|
||||
self.my_operation_list = HUMIDDIFIER_11_AVAILABLE_MODES
|
||||
self._attr_available_modes = list(self.my_operation_list.keys())
|
||||
self._attr_mode = self._attr_available_modes[0]
|
||||
self.payload_on=description.payload_on
|
||||
self.payload_off=description.payload_off
|
||||
self._attr_has_entity_name = True
|
||||
self._attr_available = False
|
||||
self._attr_current_humidity = self._attr_min_humidity
|
||||
self._attr_target_humidity = self._attr_min_humidity
|
||||
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
@callback
|
||||
def message_received_curr_humid(message):
|
||||
self._attr_current_humidity = float(message.payload)
|
||||
self.async_write_ha_state()
|
||||
@callback
|
||||
def message_received_targ_humid(message):
|
||||
if float(message.payload) < self._attr_min_humidity:
|
||||
self._attr_target_humidity = self._attr_min_humidity
|
||||
else:
|
||||
self._attr_target_humidity = float(message.payload)
|
||||
self.async_write_ha_state()
|
||||
@callback
|
||||
def message_received_mode(message):
|
||||
payload = message.payload
|
||||
if int(payload)==0:
|
||||
self._attr_is_on = 0
|
||||
else:
|
||||
self._attr_is_on = 1
|
||||
self._attr_mode = list(self.my_operation_list.keys())[list(self.my_operation_list.values()).index(message.payload)]
|
||||
self.async_write_ha_state()
|
||||
|
||||
await mqtt.async_subscribe(
|
||||
self.hass,
|
||||
self.entity_description.mqttTopicCurrentHumidity,
|
||||
message_received_curr_humid,
|
||||
1,
|
||||
)
|
||||
await mqtt.async_subscribe(
|
||||
self.hass,
|
||||
self.entity_description.mqttTopicCurrentTargetHumidity,
|
||||
message_received_targ_humid,
|
||||
1,
|
||||
)
|
||||
await mqtt.async_subscribe(
|
||||
self.hass,
|
||||
self.entity_description.mqttTopicCurrentState,
|
||||
message_received_mode,
|
||||
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)
|
||||
|
||||
|
||||
def turn_on(self, **kwargs):
|
||||
self._attr_is_on = self.payload_on
|
||||
topic = f"{self.entity_description.mqttTopicCommandState}"
|
||||
self.publishToMQTT(topic)
|
||||
|
||||
def turn_off(self, **kwargs):
|
||||
self._attr_is_on = self.payload_off
|
||||
topic = f"{self.entity_description.mqttTopicCommandState}"
|
||||
self.publishToMQTT(topic)
|
||||
|
||||
def publishToMQTT(self, topic: str):
|
||||
mqtt.publish(self.hass, topic, str(self._attr_is_on))
|
||||
|
||||
def set_humidity(self, humidity: int):
|
||||
self._attr_target_humidity = humidity
|
||||
topic = f"{self.entity_description.mqttTopicCommandTargetHumidity}"
|
||||
mqtt.publish(self.hass, topic, str(humidity))
|
||||
|
||||
|
||||
def set_mode(self, mode: str):
|
||||
self._attr_mode = mode
|
||||
topic = f"{self.entity_description.mqttTopicCommandMode}"
|
||||
mqtt.publish(self.hass, topic, self.my_operation_list[mode])
|
||||
|
||||
274
homeassistant/config/custom_components/polaris/icons.json
Normal file
274
homeassistant/config/custom_components/polaris/icons.json
Normal file
@@ -0,0 +1,274 @@
|
||||
{
|
||||
"entity": {
|
||||
"humidifier": {
|
||||
"humidifier": {
|
||||
"default": "mdi:air-humidifier",
|
||||
"state": {
|
||||
"off": "mdi:air-humidifier-off"
|
||||
},
|
||||
"state_attributes": {
|
||||
"mode": {
|
||||
"state": {
|
||||
"auto": "mdi:refresh-auto",
|
||||
"baby": "mdi:baby-carriage",
|
||||
"boost": "mdi:rocket-launch",
|
||||
"comfort": "mdi:heart-pulse",
|
||||
"eco": "mdi:cloud-percent",
|
||||
"home": "mdi:gesture-tap",
|
||||
"sleep": "mdi:power-sleep",
|
||||
"fitnes": "mdi:walk",
|
||||
"yoga": "mdi:yoga",
|
||||
"meditation": "mdi:meditation",
|
||||
"prana_hand": "mdi:human-handsdown",
|
||||
"prana_auto": "mdi:human-handsup",
|
||||
"aroma": "mdi:scent"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"water_heater": {
|
||||
"water_heater": {
|
||||
"default": "mdi:kettle",
|
||||
"state": {
|
||||
"off": "mdi:kettle-off"
|
||||
},
|
||||
"state_attributes": {
|
||||
"operation_mode": {
|
||||
"default": "mdi:circle-medium",
|
||||
"state": {
|
||||
"eco": "mdi:water-plus",
|
||||
"electric": "mdi:heat-wave",
|
||||
"gas": "mdi:fire-circle",
|
||||
"heat_pump": "mdi:water-thermometer",
|
||||
"high_demand": "mdi:finance",
|
||||
"off": "mdi:power",
|
||||
"performance": "mdi:chart-bubble"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"water_boiler": {
|
||||
"default": "mdi:water-boiler",
|
||||
"state": {
|
||||
"off": "mdi:water-boiler-off"
|
||||
},
|
||||
"state_attributes": {
|
||||
"operation_mode": {
|
||||
"state": {
|
||||
"off": "mdi:power",
|
||||
"performance": "mdi:chart-bubble",
|
||||
"electric": "mdi:heat-wave",
|
||||
"heat_pump": "mdi:water-thermometer",
|
||||
"eco": "mdi:water-plus"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"switch": {
|
||||
"sound_switch": {
|
||||
"default": "mdi:volume-high",
|
||||
"state": {
|
||||
"off": "mdi:volume-off"
|
||||
}
|
||||
},
|
||||
"child_lock_switch": {
|
||||
"default": "mdi:lock-open-variant",
|
||||
"state": {
|
||||
"on": "mdi:lock"
|
||||
}
|
||||
},
|
||||
"backlight_switch": {
|
||||
"default": "mdi:alarm-light",
|
||||
"state": {
|
||||
"off": "mdi:alarm-light-off"
|
||||
}
|
||||
},
|
||||
"backlight_bottom_switch": {
|
||||
"default": "mdi:lightbulb-on",
|
||||
"state": {
|
||||
"off": "mdi:lightbulb-on-50"
|
||||
}
|
||||
},
|
||||
"backlight_bright": {
|
||||
"default": "mdi:lightbulb-on",
|
||||
"state": {
|
||||
"off": "mdi:lightbulb-on-50"
|
||||
}
|
||||
},
|
||||
"damper_heater": {
|
||||
"default": "mdi:window-closed-variant",
|
||||
"state": {
|
||||
"on": "mdi:window-open-variant"
|
||||
}
|
||||
},
|
||||
"display_off_heater": {
|
||||
"default": "mdi:lightbulb",
|
||||
"state": {
|
||||
"on": "mdi:lightbulb-auto"
|
||||
}
|
||||
},
|
||||
"half_power_heater": {
|
||||
"default": "mdi:fraction-one-half",
|
||||
"state": {
|
||||
"off": "mdi:fraction-one-half"
|
||||
}
|
||||
},
|
||||
"auto_heater_switch": {
|
||||
"default": "mdi:snowflake",
|
||||
"state": {
|
||||
"off": "mdi:snowflake-off"
|
||||
}
|
||||
},
|
||||
"self_cleaning": {
|
||||
"default": "mdi:autorenew",
|
||||
"state": {
|
||||
"off": "mdi:autorenew-off"
|
||||
}
|
||||
},
|
||||
"eco_mode_switch": {
|
||||
"default": "mdi:leaf",
|
||||
"state": {
|
||||
"off": "mdi:leaf-off"
|
||||
}
|
||||
}
|
||||
},
|
||||
"binary_sensor": {
|
||||
"base_binary_sensor": {
|
||||
"default": "mdi:home",
|
||||
"state": {
|
||||
"on": "mdi:home-off"
|
||||
}
|
||||
},
|
||||
"water_tank_binary_sensor": {
|
||||
"default": "mdi:cup",
|
||||
"state": {
|
||||
"on": "mdi:cup-off"
|
||||
}
|
||||
},
|
||||
"lid_binary_sensor": {
|
||||
"default": "mdi:pot",
|
||||
"state": {
|
||||
"on": "mdi:pot-steam"
|
||||
}
|
||||
},
|
||||
"cappuccinator_binary_sensor": {
|
||||
"default": "mdi:cup-off",
|
||||
"state": {
|
||||
"on": "mdi:cup"
|
||||
}
|
||||
}
|
||||
},
|
||||
"climate": {
|
||||
"climate": {
|
||||
"default": "mdi:hvac",
|
||||
"state": {
|
||||
"off": "mdi:hvac-off"
|
||||
},
|
||||
"state_attributes": {
|
||||
"fan_mode": {
|
||||
"state": {
|
||||
"1_speed": "mdi:fan",
|
||||
"2_speed": "mdi:fan",
|
||||
"3_speed": "mdi:fan",
|
||||
"4_speed": "mdi:fan",
|
||||
"5_speed": "mdi:fan",
|
||||
"6_speed": "mdi:fan",
|
||||
"7_speed": "mdi:fan",
|
||||
"8_speed": "mdi:fan",
|
||||
"9_speed": "mdi:fan",
|
||||
"off": "mdi:fan-off"
|
||||
}
|
||||
},
|
||||
"preset_mode": {
|
||||
"default": "mdi:hvac",
|
||||
"state": {
|
||||
"hands": "mdi:gesture-tap",
|
||||
"auto": "mdi:molecule-co2",
|
||||
"night": "mdi:weather-night",
|
||||
"turbo": "mdi:rocket-launch",
|
||||
"passive": "mdi:air-filter"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"aircleaner": {
|
||||
"default": "mdi:air-purifier",
|
||||
"state": {
|
||||
"off": "mdi:air-purifier-off"
|
||||
},
|
||||
"state_attributes": {
|
||||
"preset_mode": {
|
||||
"default": "mdi:hvac",
|
||||
"state": {
|
||||
"hands": "mdi:gesture-tap",
|
||||
"auto": "mdi:refresh-auto",
|
||||
"night": "mdi:weather-night"
|
||||
}
|
||||
},
|
||||
"fan_mode": {
|
||||
"state": {
|
||||
"top": "mdi:rocket-launch"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"heater": {
|
||||
"default": "mdi:radiator",
|
||||
"state": {
|
||||
"off": "mdi:radiator-off"
|
||||
},
|
||||
"state_attributes": {
|
||||
"fan_mode": {
|
||||
"state": {
|
||||
"auto": "mdi:flash-auto",
|
||||
"10_percent": "mdi:numeric-1-box",
|
||||
"20_percent": "mdi:numeric-2-box",
|
||||
"30_percent": "mdi:numeric-3-box",
|
||||
"40_percent": "mdi:numeric-4-box",
|
||||
"50_percent": "mdi:numeric-5-box",
|
||||
"60_percent": "mdi:numeric-6-box",
|
||||
"70_percent": "mdi:numeric-7-box",
|
||||
"80_percent": "mdi:numeric-8-box",
|
||||
"90_percent": "mdi:numeric-9-box",
|
||||
"100_percent": "mdi:numeric-10-box",
|
||||
"20_5_percent": "mdi:numeric-1-box",
|
||||
"40_5_percent": "mdi:numeric-2-box",
|
||||
"60_5_percent": "mdi:numeric-3-box",
|
||||
"80_5_percent": "mdi:numeric-4-box",
|
||||
"100_5_percent": "mdi:numeric-5-box"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"conditioner": {
|
||||
"default": "mdi:air-conditioner",
|
||||
"state_attributes": {
|
||||
"fan_mode": {
|
||||
"state": {
|
||||
"min": "mdi:fan-minus",
|
||||
"low": "mdi:fan-speed-1",
|
||||
"middle": "mdi:fan-speed-2",
|
||||
"high": "mdi:fan-speed-3",
|
||||
"max": "mdi:fan-plus"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"thermostat": {
|
||||
"state_attributes": {
|
||||
"preset_mode": {
|
||||
"state": {
|
||||
"turbo": "mdi:rocket-launch",
|
||||
"antifrost": "mdi:snowflake-off",
|
||||
"schedule": "mdi:calendar-blank",
|
||||
"vacation": "mdi:plane-car",
|
||||
"manual": "mdi:cog"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
310
homeassistant/config/custom_components/polaris/image.py
Normal file
310
homeassistant/config/custom_components/polaris/image.py
Normal file
File diff suppressed because one or more lines are too long
114
homeassistant/config/custom_components/polaris/input_datetime.py
Normal file
114
homeassistant/config/custom_components/polaris/input_datetime.py
Normal file
@@ -0,0 +1,114 @@
|
||||
"""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 datetime import time
|
||||
from homeassistant.components.time import DOMAIN, TimeEntity, TimeEntityDescription
|
||||
#from homeassistant.components.datetime import DOMAIN, DateTimeEntity, DateTimeEntityDescription
|
||||
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
|
||||
# Import global values.
|
||||
from .const import (
|
||||
MANUFACTURER,
|
||||
MQTT_ROOT_TOPIC,
|
||||
DEVICEID,
|
||||
DEVICETYPE,
|
||||
POLARIS_DEVICE,
|
||||
TIME_COOKER,
|
||||
PolarisTimeEntityDescription,
|
||||
POLARIS_COOKER_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"]
|
||||
timeList = []
|
||||
|
||||
if (device_type in POLARIS_COOKER_TYPE):
|
||||
TIME_COOKER_LC = copy.deepcopy(TIME_COOKER)
|
||||
for description in TIME_COOKER_LC:
|
||||
description.mqttTopicCurrentTime = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentTime}"
|
||||
description.mqttTopicCommandTime = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandTime}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
timeList.append(
|
||||
PolarisTime(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
async_add_entities(timeList, update_before_add=True)
|
||||
|
||||
|
||||
class PolarisTime(PolarisBaseEntity, TimeEntity):
|
||||
|
||||
entity_description: PolarisTimeDescription
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
device_friendly_name: str,
|
||||
description: PolarisTimeEntityDescription,
|
||||
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_available = False
|
||||
self._attr_has_entity_name = True
|
||||
self._attr_native_value = time(0, self.entity_description.default_time, 0)
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
@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_set_value(self, value: time) -> None:
|
||||
"""Update the time."""
|
||||
value_hour=value.hour
|
||||
value_minute=value.minute
|
||||
value_second=0
|
||||
value_in_seconds = value.hour * 3600 + value.minute * 60
|
||||
if (value_in_seconds > (self.entity_description.max_time * 60)):
|
||||
value_hour = int(self.entity_description.max_time / 60) - 1
|
||||
self._attr_native_value = time(value_hour,value_minute,value_second)
|
||||
value_in_seconds = value_hour * 3600 + value_minute * 60
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandTime, str(value_in_seconds))
|
||||
|
||||
260
homeassistant/config/custom_components/polaris/light.py
Normal file
260
homeassistant/config/custom_components/polaris/light.py
Normal file
@@ -0,0 +1,260 @@
|
||||
"""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
|
||||
19
homeassistant/config/custom_components/polaris/manifest.json
Normal file
19
homeassistant/config/custom_components/polaris/manifest.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"domain": "polaris",
|
||||
"name": "Polaris IQ Home MQTT",
|
||||
"codeowners": ["@samoswall"],
|
||||
"config_flow": true,
|
||||
"dependencies": ["mqtt"],
|
||||
"documentation": "https://github.com/samoswall/polaris-mqtt",
|
||||
"iot_class": "local_push",
|
||||
"issue_tracker": "https://github.com/samoswall/polaris-mqtt/issues",
|
||||
"mqtt": [
|
||||
"polaris/+/state/mac",
|
||||
"/polaris/+/state/mac",
|
||||
"polaris/+/+/state/mac",
|
||||
"/polaris/+/+/state/mac",
|
||||
"rusclimate/+/+/state/mac",
|
||||
"/rusclimate/+/+/state/mac"
|
||||
],
|
||||
"version": "1.0.13"
|
||||
}
|
||||
291
homeassistant/config/custom_components/polaris/number.py
Normal file
291
homeassistant/config/custom_components/polaris/number.py
Normal file
@@ -0,0 +1,291 @@
|
||||
"""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.components.number import NumberEntity, DOMAIN
|
||||
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.const import STATE_UNAVAILABLE
|
||||
|
||||
# Import global values.
|
||||
from .const import (
|
||||
MANUFACTURER,
|
||||
MQTT_ROOT_TOPIC,
|
||||
DEVICEID,
|
||||
DEVICETYPE,
|
||||
POLARIS_DEVICE,
|
||||
NUMBER_HUMIDIFIER,
|
||||
NUMBER_RUSCLIMATE_HUMIDIFIER,
|
||||
NUMBER_COOKER,
|
||||
NUMBERS_COFFEEMAKER,
|
||||
NUMBERS_COFFEEMAKER_ROG,
|
||||
NUMBERS_AIRCLEANER,
|
||||
NUMBERS_IRRIGATOR,
|
||||
NUMBERS_HEATER,
|
||||
NUMBERS_THERMOSTAT,
|
||||
PolarisNumberEntityDescription,
|
||||
POLARIS_KETTLE_TYPE,
|
||||
POLARIS_KETTLE_WITH_WEIGHT_TYPE,
|
||||
POLARIS_HUMIDDIFIER_TYPE,
|
||||
POLARIS_HUMIDDIFIER_LOW_FAN_TYPE,
|
||||
POLARIS_COOKER_TYPE,
|
||||
POLARIS_COFFEEMAKER_TYPE,
|
||||
POLARIS_COFFEEMAKER_ROG_TYPE,
|
||||
POLARIS_AIRCLEANER_TYPE,
|
||||
POLARIS_IRRIGATOR_TYPE,
|
||||
POLARIS_HEATER_TYPE,
|
||||
POLARIS_THERMOSTAT_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"]
|
||||
numberList = []
|
||||
|
||||
if (device_type in POLARIS_HUMIDDIFIER_TYPE):
|
||||
# Create humidifier
|
||||
if device_type in {"835","881"}:
|
||||
NUMBER_HUMIDIFIER_LC = copy.deepcopy(NUMBER_RUSCLIMATE_HUMIDIFIER)
|
||||
else:
|
||||
NUMBER_HUMIDIFIER_LC = copy.deepcopy(NUMBER_HUMIDIFIER)
|
||||
for description in NUMBER_HUMIDIFIER_LC:
|
||||
description.mqttTopicCurrent = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrent}"
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
numberList.append(
|
||||
PolarisNumber(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_COOKER_TYPE):
|
||||
# Create cooker
|
||||
NUMBER_COOKER_LC = copy.deepcopy(NUMBER_COOKER)
|
||||
for description in NUMBER_COOKER_LC:
|
||||
description.mqttTopicCurrent = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrent}"
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
numberList.append(
|
||||
PolarisNumber(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_COFFEEMAKER_TYPE):
|
||||
# Create cooker
|
||||
NUMBERS_COFFEEMAKER_LC = copy.deepcopy(NUMBERS_COFFEEMAKER)
|
||||
for description in NUMBERS_COFFEEMAKER_LC:
|
||||
# description.mqttTopicCurrent = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrent}"
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
numberList.append(
|
||||
PolarisNumber(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_COFFEEMAKER_ROG_TYPE):
|
||||
# Create cooker
|
||||
NUMBERS_COFFEEMAKER_ROG_LC = copy.deepcopy(NUMBERS_COFFEEMAKER_ROG)
|
||||
for description in NUMBERS_COFFEEMAKER_ROG_LC:
|
||||
description.mqttTopicCurrent = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrent}"
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
numberList.append(
|
||||
PolarisNumber(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_AIRCLEANER_TYPE):
|
||||
# Create humidifier
|
||||
NUMBERS_AIRCLEANER_LC = copy.deepcopy(NUMBERS_AIRCLEANER)
|
||||
for description in NUMBERS_AIRCLEANER_LC:
|
||||
description.mqttTopicCurrent = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrent}"
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
numberList.append(
|
||||
PolarisNumber(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_IRRIGATOR_TYPE):
|
||||
# Create irrigator
|
||||
NUMBERS_IRRIGATOR_LC = copy.deepcopy(NUMBERS_IRRIGATOR)
|
||||
for description in NUMBERS_IRRIGATOR_LC:
|
||||
description.mqttTopicCurrent = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrent}"
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
numberList.append(
|
||||
PolarisNumber(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_HEATER_TYPE):
|
||||
# Create Heater
|
||||
NUMBERS_HEATER_LC = copy.deepcopy(NUMBERS_HEATER)
|
||||
for description in NUMBERS_HEATER_LC:
|
||||
description.mqttTopicCurrent = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrent}"
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
numberList.append(
|
||||
PolarisNumber(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_THERMOSTAT_TYPE):
|
||||
# Create Heater
|
||||
NUMBERS_THERMOSTAT_LC = copy.deepcopy(NUMBERS_THERMOSTAT)
|
||||
for description in NUMBERS_THERMOSTAT_LC:
|
||||
description.mqttTopicCurrent = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrent}"
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
numberList.append(
|
||||
PolarisNumber(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
async_add_entities(numberList, update_before_add=True)
|
||||
|
||||
|
||||
class PolarisNumber(PolarisBaseEntity, NumberEntity):
|
||||
|
||||
entity_description: PolarisNumberEntityDescription
|
||||
def __init__(
|
||||
self,
|
||||
device_friendly_name: str,
|
||||
description: PolarisNumberEntityDescription,
|
||||
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_available = False
|
||||
self._attr_has_entity_name = True
|
||||
self._attr_native_value = self.entity_description.native_value
|
||||
if POLARIS_DEVICE[int(self.device_type)]['class'] == "coffeemaker":
|
||||
if self.entity_description.name != "display_time":
|
||||
self._attr_native_value = STATE_UNAVAILABLE
|
||||
if self.device_type in POLARIS_HUMIDDIFIER_LOW_FAN_TYPE:
|
||||
self._attr_native_max_value = 3
|
||||
if self.device_type in POLARIS_THERMOSTAT_TYPE:
|
||||
self._data_zero = "00000000000000000000000000000000000000"
|
||||
|
||||
|
||||
def set_native_value(self, value: float) -> None:
|
||||
if value % 1 > 0:
|
||||
self._attr_native_value = STATE_UNAVAILABLE
|
||||
elif ((self.entity_description.key == "display_time") or
|
||||
(self.entity_description.key == "temperature_difference_antifrost") or
|
||||
(self.entity_description.key == "temperature_difference_eco")):
|
||||
self._attr_native_value = int(value)
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommand, f"{int(value):02x}", 0, True)
|
||||
elif self.entity_description.name == "time_timer":
|
||||
self._attr_native_value = int(value)
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommand, int(value)*3600)
|
||||
|
||||
elif self.entity_description.translation_key == "power_cable":
|
||||
self._attr_native_value = int(value)
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommand, f"{int(value):04x}"[-2:]+f"{int(value):04x}"[:2])
|
||||
|
||||
elif self.entity_description.translation_key == "bright_backlight":
|
||||
self._attr_native_value = int(value)
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommand, f"{self._data_zero[:2]}{hex(int(value))[2:]}{self._data_zero[4:]}")
|
||||
|
||||
else:
|
||||
self._attr_native_value = int(value)
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommand, int(value))
|
||||
|
||||
@property
|
||||
def get_state (self) -> int | None:
|
||||
return self._attr_native_value
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
@callback
|
||||
def message_received_numb(message):
|
||||
if self.entity_description.name == "display_time":
|
||||
self._attr_native_value = int(message.payload, 16)
|
||||
elif self.entity_description.name == "time_timer":
|
||||
self._attr_native_value = int(int(message.payload) / 3600)
|
||||
elif self.entity_description.translation_key == "bright_backlight":
|
||||
self._data_zero = message.payload
|
||||
self._attr_native_value = int(self._data_zero[2:4], 16)
|
||||
elif self.entity_description.translation_key == "power_cable":
|
||||
self._attr_native_value = int(message.payload[:2],16) + (int(message.payload[-2:],16)*256)
|
||||
else:
|
||||
if self.entity_description.native_min_value <= int(message.payload):
|
||||
self._attr_native_value = message.payload
|
||||
self.async_write_ha_state()
|
||||
|
||||
await mqtt.async_subscribe(
|
||||
self.hass,
|
||||
self.entity_description.mqttTopicCurrent,
|
||||
message_received_numb,
|
||||
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)
|
||||
|
||||
482
homeassistant/config/custom_components/polaris/select.py
Normal file
482
homeassistant/config/custom_components/polaris/select.py
Normal file
@@ -0,0 +1,482 @@
|
||||
"""The Polaris IQ Home component."""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
import logging
|
||||
from typing import Iterable
|
||||
import copy
|
||||
import datetime
|
||||
import os
|
||||
|
||||
from homeassistant.components import mqtt
|
||||
from homeassistant.components.mqtt.models import ReceiveMessage
|
||||
|
||||
from homeassistant.components.select import DOMAIN, SelectEntity
|
||||
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
|
||||
# Import global values.
|
||||
from .const import (
|
||||
MANUFACTURER,
|
||||
MQTT_ROOT_TOPIC,
|
||||
DEVICEID,
|
||||
DEVICETYPE,
|
||||
POLARIS_DEVICE,
|
||||
CUSTOM_SELECT_FILE_PATH,
|
||||
SELECT_KETTLE,
|
||||
SELECT_COOKER,
|
||||
SELECT_COFFEEMAKER,
|
||||
SELECT_COFFEEMAKER_ROG,
|
||||
SELECT_CLIMATE,
|
||||
SELECT_VACUUM,
|
||||
SELECT_IRRIGATOR,
|
||||
SELECT_AIRCLEANER_EAP,
|
||||
SELECT_AIRCONDITIONER_SWING_HORIZONTAL,
|
||||
SELECT_AIRCONDITIONER_SWING_VERTICAL,
|
||||
PolarisSelectEntityDescription,
|
||||
POLARIS_KETTLE_TYPE,
|
||||
POLARIS_KETTLE_WITH_WEIGHT_TYPE,
|
||||
POLARIS_HUMIDDIFIER_TYPE,
|
||||
POLARIS_COOKER_TYPE,
|
||||
POLARIS_COFFEEMAKER_TYPE,
|
||||
POLARIS_COFFEEMAKER_ROG_TYPE,
|
||||
POLARIS_CLIMATE_TYPE,
|
||||
POLARIS_VACUUM_TYPE,
|
||||
POLARIS_IRRIGATOR_TYPE,
|
||||
POLARIS_AIRCLEANER_EAP_TYPE,
|
||||
POLARIS_AIRCONDITIONER_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"]
|
||||
selectList = []
|
||||
|
||||
if (device_type in POLARIS_KETTLE_TYPE) or (device_type in POLARIS_KETTLE_WITH_WEIGHT_TYPE):
|
||||
SELECT_KETTLE_LC = copy.deepcopy(SELECT_KETTLE)
|
||||
for description in SELECT_KETTLE_LC:
|
||||
description.mqttTopicCurrentMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentMode}"
|
||||
description.mqttTopicCommandMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandMode}"
|
||||
description.mqttTopicCommandTemperature = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandTemperature}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
selectList.append(
|
||||
PolarisSelect(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_COOKER_TYPE):
|
||||
SELECT_COOKER_LC = copy.deepcopy(SELECT_COOKER)
|
||||
for description in SELECT_COOKER_LC:
|
||||
description.mqttTopicCurrentMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentMode}"
|
||||
description.mqttTopicCommandMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandMode}"
|
||||
description.mqttTopicCommandTemperature = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandTemperature}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
selectList.append(
|
||||
PolarisSelect(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_COFFEEMAKER_TYPE):
|
||||
SELECT_COFFEEMAKER_LC = copy.deepcopy(SELECT_COFFEEMAKER)
|
||||
for description in SELECT_COFFEEMAKER_LC:
|
||||
description.mqttTopicCurrentMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentMode}"
|
||||
description.mqttTopicCommandMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandMode}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
selectList.append(
|
||||
PolarisSelect(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_COFFEEMAKER_ROG_TYPE):
|
||||
SELECT_COFFEEMAKER_ROG_LC = copy.deepcopy(SELECT_COFFEEMAKER_ROG)
|
||||
for description in SELECT_COFFEEMAKER_ROG_LC:
|
||||
description.mqttTopicCurrentMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentMode}"
|
||||
description.mqttTopicCommandMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandMode}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
selectList.append(
|
||||
PolarisSelect(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_CLIMATE_TYPE):
|
||||
SELECT_CLIMATE_LC = copy.deepcopy(SELECT_CLIMATE)
|
||||
for description in SELECT_CLIMATE_LC:
|
||||
description.mqttTopicCurrentMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentMode}"
|
||||
description.mqttTopicCommandMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandMode}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
selectList.append(
|
||||
PolarisSelect(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_VACUUM_TYPE):
|
||||
SELECT_VACUUM_LC = copy.deepcopy(SELECT_VACUUM)
|
||||
for description in SELECT_VACUUM_LC:
|
||||
description.mqttTopicCurrentMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentMode}"
|
||||
description.mqttTopicCommandMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandMode}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
selectList.append(
|
||||
PolarisSelect(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_IRRIGATOR_TYPE):
|
||||
SELECT_IRRIGATOR_LC = copy.deepcopy(SELECT_IRRIGATOR)
|
||||
for description in SELECT_IRRIGATOR_LC:
|
||||
description.mqttTopicCurrentMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentMode}"
|
||||
description.mqttTopicCommandMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandMode}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
selectList.append(
|
||||
PolarisSelect(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_AIRCLEANER_EAP_TYPE):
|
||||
SELECT_AIRCLEANER_EAP_LC = copy.deepcopy(SELECT_AIRCLEANER_EAP)
|
||||
for description in SELECT_AIRCLEANER_EAP_LC:
|
||||
description.mqttTopicCurrentMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentMode}"
|
||||
description.mqttTopicCommandMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandMode}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
selectList.append(
|
||||
PolarisSelect(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_AIRCONDITIONER_TYPE) and (device_type == "813"):
|
||||
SELECT_AIRCONDITIONER_SWING_HORIZONTAL_LC = copy.deepcopy(SELECT_AIRCONDITIONER_SWING_HORIZONTAL)
|
||||
for description in SELECT_AIRCONDITIONER_SWING_HORIZONTAL_LC:
|
||||
description.mqttTopicCurrentMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentMode}"
|
||||
description.mqttTopicCommandMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandMode}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
selectList.append(
|
||||
PolarisSelect(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_AIRCONDITIONER_TYPE) and (device_type == "813"):
|
||||
SELECT_AIRCONDITIONER_SWING_VERTICAL_LC = copy.deepcopy(SELECT_AIRCONDITIONER_SWING_VERTICAL)
|
||||
for description in SELECT_AIRCONDITIONER_SWING_VERTICAL_LC:
|
||||
description.mqttTopicCurrentMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentMode}"
|
||||
description.mqttTopicCommandMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandMode}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
selectList.append(
|
||||
PolarisSelect(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
async_add_entities(selectList, update_before_add=True)
|
||||
|
||||
|
||||
class PolarisSelect(PolarisBaseEntity, SelectEntity):
|
||||
|
||||
entity_description: PolarisSelectEntityDescription
|
||||
def __init__(
|
||||
self,
|
||||
device_friendly_name: str,
|
||||
description: PolarisSelectEntityDescription,
|
||||
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_has_entity_name = True
|
||||
|
||||
|
||||
if POLARIS_DEVICE[int(self.device_type)]['class'] == "kettle" or POLARIS_DEVICE[int(self.device_type)]['class'] == "cooker" or POLARIS_DEVICE[int(self.device_type)]['class'] == "coffeemaker" or POLARIS_DEVICE[int(self.device_type)]['class'] == "cleaner":
|
||||
self._select_options = json.loads(json.dumps(SELECT_COFFEEMAKER[0].options))
|
||||
if device_type == "826":
|
||||
self._EAP_data0 = "0000"
|
||||
if device_type == "813":
|
||||
self._conditioner_data0 = "0000"
|
||||
|
||||
self._custom_data_select = self._read_file()
|
||||
if self._custom_data_select is not None:
|
||||
if POLARIS_DEVICE[int(self.device_type)]['class'] == "kettle" and "SELECT_KETTLE_options" in self._custom_data_select:
|
||||
# self.entity_description.options = json.loads(json.dumps(self.entity_description.options))
|
||||
for key, value in self._custom_data_select["SELECT_KETTLE_options"].items():
|
||||
self.entity_description.options[key] = value
|
||||
# _LOGGER.debug("kettle %s", self.entity_description.options)
|
||||
if POLARIS_DEVICE[int(self.device_type)]['class'] == "cooker" and "SELECT_COOKER_options" in self._custom_data_select:
|
||||
# self.entity_description.options = json.loads(json.dumps(self.entity_description.options))
|
||||
for key, value in self._custom_data_select["SELECT_COOKER_options"].items():
|
||||
self.entity_description.options[key] = json.dumps([value])
|
||||
# _LOGGER.debug("cooker %s", self.entity_description.options)
|
||||
if POLARIS_DEVICE[int(self.device_type)]['class'] == "coffeemaker":
|
||||
if int(self.device_type) == 45 and "SELECT_COFFEEMAKER_ROG_options" in self._custom_data_select:
|
||||
# self.entity_description.options = json.loads(json.dumps(self.entity_description.options))
|
||||
for key, value in self._custom_data_select["SELECT_COFFEEMAKER_ROG_options"].items():
|
||||
self.entity_description.options[key] = json.dumps([value])
|
||||
# _LOGGER.debug("coffee_rog %s", self.entity_description.options)
|
||||
elif "SELECT_COFFEEMAKER_options" in self._custom_data_select:
|
||||
# self.entity_description.options = json.loads(json.dumps(self.entity_description.options))
|
||||
for key, value in self._custom_data_select["SELECT_COFFEEMAKER_options"].items():
|
||||
self.entity_description.options[key] = json.dumps([value])
|
||||
# _LOGGER.debug("coffee %s", self.entity_description.options)
|
||||
if POLARIS_DEVICE[int(self.device_type)]['class'] == "cleaner" and "SELECT_VACUUM_rooms" in self._custom_data_select and self.entity_description.key == "select_room":
|
||||
# self.entity_description.options = json.loads(json.dumps(self.entity_description.options))
|
||||
for key, value in self._custom_data_select["SELECT_VACUUM_rooms"].items():
|
||||
self.entity_description.options[key] = json.dumps([value])
|
||||
|
||||
self._attr_options = list(self.entity_description.options.keys())
|
||||
self._attr_current_option = self._attr_options[0]
|
||||
self._attr_available = False
|
||||
|
||||
def _read_file(self):
|
||||
file_path = CUSTOM_SELECT_FILE_PATH
|
||||
if os.path.exists(file_path):
|
||||
with open(file_path, 'r', encoding='utf-8') as file:
|
||||
content = json.loads(file.read())
|
||||
else:
|
||||
content = None
|
||||
return content
|
||||
|
||||
# @property
|
||||
# def available(self):
|
||||
# return self._attr_current_option is not None
|
||||
|
||||
def key_from_option(self, option: str):
|
||||
try:
|
||||
return next(
|
||||
key
|
||||
for key, value in self.entity_description.options.items()
|
||||
if json.loads(value)[0]["mode"] == option
|
||||
)
|
||||
except StopIteration:
|
||||
return None
|
||||
|
||||
async def async_select_option(self, option: str) -> None:
|
||||
self._attr_current_option = option
|
||||
if POLARIS_DEVICE[int(self.device_type)]['class'] == "cooker":
|
||||
cook_time = json.loads(self.entity_description.options[option])
|
||||
service_data = {}
|
||||
service_data["entity_id"] = f"time.{POLARIS_DEVICE[int(self.device_type)]['class']}_{POLARIS_DEVICE[int(self.device_type)]['model'].replace('-', '_')}_cooking_time"
|
||||
service_data["time"] = str(datetime.timedelta(seconds=cook_time[0]["time"]))
|
||||
await self.hass.services.async_call("time", "set_value", service_data)
|
||||
service_data = {}
|
||||
service_data["entity_id"] = f"number.{POLARIS_DEVICE[int(self.device_type)]['class']}_{POLARIS_DEVICE[int(self.device_type)]['model'].replace('-', '_')}_set_temperature"
|
||||
service_data["value"] = cook_time[0]["temperature"]
|
||||
await self.hass.services.async_call("number", "set_value", service_data)
|
||||
if POLARIS_DEVICE[int(self.device_type)]['class'] == "kettle":
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandTemperature, self.entity_description.options[option])
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandMode, 3)
|
||||
if POLARIS_DEVICE[int(self.device_type)]['class'] == "coffeemaker":
|
||||
if int(self.device_type) == 45:
|
||||
coffee_mode = json.loads(self.entity_description.options[option])
|
||||
|
||||
service_data = {}
|
||||
service_data["entity_id"] = f"number.{POLARIS_DEVICE[int(self.device_type)]['class']}_{POLARIS_DEVICE[int(self.device_type)]['model'].replace('-', '_')}_tank"
|
||||
if coffee_mode[0]["tank"] != 0:
|
||||
service_data["value"] = str(coffee_mode[0]["tank"])
|
||||
else:
|
||||
service_data["value"] = 7.777
|
||||
await self.hass.services.async_call("number", "set_value", service_data)
|
||||
|
||||
service_data = {}
|
||||
service_data["entity_id"] = f"number.{POLARIS_DEVICE[int(self.device_type)]['class']}_{POLARIS_DEVICE[int(self.device_type)]['model'].replace('-', '_')}_amount"
|
||||
if coffee_mode[0]["amount"] != 0:
|
||||
service_data["value"] = str(coffee_mode[0]["amount"])
|
||||
else:
|
||||
service_data["value"] = 100.777
|
||||
await self.hass.services.async_call("number", "set_value", service_data)
|
||||
|
||||
service_data = {}
|
||||
service_data["entity_id"] = f"number.{POLARIS_DEVICE[int(self.device_type)]['class']}_{POLARIS_DEVICE[int(self.device_type)]['model'].replace('-', '_')}_temperature"
|
||||
if coffee_mode[0]["temperature"] != 0:
|
||||
service_data["value"] = str(coffee_mode[0]["temperature"])
|
||||
else:
|
||||
service_data["value"] = 100.777
|
||||
await self.hass.services.async_call("number", "set_value", service_data)
|
||||
|
||||
else:
|
||||
coffee_mode = json.loads(self.entity_description.options[option])
|
||||
for key, val in coffee_mode[0].items():
|
||||
if key == "mode":
|
||||
mode = val
|
||||
elif val != 0:
|
||||
service_data = {}
|
||||
service_data["entity_id"] = f"number.{POLARIS_DEVICE[int(self.device_type)]['class']}_{POLARIS_DEVICE[int(self.device_type)]['model'].replace('-', '_')}_{key}"
|
||||
service_data["value"] = str(val)
|
||||
await self.hass.services.async_call("number", "set_value", service_data)
|
||||
else:
|
||||
if key == "weight":
|
||||
val = "7.777"
|
||||
else:
|
||||
val = "55.777"
|
||||
service_data = {}
|
||||
service_data["entity_id"] = f"number.{POLARIS_DEVICE[int(self.device_type)]['class']}_{POLARIS_DEVICE[int(self.device_type)]['model'].replace('-', '_')}_{key}"
|
||||
service_data["value"] = val
|
||||
await self.hass.services.async_call("number", "set_value", service_data)
|
||||
if self.device_type in POLARIS_CLIMATE_TYPE:
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandMode, self.entity_description.options[option])
|
||||
if self.device_type in POLARIS_AIRCONDITIONER_TYPE:
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandMode, self.entity_description.options[option])
|
||||
if (int(self.entity_description.options[option]) > 0):
|
||||
if self.entity_description.key == "select_swing_horizontal":
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandMode[:-1] + "0", self._conditioner_data0[:2] + "00" + self._conditioner_data0[-4:])
|
||||
if self.entity_description.key == "select_swing_vertical":
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandMode[:-1] + "0", "00" + self._conditioner_data0[-6:])
|
||||
else:
|
||||
if self.entity_description.key == "select_swing_horizontal":
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandMode[:-1] + "0", self._conditioner_data0[:2] + "01" + self._conditioner_data0[-4:])
|
||||
if self.entity_description.key == "select_swing_vertical":
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandMode[:-1] + "0", "01" + self._conditioner_data0[-6:])
|
||||
|
||||
if POLARIS_DEVICE[int(self.device_type)]['class'] == "irrigator":
|
||||
if self._attr_current_option == "preset3":
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandMode+"speed", "10" if self._preset_3[0] == "a" else self._preset_3[0])
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandMode+"ioniser", self._preset_3[1])
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandMode+"smart_mode", self._preset_3[2])
|
||||
elif self._attr_current_option == "preset2":
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandMode+"speed", "10" if self._preset_2[0] == "a" else self._preset_2[0])
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandMode+"ioniser", self._preset_2[1])
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandMode+"smart_mode", self._preset_2[2])
|
||||
else:
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandMode+"speed", "10" if self._preset_1[0] == "a" else self._preset_1[0])
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandMode+"ioniser", self._preset_1[1])
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandMode+"smart_mode", self._preset_1[2])
|
||||
if (self.device_type == "826" and self._EAP_data0[:2] == "02"):
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandMode, self._EAP_data0[:3] + str(self.entity_description.options[option]))
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
@callback
|
||||
def message_received_sel(message):
|
||||
payload = message.payload
|
||||
if payload in ("0", "[]"):
|
||||
self._attr_current_option = self._attr_options[0]
|
||||
self.async_write_ha_state()
|
||||
elif POLARIS_DEVICE[int(self.device_type)]['class'] == "cooker":
|
||||
sel_mode = json.loads(payload)[0]["mode"]
|
||||
# if int(sel_mode)>0:
|
||||
# self.switch.set_available(True)
|
||||
# else:
|
||||
# self.switch.set_available(False)
|
||||
sel_opt = self.key_from_option(sel_mode)
|
||||
self._attr_current_option = sel_opt
|
||||
self.async_write_ha_state()
|
||||
elif int(self.device_type) == 45:
|
||||
sel_opt = self.key_from_option(int(payload))
|
||||
self._attr_current_option = sel_opt
|
||||
self.async_write_ha_state()
|
||||
elif int(self.device_type) == 69:
|
||||
self._attr_current_option = self._attr_options[int(payload)]
|
||||
self.async_write_ha_state()
|
||||
elif int(self.device_type) == 813:
|
||||
self._attr_current_option = self._attr_options[int(payload)]
|
||||
self.async_write_ha_state()
|
||||
elif POLARIS_DEVICE[int(self.device_type)]['class'] == "irrigator":
|
||||
self._preset_1 = [payload[1:2], payload[7:8], payload[13:14]]
|
||||
self._preset_2 = [payload[3:4], payload[9:10], payload[15:16]]
|
||||
self._preset_3 = [payload[5:6], payload[11:12], payload[17:]]
|
||||
if self._attr_current_option == "preset3":
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandMode+"speed", "10" if self._preset_3[0] == "a" else self._preset_3[0])
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandMode+"ioniser", self._preset_3[1])
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandMode+"smart_mode", self._preset_3[2])
|
||||
elif self._attr_current_option == "preset2":
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandMode+"speed", "10" if self._preset_2[0] == "a" else self._preset_2[0])
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandMode+"ioniser", self._preset_2[1])
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandMode+"smart_mode", self._preset_2[2])
|
||||
else:
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandMode+"speed", "10" if self._preset_1[0] == "a" else self._preset_1[0])
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandMode+"ioniser", self._preset_1[1])
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandMode+"smart_mode", self._preset_1[2])
|
||||
await mqtt.async_subscribe(self.hass, self.entity_description.mqttTopicCurrentMode, message_received_sel, 1)
|
||||
|
||||
@callback
|
||||
def EAP_data_message_received(message):
|
||||
self._EAP_data0 = message.payload
|
||||
# _LOGGER.debug("EAP data0 message select %s", self._EAP_data0)
|
||||
|
||||
|
||||
if self.device_type == "826":
|
||||
await mqtt.async_subscribe(
|
||||
self.hass,
|
||||
self.entity_description.mqttTopicCurrentMode,
|
||||
EAP_data_message_received,
|
||||
1,
|
||||
)
|
||||
|
||||
@callback
|
||||
def conditioner_data_message_received(message):
|
||||
self._conditioner_data0 = message.payload
|
||||
|
||||
if self.device_type == "813":
|
||||
await mqtt.async_subscribe(
|
||||
self.hass,
|
||||
self.entity_description.mqttTopicCurrentMode[:-1]+"0",
|
||||
conditioner_data_message_received,
|
||||
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)
|
||||
|
||||
529
homeassistant/config/custom_components/polaris/sensor.py
Normal file
529
homeassistant/config/custom_components/polaris/sensor.py
Normal file
@@ -0,0 +1,529 @@
|
||||
"""The Polaris IQ Home component."""
|
||||
from __future__ import annotations
|
||||
|
||||
import copy
|
||||
import json
|
||||
import logging
|
||||
import struct
|
||||
|
||||
from homeassistant.components import mqtt
|
||||
from homeassistant.components.sensor import DOMAIN, SensorEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.device_registry import async_get as async_get_dev_reg
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.util import slugify
|
||||
|
||||
from .common import PolarisBaseEntity
|
||||
|
||||
# Import global values.
|
||||
from .const import (
|
||||
MANUFACTURER,
|
||||
MQTT_ROOT_TOPIC,
|
||||
DEVICEID,
|
||||
DEVICETYPE,
|
||||
POLARIS_DEVICE,
|
||||
SENSORS_ALL_DEVICES,
|
||||
SENSORS_WEIGHT,
|
||||
SENSORS_HUMIDIFIER,
|
||||
SENSORS_RUSCLIMATE_HUMIDIFIER,
|
||||
SENSORS_COOKER,
|
||||
SENSORS_COFFEEMAKER,
|
||||
SENSORS_COFFEEMAKER_ROG,
|
||||
SENSORS_CLIMATE,
|
||||
SENSORS_CLIMATE_200,
|
||||
SENSORS_AIRCLEANER,
|
||||
SENSORS_AIRCLEANER_EAP,
|
||||
SENSORS_VACUUM,
|
||||
SENSORS_WATER_BOILER,
|
||||
SENSORS_IRRIGATOR,
|
||||
SENSORS_HEATER,
|
||||
SENSORS_AIRCONDITIONER,
|
||||
SENSORS_THERMOSTAT,
|
||||
PolarisSensorEntityDescription,
|
||||
POLARIS_KETTLE_TYPE,
|
||||
POLARIS_KETTLE_WITH_WEIGHT_TYPE,
|
||||
POLARIS_HUMIDDIFIER_TYPE,
|
||||
POLARIS_COOKER_TYPE,
|
||||
POLARIS_COFFEEMAKER_TYPE,
|
||||
POLARIS_COFFEEMAKER_ROG_TYPE,
|
||||
POLARIS_CLIMATE_TYPE,
|
||||
POLARIS_AIRCLEANER_TYPE,
|
||||
POLARIS_AIRCLEANER_EAP_TYPE,
|
||||
POLARIS_VACUUM_TYPE,
|
||||
POLARIS_BOILER_TYPE,
|
||||
POLARIS_IRRIGATOR_TYPE,
|
||||
POLARIS_HEATER_TYPE,
|
||||
POLARIS_AIRCONDITIONER_TYPE,
|
||||
POLARIS_THERMOSTAT_TYPE,
|
||||
KETTLE_ERROR,
|
||||
HUMIDDIFIER_ERROR,
|
||||
COOKER_ERROR,
|
||||
COFFEEMAKER_ERROR,
|
||||
AIRCLEANER_ERROR,
|
||||
VACUUM_ERROR,
|
||||
)
|
||||
|
||||
_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
|
||||
mqttRoot = config.data[MQTT_ROOT_TOPIC]
|
||||
deviceID = config.data["DEVICEID"]
|
||||
devicetype = config.data[DEVICETYPE]
|
||||
device_prefix_topic = config.data["DEVPREFIXTOPIC"]
|
||||
if len(device_prefix_topic)>15:
|
||||
mqtt.publish(hass, f"{mqttRoot}/{device_prefix_topic}/state/devtype", devicetype, 0, True)
|
||||
sensorList = []
|
||||
#Kettle
|
||||
if (devicetype in POLARIS_KETTLE_TYPE):
|
||||
# Create sensors for all devices
|
||||
SENSORS_ALL_DEVICES_CP = copy.deepcopy(SENSORS_ALL_DEVICES)
|
||||
for description in SENSORS_ALL_DEVICES_CP:
|
||||
description.mqttTopicCurrentValue = (f"{mqttRoot}/{device_prefix_topic}/state/{description.key}")
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
sensorList.append(
|
||||
PolarisSensor(
|
||||
description=description,
|
||||
device_friendly_name=deviceID,
|
||||
mqtt_root=mqttRoot,
|
||||
device_type=devicetype,
|
||||
device_id=deviceID,
|
||||
)
|
||||
)
|
||||
#Kettle with weight
|
||||
if (devicetype in POLARIS_KETTLE_WITH_WEIGHT_TYPE):
|
||||
# Create sensors for all devices
|
||||
SENSORS_ALL_DEVICES_CP = copy.deepcopy(SENSORS_ALL_DEVICES)
|
||||
for description in SENSORS_ALL_DEVICES_CP:
|
||||
description.mqttTopicCurrentValue = (f"{mqttRoot}/{device_prefix_topic}/state/{description.key}")
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
sensorList.append(
|
||||
PolarisSensor(
|
||||
description=description,
|
||||
device_friendly_name=deviceID,
|
||||
mqtt_root=mqttRoot,
|
||||
device_type=devicetype,
|
||||
device_id=deviceID,
|
||||
)
|
||||
)
|
||||
SENSORS_WEIGHT_CP = copy.deepcopy(SENSORS_WEIGHT)
|
||||
for description in SENSORS_WEIGHT_CP:
|
||||
description.mqttTopicCurrentValue = (f"{mqttRoot}/{device_prefix_topic}/state/{description.key}")
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
sensorList.append(
|
||||
PolarisSensor(
|
||||
description=description,
|
||||
device_friendly_name=deviceID,
|
||||
mqtt_root=mqttRoot,
|
||||
device_type=devicetype,
|
||||
device_id=deviceID,
|
||||
)
|
||||
)
|
||||
# Humidifier
|
||||
if (devicetype in POLARIS_HUMIDDIFIER_TYPE):
|
||||
if devicetype == "881":
|
||||
SENSORS_RUSCLIMATE_HUMIDIFIER_CP = copy.deepcopy(SENSORS_RUSCLIMATE_HUMIDIFIER)
|
||||
for description in SENSORS_RUSCLIMATE_HUMIDIFIER_CP:
|
||||
description.mqttTopicCurrentValue = (f"{mqttRoot}/{device_prefix_topic}/state/{description.key}")
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
sensorList.append(
|
||||
PolarisSensor(
|
||||
description=description,
|
||||
device_friendly_name=deviceID,
|
||||
mqtt_root=mqttRoot,
|
||||
device_type=devicetype,
|
||||
device_id=deviceID,
|
||||
)
|
||||
)
|
||||
else:
|
||||
# Create sensors for all devices
|
||||
SENSORS_ALL_DEVICES_CP = copy.deepcopy(SENSORS_ALL_DEVICES)
|
||||
for description in SENSORS_ALL_DEVICES_CP:
|
||||
description.mqttTopicCurrentValue = (f"{mqttRoot}/{device_prefix_topic}/state/{description.key}")
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
sensorList.append(
|
||||
PolarisSensor(
|
||||
description=description,
|
||||
device_friendly_name=deviceID,
|
||||
mqtt_root=mqttRoot,
|
||||
device_type=devicetype,
|
||||
device_id=deviceID,
|
||||
)
|
||||
)
|
||||
SENSORS_HUMIDIFIER_CP = copy.deepcopy(SENSORS_HUMIDIFIER)
|
||||
for description in SENSORS_HUMIDIFIER_CP:
|
||||
if (devicetype != "835" or description.translation_key != "clean_retain"):
|
||||
description.mqttTopicCurrentValue = (f"{mqttRoot}/{device_prefix_topic}/state/{description.key}")
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
sensorList.append(
|
||||
PolarisSensor(
|
||||
description=description,
|
||||
device_friendly_name=deviceID,
|
||||
mqtt_root=mqttRoot,
|
||||
device_type=devicetype,
|
||||
device_id=deviceID,
|
||||
)
|
||||
)
|
||||
# Cooker
|
||||
if (devicetype in POLARIS_COOKER_TYPE):
|
||||
# Create sensors for all devices
|
||||
SENSORS_ALL_DEVICES_CP = copy.deepcopy(SENSORS_ALL_DEVICES)
|
||||
for description in SENSORS_ALL_DEVICES_CP:
|
||||
description.mqttTopicCurrentValue = (f"{mqttRoot}/{device_prefix_topic}/state/{description.key}")
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
sensorList.append(
|
||||
PolarisSensor(
|
||||
description=description,
|
||||
device_friendly_name=deviceID,
|
||||
mqtt_root=mqttRoot,
|
||||
device_type=devicetype,
|
||||
device_id=deviceID,
|
||||
)
|
||||
)
|
||||
SENSORS_COOKER_CP = copy.deepcopy(SENSORS_COOKER)
|
||||
for description in SENSORS_COOKER_CP:
|
||||
description.mqttTopicCurrentValue = (f"{mqttRoot}/{device_prefix_topic}/state/{description.key}")
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
sensorList.append(
|
||||
PolarisSensor(
|
||||
description=description,
|
||||
device_friendly_name=deviceID,
|
||||
mqtt_root=mqttRoot,
|
||||
device_type=devicetype,
|
||||
device_id=deviceID,
|
||||
)
|
||||
)
|
||||
# Coffeemaker
|
||||
if (devicetype in POLARIS_COFFEEMAKER_TYPE):
|
||||
# Create sensors for all devices
|
||||
SENSORS_ALL_DEVICES_CP = copy.deepcopy(SENSORS_ALL_DEVICES)
|
||||
for description in SENSORS_ALL_DEVICES_CP:
|
||||
description.mqttTopicCurrentValue = (f"{mqttRoot}/{device_prefix_topic}/state/{description.key}")
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
sensorList.append(
|
||||
PolarisSensor(
|
||||
description=description,
|
||||
device_friendly_name=deviceID,
|
||||
mqtt_root=mqttRoot,
|
||||
device_type=devicetype,
|
||||
device_id=deviceID,
|
||||
)
|
||||
)
|
||||
SENSORS_COFFEEMAKER_CP = copy.deepcopy(SENSORS_COFFEEMAKER)
|
||||
for description in SENSORS_COFFEEMAKER_CP:
|
||||
description.mqttTopicCurrentValue = (f"{mqttRoot}/{device_prefix_topic}/state/{description.key}")
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
sensorList.append(
|
||||
PolarisSensor(
|
||||
description=description,
|
||||
device_friendly_name=deviceID,
|
||||
mqtt_root=mqttRoot,
|
||||
device_type=devicetype,
|
||||
device_id=deviceID,
|
||||
)
|
||||
)
|
||||
if (devicetype in POLARIS_COFFEEMAKER_ROG_TYPE):
|
||||
# Create sensors for coffeemaker
|
||||
SENSORS_COFFEEMAKER_ROG_CP = copy.deepcopy(SENSORS_COFFEEMAKER_ROG)
|
||||
for description in SENSORS_COFFEEMAKER_ROG_CP:
|
||||
description.mqttTopicCurrentValue = (f"{mqttRoot}/{device_prefix_topic}/state/{description.key}")
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
sensorList.append(
|
||||
PolarisSensor(
|
||||
description=description,
|
||||
device_friendly_name=deviceID,
|
||||
mqtt_root=mqttRoot,
|
||||
device_type=devicetype,
|
||||
device_id=deviceID,
|
||||
)
|
||||
)
|
||||
if (devicetype in POLARIS_CLIMATE_TYPE):
|
||||
# Create sensors for climate asp-200 or asp-100
|
||||
if (devicetype == "859"):
|
||||
SENSORS_CLIMATE_CP = copy.deepcopy(SENSORS_CLIMATE_200)
|
||||
else:
|
||||
SENSORS_CLIMATE_CP = copy.deepcopy(SENSORS_CLIMATE)
|
||||
for description in SENSORS_CLIMATE_CP:
|
||||
description.mqttTopicCurrentValue = (f"{mqttRoot}/{device_prefix_topic}/state/{description.key}")
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
sensorList.append(
|
||||
PolarisSensor(
|
||||
description=description,
|
||||
device_friendly_name=deviceID,
|
||||
mqtt_root=mqttRoot,
|
||||
device_type=devicetype,
|
||||
device_id=deviceID,
|
||||
)
|
||||
)
|
||||
SENSORS_ALL_DEVICES_CP = copy.deepcopy(SENSORS_ALL_DEVICES)
|
||||
for description in SENSORS_ALL_DEVICES_CP:
|
||||
description.mqttTopicCurrentValue = (f"{mqttRoot}/{device_prefix_topic}/state/{description.key}")
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
sensorList.append(
|
||||
PolarisSensor(
|
||||
description=description,
|
||||
device_friendly_name=deviceID,
|
||||
mqtt_root=mqttRoot,
|
||||
device_type=devicetype,
|
||||
device_id=deviceID,
|
||||
)
|
||||
)
|
||||
if (devicetype in POLARIS_AIRCLEANER_TYPE):
|
||||
SENSORS_AIRCLEANER_CP = copy.deepcopy(SENSORS_AIRCLEANER)
|
||||
for description in SENSORS_AIRCLEANER_CP:
|
||||
description.mqttTopicCurrentValue = (f"{mqttRoot}/{device_prefix_topic}/state/{description.key}")
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
sensorList.append(
|
||||
PolarisSensor(
|
||||
description=description,
|
||||
device_friendly_name=deviceID,
|
||||
mqtt_root=mqttRoot,
|
||||
device_type=devicetype,
|
||||
device_id=deviceID,
|
||||
)
|
||||
)
|
||||
if (devicetype in POLARIS_AIRCLEANER_EAP_TYPE):
|
||||
SENSORS_AIRCLEANER_EAP_CP = copy.deepcopy(SENSORS_AIRCLEANER_EAP)
|
||||
for description in SENSORS_AIRCLEANER_EAP_CP:
|
||||
description.mqttTopicCurrentValue = (f"{mqttRoot}/{device_prefix_topic}/state/{description.key}")
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
sensorList.append(
|
||||
PolarisSensor(
|
||||
description=description,
|
||||
device_friendly_name=deviceID,
|
||||
mqtt_root=mqttRoot,
|
||||
device_type=devicetype,
|
||||
device_id=deviceID,
|
||||
)
|
||||
)
|
||||
if (devicetype in POLARIS_VACUUM_TYPE):
|
||||
SENSORS_VACUUM_CP = copy.deepcopy(SENSORS_VACUUM)
|
||||
for description in SENSORS_VACUUM_CP:
|
||||
description.mqttTopicCurrentValue = (f"{mqttRoot}/{device_prefix_topic}/state/{description.key}")
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
sensorList.append(
|
||||
PolarisSensor(
|
||||
description=description,
|
||||
device_friendly_name=deviceID,
|
||||
mqtt_root=mqttRoot,
|
||||
device_type=devicetype,
|
||||
device_id=deviceID,
|
||||
)
|
||||
)
|
||||
if (devicetype in POLARIS_BOILER_TYPE):
|
||||
SENSORS_WATER_BOILER_CP = copy.deepcopy(SENSORS_WATER_BOILER)
|
||||
for description in SENSORS_WATER_BOILER_CP:
|
||||
if (devicetype not in {"833","802"} or description.translation_key != "anode_retain"):
|
||||
description.mqttTopicCurrentValue = (f"{mqttRoot}/{device_prefix_topic}/state/{description.key}")
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
sensorList.append(
|
||||
PolarisSensor(
|
||||
description=description,
|
||||
device_friendly_name=deviceID,
|
||||
mqtt_root=mqttRoot,
|
||||
device_type=devicetype,
|
||||
device_id=deviceID,
|
||||
)
|
||||
)
|
||||
if (devicetype in POLARIS_IRRIGATOR_TYPE):
|
||||
SENSORS_IRRIGATOR_CP = copy.deepcopy(SENSORS_IRRIGATOR)
|
||||
for description in SENSORS_IRRIGATOR_CP:
|
||||
description.mqttTopicCurrentValue = (f"{mqttRoot}/{device_prefix_topic}/state/{description.key}")
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
sensorList.append(
|
||||
PolarisSensor(
|
||||
description=description,
|
||||
device_friendly_name=deviceID,
|
||||
mqtt_root=mqttRoot,
|
||||
device_type=devicetype,
|
||||
device_id=deviceID,
|
||||
)
|
||||
)
|
||||
if (devicetype in POLARIS_HEATER_TYPE):
|
||||
SENSORS_HEATER_CP = copy.deepcopy(SENSORS_HEATER)
|
||||
for description in SENSORS_HEATER_CP:
|
||||
description.mqttTopicCurrentValue = (f"{mqttRoot}/{device_prefix_topic}/state/{description.key}")
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
sensorList.append(
|
||||
PolarisSensor(
|
||||
description=description,
|
||||
device_friendly_name=deviceID,
|
||||
mqtt_root=mqttRoot,
|
||||
device_type=devicetype,
|
||||
device_id=deviceID,
|
||||
)
|
||||
)
|
||||
if (devicetype in POLARIS_AIRCONDITIONER_TYPE):
|
||||
SENSORS_AIRCONDITIONER_CP = copy.deepcopy(SENSORS_AIRCONDITIONER)
|
||||
for description in SENSORS_AIRCONDITIONER_CP:
|
||||
description.mqttTopicCurrentValue = (f"{mqttRoot}/{device_prefix_topic}/state/{description.key}")
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
sensorList.append(
|
||||
PolarisSensor(
|
||||
description=description,
|
||||
device_friendly_name=deviceID,
|
||||
mqtt_root=mqttRoot,
|
||||
device_type=devicetype,
|
||||
device_id=deviceID,
|
||||
)
|
||||
)
|
||||
if (devicetype in POLARIS_THERMOSTAT_TYPE):
|
||||
SENSORS_ALL_DEVICES_CP = copy.deepcopy(SENSORS_ALL_DEVICES)
|
||||
for description in SENSORS_ALL_DEVICES_CP:
|
||||
description.mqttTopicCurrentValue = (f"{mqttRoot}/{device_prefix_topic}/state/{description.key}")
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
sensorList.append(
|
||||
PolarisSensor(
|
||||
description=description,
|
||||
device_friendly_name=deviceID,
|
||||
mqtt_root=mqttRoot,
|
||||
device_type=devicetype,
|
||||
device_id=deviceID,
|
||||
)
|
||||
)
|
||||
SENSORS_THERMOSTAT_CP = copy.deepcopy(SENSORS_THERMOSTAT)
|
||||
for description in SENSORS_THERMOSTAT_CP:
|
||||
description.mqttTopicCurrentValue = (f"{mqttRoot}/{device_prefix_topic}/state/{description.key}")
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
sensorList.append(
|
||||
PolarisSensor(
|
||||
description=description,
|
||||
device_friendly_name=deviceID,
|
||||
mqtt_root=mqttRoot,
|
||||
device_type=devicetype,
|
||||
device_id=deviceID,
|
||||
)
|
||||
)
|
||||
async_add_entities(sensorList)
|
||||
|
||||
|
||||
class PolarisSensor(PolarisBaseEntity, SensorEntity):
|
||||
|
||||
entity_description: PolarisSensorEntityDescription
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
# uniqueID: str | None,
|
||||
device_friendly_name: str,
|
||||
mqtt_root: str,
|
||||
description: PolarisSensorEntityDescription,
|
||||
device_type: str,
|
||||
device_id: str,
|
||||
) -> 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_has_entity_name = True
|
||||
self._attr_available = False
|
||||
|
||||
|
||||
def bytes_to_int16_array(self, byte_data, byteorder='little'):
|
||||
"""
|
||||
Преобразует байтовую строку в массив int16.
|
||||
Аргументы:
|
||||
byte_data: Байтовая строка для преобразования (bytes).
|
||||
byteorder: Порядок байтов ('little' или 'big'), по умолчанию 'little'.
|
||||
Возвращает:
|
||||
Массив int16 значений (list of int).
|
||||
Вызывает исключение ValueError:
|
||||
Если длина byte_data нечетная.
|
||||
Если byteorder не является 'little' или 'big'.
|
||||
"""
|
||||
if len(byte_data) % 2 != 0:
|
||||
raise ValueError("Длина байтовой строки должна быть четной для int16 преобразования.")
|
||||
if byteorder not in ('little', 'big'):
|
||||
raise ValueError("Неверный порядок байтов. Допустимые значения: 'little', 'big'.")
|
||||
endian_prefix = '<' if byteorder == 'little' else '>' # '<' - little-endian, '>' - big-endian
|
||||
format_string = endian_prefix + 'h' * (len(byte_data) // 2) # 'h' - signed short (2 bytes - int16)
|
||||
return list(struct.unpack(format_string, byte_data))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
@callback
|
||||
def message_received(message):
|
||||
payload_message = message.payload
|
||||
if self.entity_description.name == "error":
|
||||
if POLARIS_DEVICE[int(self.device_type)]['class'] == "cooker":
|
||||
payload_message = COOKER_ERROR[payload_message]
|
||||
if POLARIS_DEVICE[int(self.device_type)]['class'] == "kettle":
|
||||
payload_message = KETTLE_ERROR[payload_message]
|
||||
if POLARIS_DEVICE[int(self.device_type)]['class'] == "humidifier":
|
||||
payload_message = HUMIDDIFIER_ERROR[payload_message]
|
||||
if POLARIS_DEVICE[int(self.device_type)]['class'] == "coffeemaker":
|
||||
payload_message = COFFEEMAKER_ERROR[payload_message]
|
||||
if POLARIS_DEVICE[int(self.device_type)]['class'] == "air_cleaner":
|
||||
payload_message = AIRCLEANER_ERROR[payload_message]
|
||||
if POLARIS_DEVICE[int(self.device_type)]['class'] == "cleaner":
|
||||
payload_message = VACUUM_ERROR[payload_message]
|
||||
if self.entity_description.name == "filter_retain":
|
||||
payload_message = payload_message.replace("[","",1).replace("]","",1).split(",")[0]
|
||||
if self.entity_description.name == "pre_filter_retain":
|
||||
payload_message = payload_message.replace("[","",1).replace("]","",1).split(",")[1]
|
||||
if self.entity_description.name == "anode_retain":
|
||||
payload_message = payload_message.replace("[","",1).replace("]","",1).split(",")[0]
|
||||
if self.entity_description.name == "clean_retain":
|
||||
payload_message = payload_message.replace("[","",1).replace("]","",1).split(",")[1]
|
||||
if self.entity_description.name == "mode":
|
||||
payload_message = self.entity_description.valueMap[payload_message]
|
||||
if self.entity_description.name == "power_state":
|
||||
payload_message = self.entity_description.valueMap[payload_message]
|
||||
if self.entity_description.name == "go_area":
|
||||
# _LOGGER.debug("go_area %s", payload_message)
|
||||
list_dubleint = self.bytes_to_int16_array(payload_message)
|
||||
# _LOGGER.debug("bytes_to_int16 %s",list_dubleint)
|
||||
# list_dubleint = self.bytes_to_int16_array(payload_message, byteorder='big')
|
||||
# _LOGGER.debug("list_integers %s",list_dubleint)
|
||||
payload_message = list_dubleint
|
||||
if self.entity_description.name == "quality":
|
||||
payload_message = str( int(payload_message) / 100 )
|
||||
if self.entity_description.name == "сurrent_power":
|
||||
if self.device_type == "806":
|
||||
payload_message = str( int(payload_message[:2],16) * 20 )
|
||||
else:
|
||||
payload_message = str( int(payload_message[:2],16) * 10 )
|
||||
|
||||
self._attr_native_value = payload_message
|
||||
self.async_write_ha_state()
|
||||
|
||||
if self.entity_description.name == "go_area":
|
||||
await mqtt.async_subscribe(
|
||||
self.hass,
|
||||
self.entity_description.mqttTopicCurrentValue,
|
||||
message_received,
|
||||
1,
|
||||
None,
|
||||
)
|
||||
else:
|
||||
await mqtt.async_subscribe(
|
||||
self.hass,
|
||||
self.entity_description.mqttTopicCurrentValue,
|
||||
message_received,
|
||||
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)
|
||||
15
homeassistant/config/custom_components/polaris/services.yaml
Normal file
15
homeassistant/config/custom_components/polaris/services.yaml
Normal file
@@ -0,0 +1,15 @@
|
||||
select_rooms:
|
||||
target:
|
||||
entity:
|
||||
integration: "polaris"
|
||||
domain: "vacuum"
|
||||
name: Select rooms
|
||||
description: Select rooms to clean
|
||||
fields:
|
||||
select_rooms:
|
||||
name: Rooms
|
||||
description: Input of available rooms to clean
|
||||
required: true
|
||||
example: Kitchen
|
||||
selector:
|
||||
text:
|
||||
752
homeassistant/config/custom_components/polaris/switch.py
Normal file
752
homeassistant/config/custom_components/polaris/switch.py
Normal file
@@ -0,0 +1,752 @@
|
||||
"""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.switch import DOMAIN, SwitchEntity
|
||||
#from homeassistant.helpers.restore_state import RestoreEntity
|
||||
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 homeassistant.helpers.device_registry import async_get as async_get_dev_reg
|
||||
|
||||
from .common import PolarisBaseEntity
|
||||
# Import global values.
|
||||
from .const import (
|
||||
MANUFACTURER,
|
||||
MQTT_ROOT_TOPIC,
|
||||
DEVICEID,
|
||||
DEVICETYPE,
|
||||
POLARIS_DEVICE,
|
||||
SWITCHES_ALL_DEVICES,
|
||||
SWITCH_KETTLE_BACKLIGHT,
|
||||
SWITCH_HUMIDIFIER_BACKLIGHT,
|
||||
SWITCH_HUMIDIFIER_IONISER,
|
||||
SWITCH_HUMIDIFIER_WARM_STREAM,
|
||||
SWITCH_HUMIDIFIER_ULTRAVIOLET,
|
||||
SWITCHES_RUSCLIMATE_HUMIDIFIER,
|
||||
SWITCHES_COOKER,
|
||||
SWITCHES_COFFEEMAKER,
|
||||
SWITCHES_COFFEEMAKER_ROG,
|
||||
SWITCHES_CLIMATE,
|
||||
SWITCHES_CLIMATE_200,
|
||||
SWITCHES_AIRCLEANER,
|
||||
SWITCHES_AIRCLEANER_EAP,
|
||||
SWITCHES_VACUUM,
|
||||
SWITCHES_WATER_BOILER,
|
||||
SWITCHES_WATER_BOILER_NO_FROST,
|
||||
SWITCHES_WATER_BOILER_BACKLIGHT,
|
||||
SWITCHES_IRRIGATOR,
|
||||
SWITCHES_HEATER,
|
||||
SWITCHES_AIRCONDITIONER,
|
||||
SWITCHES_AIRCONDITIONER_820,
|
||||
SWITCHES_AIRCONDITIONER_882,
|
||||
SWITCHES_THERMOSTAT,
|
||||
PolarisSwitchEntityDescription,
|
||||
POLARIS_KETTLE_TYPE,
|
||||
POLARIS_KETTLE_WITH_WEIGHT_TYPE,
|
||||
POLARIS_KETTLE_WITH_BACKLIGHT_TYPE,
|
||||
POLARIS_HUMIDDIFIER_TYPE,
|
||||
POLARIS_HUMIDDIFIER_WITH_IONISER_TYPE,
|
||||
POLARIS_HUMIDDIFIER_WITH_WARM_STREAM_TYPE,
|
||||
POLARIS_COOKER_TYPE,
|
||||
POLARIS_COFFEEMAKER_TYPE,
|
||||
POLARIS_COFFEEMAKER_ROG_TYPE,
|
||||
POLARIS_CLIMATE_TYPE,
|
||||
POLARIS_AIRCLEANER_TYPE,
|
||||
POLARIS_AIRCLEANER_EAP_TYPE,
|
||||
POLARIS_VACUUM_TYPE,
|
||||
POLARIS_BOILER_TYPE,
|
||||
POLARIS_IRRIGATOR_TYPE,
|
||||
POLARIS_HEATER_TYPE,
|
||||
POLARIS_AIRCONDITIONER_TYPE,
|
||||
POLARIS_THERMOSTAT_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"]
|
||||
switchList = []
|
||||
|
||||
if (device_type in POLARIS_KETTLE_TYPE) or (device_type in POLARIS_KETTLE_WITH_WEIGHT_TYPE):
|
||||
# Create sensors for all devices
|
||||
SWITCHES_ALL_DEVICES_LC = copy.deepcopy(SWITCHES_ALL_DEVICES)
|
||||
for description in SWITCHES_ALL_DEVICES_LC:
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.mqttTopicCurrentValue = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentValue}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
switchList.append(
|
||||
PolarisSwitch(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if device_type in POLARIS_KETTLE_WITH_BACKLIGHT_TYPE:
|
||||
# Create sensors for backlight devices
|
||||
SWITCH_KETTLE_BACKLIGHT_LC = copy.deepcopy(SWITCH_KETTLE_BACKLIGHT)
|
||||
for description in SWITCH_KETTLE_BACKLIGHT_LC:
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.mqttTopicCurrentValue = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentValue}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
switchList.append(
|
||||
PolarisSwitch(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_HUMIDDIFIER_TYPE):
|
||||
if device_type == "881":
|
||||
SWITCHES_RUSCLIMATE_HUMIDIFIER_LC = copy.deepcopy(SWITCHES_RUSCLIMATE_HUMIDIFIER)
|
||||
for description in SWITCHES_RUSCLIMATE_HUMIDIFIER_LC:
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.mqttTopicCurrentValue = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentValue}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
switchList.append(
|
||||
PolarisSwitch(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
else:
|
||||
# Create switches for all devices
|
||||
SWITCHES_ALL_DEVICES_LC = copy.deepcopy(SWITCHES_ALL_DEVICES)
|
||||
for description in SWITCHES_ALL_DEVICES_LC:
|
||||
if (device_type != "835" or description.translation_key != "child_lock_switch"):
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.mqttTopicCurrentValue = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentValue}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
switchList.append(
|
||||
PolarisSwitch(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
SWITCH_HUMIDIFIER_BACKLIGHT_LC = copy.deepcopy(SWITCH_HUMIDIFIER_BACKLIGHT)
|
||||
for description in SWITCH_HUMIDIFIER_BACKLIGHT_LC:
|
||||
if (device_type != "835" or description.translation_key != "backlight_switch"):
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.mqttTopicCurrentValue = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentValue}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
switchList.append(
|
||||
PolarisSwitch(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_HUMIDDIFIER_WITH_IONISER_TYPE):
|
||||
# Create switch ioniser for humidifiers
|
||||
SWITCH_HUMIDIFIER_IONISER_LC = copy.deepcopy(SWITCH_HUMIDIFIER_IONISER)
|
||||
for description in SWITCH_HUMIDIFIER_IONISER_LC:
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.mqttTopicCurrentValue = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentValue}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
switchList.append(
|
||||
PolarisSwitch(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_HUMIDDIFIER_WITH_WARM_STREAM_TYPE):
|
||||
# Create switch stream warm for humidifiers
|
||||
SWITCH_HUMIDIFIER_WARM_STREAM_LC = copy.deepcopy(SWITCH_HUMIDIFIER_WARM_STREAM)
|
||||
for description in SWITCH_HUMIDIFIER_WARM_STREAM_LC:
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.mqttTopicCurrentValue = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentValue}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
switchList.append(
|
||||
PolarisSwitch(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in {"835","157"}):
|
||||
# Create switch stream warm for humidifiers
|
||||
SWITCH_HUMIDIFIER_ULTRAVIOLET_LC = copy.deepcopy(SWITCH_HUMIDIFIER_ULTRAVIOLET)
|
||||
for description in SWITCH_HUMIDIFIER_ULTRAVIOLET_LC:
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.mqttTopicCurrentValue = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentValue}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
switchList.append(
|
||||
PolarisSwitch(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_COOKER_TYPE):
|
||||
# Create switches for cooker
|
||||
SWITCHES_COOKER_LC = copy.deepcopy(SWITCHES_COOKER)
|
||||
for description in SWITCHES_COOKER_LC:
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.mqttTopicCurrentValue = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentValue}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
switchList.append(
|
||||
PolarisSwitch(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_COFFEEMAKER_TYPE):
|
||||
# Create switches for coffeemaker
|
||||
SWITCHES_COFFEEMAKER_LC = copy.deepcopy(SWITCHES_COFFEEMAKER)
|
||||
for description in SWITCHES_COFFEEMAKER_LC:
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.mqttTopicCurrentValue = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentValue}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
switchList.append(
|
||||
PolarisSwitch(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_COFFEEMAKER_ROG_TYPE):
|
||||
# Create switches for coffeemaker
|
||||
SWITCHES_COFFEEMAKER_ROG_LC = copy.deepcopy(SWITCHES_COFFEEMAKER_ROG)
|
||||
for description in SWITCHES_COFFEEMAKER_ROG_LC:
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.mqttTopicCurrentValue = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentValue}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
switchList.append(
|
||||
PolarisSwitch(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_CLIMATE_TYPE):
|
||||
# Create switches for climate
|
||||
SWITCHES_CLIMATE_LC = copy.deepcopy(SWITCHES_CLIMATE)
|
||||
for description in SWITCHES_CLIMATE_LC:
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.mqttTopicCurrentValue = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentValue}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
switchList.append(
|
||||
PolarisSwitch(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type == "859"):
|
||||
SWITCHES_CLIMATE_200_LC = copy.deepcopy(SWITCHES_CLIMATE_200)
|
||||
for description in SWITCHES_CLIMATE_200_LC:
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.mqttTopicCurrentValue = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentValue}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
switchList.append(
|
||||
PolarisSwitch(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_AIRCLEANER_TYPE):
|
||||
# Create switches for all devices
|
||||
SWITCHES_ALL_DEVICES_LC = copy.deepcopy(SWITCHES_ALL_DEVICES)
|
||||
for description in SWITCHES_ALL_DEVICES_LC:
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.mqttTopicCurrentValue = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentValue}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
switchList.append(
|
||||
PolarisSwitch(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
SWITCHES_AIRCLEANER_LC = copy.deepcopy(SWITCHES_AIRCLEANER)
|
||||
for description in SWITCHES_AIRCLEANER_LC:
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.mqttTopicCurrentValue = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentValue}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
switchList.append(
|
||||
PolarisSwitch(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_AIRCLEANER_EAP_TYPE):
|
||||
SWITCHES_AIRCLEANER_EAP_LC = copy.deepcopy(SWITCHES_AIRCLEANER_EAP)
|
||||
for description in SWITCHES_AIRCLEANER_EAP_LC:
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.mqttTopicCurrentValue = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentValue}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
switchList.append(
|
||||
PolarisSwitch(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_VACUUM_TYPE):
|
||||
# Create switches for vacuum
|
||||
SWITCHES_VACUUM_LC = copy.deepcopy(SWITCHES_VACUUM)
|
||||
for description in SWITCHES_VACUUM_LC:
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.mqttTopicCurrentValue = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentValue}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
switchList.append(
|
||||
PolarisSwitch(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_BOILER_TYPE):
|
||||
# Create switches for boiler
|
||||
SWITCHES_WATER_BOILER_LC = copy.deepcopy(SWITCHES_WATER_BOILER)
|
||||
for description in SWITCHES_WATER_BOILER_LC:
|
||||
if (device_type not in {"802","833","844"} or description.translation_key != "child_lock_switch") and (device_type != "833" or description.translation_key != "smart_mode"):
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.mqttTopicCurrentValue = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentValue}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
switchList.append(
|
||||
PolarisSwitch(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type == "844"):
|
||||
# Create switches for boiler bright 50%
|
||||
SWITCHES_WATER_BOILER_BACKLIGHT_LC = copy.deepcopy(SWITCHES_WATER_BOILER_BACKLIGHT)
|
||||
for description in SWITCHES_WATER_BOILER_BACKLIGHT_LC:
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.mqttTopicCurrentValue = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentValue}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
switchList.append(
|
||||
PolarisSwitch(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type == "802"):
|
||||
# Create switches for boiler no frost
|
||||
SWITCHES_WATER_BOILER_NO_FROST_LC = copy.deepcopy(SWITCHES_WATER_BOILER_NO_FROST)
|
||||
for description in SWITCHES_WATER_BOILER_NO_FROST_LC:
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.mqttTopicCurrentValue = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentValue}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
switchList.append(
|
||||
PolarisSwitch(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_IRRIGATOR_TYPE):
|
||||
# Create switches for irrigator
|
||||
SWITCHES_IRRIGATOR_LC = copy.deepcopy(SWITCHES_IRRIGATOR)
|
||||
for description in SWITCHES_IRRIGATOR_LC:
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.mqttTopicCurrentValue = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentValue}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
switchList.append(
|
||||
PolarisSwitch(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_HEATER_TYPE):
|
||||
# Create switches for heater
|
||||
SWITCHES_HEATER_LC = copy.deepcopy(SWITCHES_HEATER)
|
||||
for description in SWITCHES_HEATER_LC:
|
||||
if (device_type not in {"806","847"} or description.translation_key != "half_power_heater"):
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.mqttTopicCurrentValue = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentValue}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
switchList.append(
|
||||
PolarisSwitch(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type == "820"):
|
||||
SWITCHES_AIRCONDITIONER_820_LC = copy.deepcopy(SWITCHES_AIRCONDITIONER_820)
|
||||
for description in SWITCHES_AIRCONDITIONER_820_LC:
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.mqttTopicCurrentValue = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentValue}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
switchList.append(
|
||||
PolarisSwitch(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type == "813"):
|
||||
SWITCHES_AIRCONDITIONER_LC = copy.deepcopy(SWITCHES_AIRCONDITIONER)
|
||||
for description in SWITCHES_AIRCONDITIONER_LC:
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.mqttTopicCurrentValue = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentValue}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
switchList.append(
|
||||
PolarisSwitch(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type == "882"):
|
||||
SWITCHES_AIRCONDITIONER_882_LC = copy.deepcopy(SWITCHES_AIRCONDITIONER_882)
|
||||
for description in SWITCHES_AIRCONDITIONER_882_LC:
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.mqttTopicCurrentValue = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentValue}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
switchList.append(
|
||||
PolarisSwitch(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_THERMOSTAT_TYPE):
|
||||
SWITCHES_THERMOSTAT_LC = copy.deepcopy(SWITCHES_THERMOSTAT)
|
||||
for description in SWITCHES_THERMOSTAT_LC:
|
||||
description.mqttTopicCommand = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommand}"
|
||||
description.mqttTopicCurrentValue = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentValue}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
switchList.append(
|
||||
PolarisSwitch(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
async_add_entities(switchList, update_before_add=True)
|
||||
|
||||
class PolarisSwitch(PolarisBaseEntity, SwitchEntity):
|
||||
entity_description: PolarisSwitchEntityDescription
|
||||
def __init__(
|
||||
self,
|
||||
device_friendly_name: str,
|
||||
description: PolarisSwitchEntityDescription,
|
||||
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.payload_on=description.payload_on
|
||||
self.payload_off=description.payload_off
|
||||
self._attr_has_entity_name = True
|
||||
# self._old_mode = "0"
|
||||
self._attr_available = False
|
||||
# self._attr_assumed_state = False
|
||||
# self._optimistic = False
|
||||
# self._value_template = self.entity_description.mqttTopicCurrentValue
|
||||
if device_type == "806":
|
||||
self._heater_prog_data0 = "0000"
|
||||
else:
|
||||
self._heater_prog_data0 = "000000"
|
||||
if device_type == "826":
|
||||
self._EAP_data0 = "0000"
|
||||
if device_type in POLARIS_AIRCONDITIONER_TYPE:
|
||||
if device_type == "882":
|
||||
self._swing_message = "000000000000"
|
||||
else:
|
||||
self._swing_message = "00000000"
|
||||
self._aircond_data0 = "0000"
|
||||
if self.entity_description.key == "turbo":
|
||||
self._attr_available = False
|
||||
if self.entity_description.key == "self_cleaning":
|
||||
self._attr_available = False
|
||||
if self.entity_description.key == "eco_mode_switch":
|
||||
self._attr_available = False
|
||||
if self.entity_description.key == "anti_fingus":
|
||||
self._attr_available = False
|
||||
if self.entity_description.key == "night":
|
||||
self._attr_available = False
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
@callback
|
||||
def message_received(message):
|
||||
if POLARIS_DEVICE[int(self.device_type)]['class'] == "coffeemaker":
|
||||
if int(self.device_type) in POLARIS_COFFEEMAKER_ROG_TYPE:
|
||||
if str(message.payload) in ("1", "2", "3", "4", "5", "6"):
|
||||
self._attr_is_on = True
|
||||
else:
|
||||
self._attr_is_on = False
|
||||
elif str(message.payload) in ("01", "1", "03", "3"):
|
||||
self._attr_is_on = True
|
||||
else:
|
||||
self._attr_is_on = False
|
||||
elif self.entity_description.key == "display_off_heater":
|
||||
self._heater_prog_data0 = str(message.payload)
|
||||
self._attr_is_on = True if (self._heater_prog_data0[2:4] == "01") else False
|
||||
elif self.entity_description.key == "half_power_heater":
|
||||
self._heater_prog_data0 = str(message.payload)
|
||||
self._attr_is_on = True if (self._heater_prog_data0[-2:] == "01") else False
|
||||
|
||||
elif self.entity_description.key == "quiet_mode":
|
||||
self._aircond_data0 = str(message.payload)
|
||||
self._attr_is_on = True if (self._aircond_data0[-2:] == "01") else False
|
||||
elif self.entity_description.key == "self_cleaning":
|
||||
self._aircond_data0 = str(message.payload)
|
||||
self._attr_is_on = True if (self._aircond_data0[:2] == "01") else False
|
||||
else:
|
||||
if str(message.payload).lower() in ("1", "01", "2", "3", "4", "5", "true"):
|
||||
self._attr_is_on = True
|
||||
elif str(message.payload).lower() in ("0", "00", "false"):
|
||||
self._attr_is_on = False
|
||||
self.async_write_ha_state()
|
||||
|
||||
await mqtt.async_subscribe(
|
||||
self.hass,
|
||||
self.entity_description.mqttTopicCurrentValue,
|
||||
message_received,
|
||||
1,
|
||||
)
|
||||
|
||||
@callback
|
||||
def mode_message_received(message):
|
||||
if self.entity_description.translation_key == "keepwarm_switch":
|
||||
if str(message.payload) in ("[]", '[{"mode":1,"time":0,"temperature":0}]'):
|
||||
self._attr_available = False
|
||||
# self._attr_is_on = False
|
||||
else:
|
||||
self._attr_available = True
|
||||
self._attr_is_on = True
|
||||
self.async_write_ha_state()
|
||||
|
||||
await mqtt.async_subscribe(
|
||||
self.hass,
|
||||
self.entity_description.mqttTopicCurrentValue.replace("keepwarm", "steps"),
|
||||
mode_message_received,
|
||||
1,
|
||||
)
|
||||
|
||||
@callback
|
||||
def EAP_data_message_received(message):
|
||||
self._EAP_data0 = message.payload
|
||||
if self.device_type == "826":
|
||||
await mqtt.async_subscribe(
|
||||
self.hass,
|
||||
self.entity_description.mqttTopicCurrentValue.replace("backlight", "program_data/0"),
|
||||
EAP_data_message_received,
|
||||
1,
|
||||
)
|
||||
|
||||
@callback
|
||||
def mode_conditioner_data_message_received(message):
|
||||
if self.entity_description.key in ("auto_heater_switch", "eco_mode_switch", "turbo", "night", "self_cleaning", "anti_fingus"):
|
||||
if (message.payload == "5"): #FAN
|
||||
if self.entity_description.key == "night":
|
||||
self._attr_available = False
|
||||
elif self.entity_description.key == "night":
|
||||
self._attr_available = True
|
||||
if (message.payload == "4"): #HEAT
|
||||
if self.entity_description.key in ("auto_heater_switch", "turbo"):
|
||||
self._attr_available = True
|
||||
elif self.entity_description.key == "auto_heater_switch":
|
||||
self._attr_available = False
|
||||
if (message.payload == "2"): #COOL
|
||||
if self.entity_description.key in ("eco_mode_switch", "turbo"):
|
||||
self._attr_available = True
|
||||
elif self.entity_description.key == "eco_mode_switch":
|
||||
self._attr_available = False
|
||||
if (message.payload == "0"): #OFF
|
||||
if self.entity_description.key in ("self_cleaning", "anti_fingus"):
|
||||
self._attr_available = True
|
||||
elif self.entity_description.key in ("self_cleaning", "anti_fingus"):
|
||||
self._attr_available = False
|
||||
if message.payload in ("0", "1", "3", "5"):
|
||||
if self.entity_description.key == "turbo":
|
||||
self._attr_available = False
|
||||
self.async_write_ha_state()
|
||||
if self.device_type in POLARIS_AIRCONDITIONER_TYPE:
|
||||
await mqtt.async_subscribe(
|
||||
self.hass,
|
||||
f"{self.mqtt_root}/{self.entity_description.device_prefix_topic}/state/mode",
|
||||
mode_conditioner_data_message_received,
|
||||
1,
|
||||
)
|
||||
|
||||
@callback
|
||||
def swing_data_message_received(message):
|
||||
self._swing_message = message.payload
|
||||
if self.entity_description.key == "eco_mode_switch":
|
||||
if message.payload[4:6] == "01":
|
||||
self._attr_is_on = True
|
||||
else:
|
||||
self._attr_is_on = False
|
||||
self.async_write_ha_state()
|
||||
if self.entity_description.key == "auto_heater_switch":
|
||||
if message.payload[-2:] == "01":
|
||||
self._attr_is_on = True
|
||||
else:
|
||||
self._attr_is_on = False
|
||||
self.async_write_ha_state()
|
||||
if self.entity_description.key == "anti_fingus":
|
||||
if message.payload[-2:] == "01":
|
||||
self._attr_is_on = True
|
||||
else:
|
||||
self._attr_is_on = False
|
||||
self.async_write_ha_state()
|
||||
if self.device_type in POLARIS_AIRCONDITIONER_TYPE:
|
||||
await mqtt.async_subscribe(
|
||||
self.hass,
|
||||
self.entity_description.mqttTopicCurrentValue,
|
||||
swing_data_message_received,
|
||||
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:
|
||||
if self.entity_description.key != "keepwarm":
|
||||
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)
|
||||
|
||||
|
||||
def turn_on(self, **kwargs):
|
||||
# self._attr_is_on = True # optimistic mode
|
||||
topic = f"{self.entity_description.mqttTopicCommand}"
|
||||
if self.entity_description.key == "display_off_heater":
|
||||
if self.device_type == "806":
|
||||
send_message = self._heater_prog_data0[:2] + self.payload_on
|
||||
else:
|
||||
send_message = self._heater_prog_data0[:2] + self.payload_on + self._heater_prog_data0[-2:]
|
||||
elif self.entity_description.key == "eco_mode_switch":
|
||||
send_message = self._swing_message[:4] + self.payload_on + self._swing_message[-2:]
|
||||
elif self.entity_description.key == "auto_heater_switch":
|
||||
send_message = self._swing_message[:6] + self.payload_on
|
||||
elif self.entity_description.key == "anti_fingus":
|
||||
send_message = self._swing_message[:6] + self.payload_on
|
||||
elif self.entity_description.key == "half_power_heater":
|
||||
send_message = self._heater_prog_data0[:4] + self.payload_on
|
||||
elif self.entity_description.key == "quiet_mode":
|
||||
send_message = self._aircond_data0[:2] + self.payload_on
|
||||
elif self.entity_description.key == "self_cleaning":
|
||||
send_message = self.payload_on + self._aircond_data0[-2:]
|
||||
elif (self.device_type == "826" and self.entity_description.key == "backlight"):
|
||||
self._EAP_data0 = self._EAP_data0[:2] + "01"
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommand.replace("backlight", "program_data/0"), self._EAP_data0)
|
||||
send_message = self.payload_on
|
||||
else:
|
||||
send_message = self.payload_on
|
||||
mqtt.publish(self.hass, topic, send_message)
|
||||
|
||||
|
||||
def turn_off(self, **kwargs):
|
||||
# self._attr_is_on = False # optimistic mode
|
||||
topic = f"{self.entity_description.mqttTopicCommand}"
|
||||
if self.entity_description.key == "display_off_heater":
|
||||
if self.device_type == "806":
|
||||
send_message = self._heater_prog_data0[:2] + self.payload_off
|
||||
else:
|
||||
send_message = self._heater_prog_data0[:2] + self.payload_off + self._heater_prog_data0[-2:]
|
||||
elif self.entity_description.key == "eco_mode_switch":
|
||||
send_message = self._swing_message[:4] + self.payload_off + self._swing_message[-2:]
|
||||
elif self.entity_description.key == "auto_heater_switch":
|
||||
send_message = self._swing_message[:6] + self.payload_off
|
||||
elif self.entity_description.key == "anti_fingus":
|
||||
send_message = self._swing_message[:6] + self.payload_off
|
||||
elif self.entity_description.key == "half_power_heater":
|
||||
send_message = self._heater_prog_data0[:4] + self.payload_off
|
||||
elif self.entity_description.key == "quiet_mode":
|
||||
send_message = self._aircond_data0[:2] + self.payload_off
|
||||
elif self.entity_description.key == "self_cleaning":
|
||||
send_message = self.payload_off + self._aircond_data0[-2:]
|
||||
elif (self.device_type == "826" and self.entity_description.key == "backlight"):
|
||||
self._EAP_data0 = self._EAP_data0[:2] + "00"
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommand.replace("backlight", "program_data/0"), self._EAP_data0)
|
||||
send_message = self.payload_off
|
||||
else:
|
||||
send_message = self.payload_off
|
||||
mqtt.publish(self.hass, topic, send_message)
|
||||
|
||||
|
||||
|
||||
114
homeassistant/config/custom_components/polaris/time.py
Normal file
114
homeassistant/config/custom_components/polaris/time.py
Normal file
@@ -0,0 +1,114 @@
|
||||
"""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 datetime import time
|
||||
from homeassistant.components.time import DOMAIN, TimeEntity, TimeEntityDescription
|
||||
#from homeassistant.components.datetime import DOMAIN, DateTimeEntity, DateTimeEntityDescription
|
||||
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
|
||||
# Import global values.
|
||||
from .const import (
|
||||
MANUFACTURER,
|
||||
MQTT_ROOT_TOPIC,
|
||||
DEVICEID,
|
||||
DEVICETYPE,
|
||||
POLARIS_DEVICE,
|
||||
TIME_COOKER,
|
||||
PolarisTimeEntityDescription,
|
||||
POLARIS_COOKER_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"]
|
||||
timeList = []
|
||||
|
||||
if (device_type in POLARIS_COOKER_TYPE):
|
||||
TIME_COOKER_LC = copy.deepcopy(TIME_COOKER)
|
||||
for description in TIME_COOKER_LC:
|
||||
description.mqttTopicCurrentTime = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentTime}"
|
||||
description.mqttTopicCommandTime = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandTime}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
timeList.append(
|
||||
PolarisTime(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
async_add_entities(timeList, update_before_add=True)
|
||||
|
||||
|
||||
class PolarisTime(PolarisBaseEntity, TimeEntity):
|
||||
|
||||
entity_description: PolarisTimeDescription
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
device_friendly_name: str,
|
||||
description: PolarisTimeEntityDescription,
|
||||
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_available = False
|
||||
self._attr_has_entity_name = True
|
||||
self._attr_native_value = time(0, self.entity_description.default_time, 0)
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
@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_set_value(self, value: time) -> None:
|
||||
"""Update the time."""
|
||||
value_hour=value.hour
|
||||
value_minute=value.minute
|
||||
value_second=0
|
||||
value_in_seconds = value.hour * 3600 + value.minute * 60
|
||||
if (value_in_seconds > (self.entity_description.max_time * 60)):
|
||||
value_hour = int(self.entity_description.max_time / 60) - 1
|
||||
self._attr_native_value = time(value_hour,value_minute,value_second)
|
||||
value_in_seconds = value_hour * 3600 + value_minute * 60
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandTime, str(value_in_seconds))
|
||||
|
||||
@@ -0,0 +1,669 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "This device has already been configured.",
|
||||
"not_supported": "Error. Not selected device type."
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "Failed to connect, please try again.",
|
||||
"invalid_auth": "Invalid authentication.",
|
||||
"too_many_requests": "Too many requests, retry later.",
|
||||
"unknown": "Unexpected error.",
|
||||
"Unknown error occurred": "Unexpected error."
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"description": "Configuring Polaris Local MQTT.",
|
||||
"data": {
|
||||
"DEVICEID": "Select a device (or all devices)",
|
||||
"MQTT_ROOT_TOPIC": "Topic Prefix (usually 'polaris')"
|
||||
},
|
||||
"title": "Polaris Local MQTT"
|
||||
},
|
||||
"undef": {
|
||||
"description": "Configuring Polaris device.",
|
||||
"data": {
|
||||
"DEVICETYPE": "Select device type"
|
||||
},
|
||||
"title": "Polaris Local MQTT"
|
||||
}
|
||||
}
|
||||
},
|
||||
"entity": {
|
||||
"switch": {
|
||||
"sound_switch": {
|
||||
"name": "Sound"
|
||||
},
|
||||
"power_switch": {
|
||||
"name": "Power"
|
||||
},
|
||||
"child_lock_switch": {
|
||||
"name": "Child lock"
|
||||
},
|
||||
"backlight_switch": {
|
||||
"name": "Backlight"
|
||||
},
|
||||
"backlight_bottom_switch": {
|
||||
"name": "Bottom backlight"
|
||||
},
|
||||
"ioniser_switch": {
|
||||
"name": "Ioniser"
|
||||
},
|
||||
"ozonation_switch": {
|
||||
"name": "Ozonation"
|
||||
},
|
||||
"warm_stream_switch": {
|
||||
"name": "Warm stream"
|
||||
},
|
||||
"keepwarm_switch": {
|
||||
"name": "Keep warm"
|
||||
},
|
||||
"ultraviolet_switch": {
|
||||
"name": "Ultraviolet"
|
||||
},
|
||||
"smart_mode": {
|
||||
"name": "Smart"
|
||||
},
|
||||
"bss_mode": {
|
||||
"name": "BSS"
|
||||
},
|
||||
"smart_mode_switch": {
|
||||
"name": "Массаж"
|
||||
},
|
||||
"damper_switch": {
|
||||
"name": "Recycling"
|
||||
},
|
||||
"damper_heater": {
|
||||
"name": "Detecting open window"
|
||||
},
|
||||
"display_off_heater": {
|
||||
"name": "Auto off display"
|
||||
},
|
||||
"half_power_heater": {
|
||||
"name": "Half power"
|
||||
},
|
||||
"backlight_bright": {
|
||||
"name": "Bright 50/100"
|
||||
},
|
||||
"turbo_switch": {
|
||||
"name": "Turbo mode"
|
||||
},
|
||||
"night_switch": {
|
||||
"name": "Night mode"
|
||||
},
|
||||
"night_light_switch": {
|
||||
"name": "Night light"
|
||||
},
|
||||
"self_cleaning": {
|
||||
"name": "Self cleaning"
|
||||
},
|
||||
"delicate_blowing": {
|
||||
"name": "Delicate blowing"
|
||||
},
|
||||
"eco_mode_switch": {
|
||||
"name": "Eco mode"
|
||||
},
|
||||
"auto_heater_switch": {
|
||||
"name": "Auto heating"
|
||||
},
|
||||
"quiet_mode": {
|
||||
"name": "Quiet mode"
|
||||
},
|
||||
"no_frost": {
|
||||
"name": "No frost"
|
||||
},
|
||||
"anti_fingus_switch": {
|
||||
"name": "Anti fingus"
|
||||
}
|
||||
},
|
||||
"water_heater": {
|
||||
"water_heater": {
|
||||
"name": "Water heater",
|
||||
"state": {
|
||||
"off": "Off",
|
||||
"performance": "Boiling",
|
||||
"high_demand": "Keep with warm up",
|
||||
"electric": "Warm up",
|
||||
"heat_pump": "Warm up with keep",
|
||||
"eco": "IQ boiling",
|
||||
"gas": "Tea Time"
|
||||
}
|
||||
},
|
||||
"water_boiler": {
|
||||
"name": "Boiler",
|
||||
"state": {
|
||||
"off": "Off",
|
||||
"performance": "Low",
|
||||
"electric": "Mid",
|
||||
"heat_pump": "Turbo",
|
||||
"eco": "Eco"
|
||||
}
|
||||
}
|
||||
},
|
||||
"humidifier": {
|
||||
"humidifier": {
|
||||
"name": "Humidifier",
|
||||
"state_attributes": {
|
||||
"my_available_modes": {
|
||||
"state": {
|
||||
"auto": "Auto",
|
||||
"comfort": "Health",
|
||||
"baby": "Baby mode",
|
||||
"sleep": "Night",
|
||||
"boost": "Intensity",
|
||||
"home": "Custom",
|
||||
"eco": "Humidity",
|
||||
"fitnes": "Fitnes",
|
||||
"yoga": "Yoga",
|
||||
"meditation": "Meditation",
|
||||
"prana_hand": "Prana hand",
|
||||
"prana_auto": "Prana auto",
|
||||
"aroma": "Aroma"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"number": {
|
||||
"intensity": {
|
||||
"name": "Intensity"
|
||||
},
|
||||
"evaporation_rate": {
|
||||
"name": "Evaporation rate"
|
||||
},
|
||||
"set_temperature": {
|
||||
"name": "Set temperature"
|
||||
},
|
||||
"amount": {
|
||||
"name": "Amount"
|
||||
},
|
||||
"weight": {
|
||||
"name": "Weight"
|
||||
},
|
||||
"tank": {
|
||||
"name": "Water tank"
|
||||
},
|
||||
"pressure": {
|
||||
"name": "Pressure"
|
||||
},
|
||||
"speed": {
|
||||
"name": "Speed"
|
||||
},
|
||||
"temperature": {
|
||||
"name": "Temperature"
|
||||
},
|
||||
"display_time": {
|
||||
"name": "Display time"
|
||||
},
|
||||
"time_timer": {
|
||||
"name": "Timer"
|
||||
},
|
||||
"speed_irrigator": {
|
||||
"name": "Speed irrigator"
|
||||
},
|
||||
"temperature_difference_eco": {
|
||||
"name": "Temperature difference eco"
|
||||
},
|
||||
"temperature_difference_antifrost": {
|
||||
"name": "Temperature difference antifrost"
|
||||
},
|
||||
"bright_backlight": {
|
||||
"name": "Bright backlight"
|
||||
},
|
||||
"power_cable": {
|
||||
"name": "Power cable"
|
||||
}
|
||||
},
|
||||
"sensor": {
|
||||
"temperature_sensor": {
|
||||
"name": "Temperature"
|
||||
},
|
||||
"firmware_sensor": {
|
||||
"name": "Firmware Version"
|
||||
},
|
||||
"type_sensor": {
|
||||
"name": "Device Type"
|
||||
},
|
||||
"humidity_sensor": {
|
||||
"name": "Humidity"
|
||||
},
|
||||
"time_to_end_sensor": {
|
||||
"name": "Time to end"
|
||||
},
|
||||
"time_to_end_sensor_turbo": {
|
||||
"name": "Time to end Turbo"
|
||||
},
|
||||
"quality": {
|
||||
"name": "Качество чистки"
|
||||
},
|
||||
"power_consume": {
|
||||
"name": "Power consume"
|
||||
},
|
||||
"error": {
|
||||
"name": "Error",
|
||||
"state": {
|
||||
"no_error": "No",
|
||||
"low_water": "Low water",
|
||||
"kettle_out_of_base": "Kettle is out of base station",
|
||||
"temperature_sensor_failure": "Temperature sensor failure",
|
||||
"child_lock": "Child lock operated",
|
||||
"recommended_to_change_water": "It is recommended to change the water in the kettle",
|
||||
"changed_water_for_long_time": "You probably haven't changed water for a long time. It is desirable to boil it",
|
||||
"replace_filter": "It is recommended to replace the filter",
|
||||
"maximum_schedules": "Maximum number of schedules 4",
|
||||
"clean_tank": "Clean the tank",
|
||||
"cup_not_present": "Cup is not present",
|
||||
"gesture_sensor_error": "Gesture sensor error",
|
||||
"side_door_open": "Side door open",
|
||||
"waste_container_not_installed": "Waste container not installed",
|
||||
"drip_tray_not_installed": "Drip tray not installed",
|
||||
"the_brewing_unit_not_installed": "The brewing unit isn't installed",
|
||||
"missing_water_tank": "Missing water tank",
|
||||
"waste_container_full": "Waste container is full",
|
||||
"not_enough_coffee_beans": "Not enough coffee beans",
|
||||
"water_supply_blocked": "Water supply is blocked",
|
||||
"code_e001": "The coffee machine is faulty (code E001) Contact service center",
|
||||
"code_e002": "The coffee machine is faulty (code E002) Contact service center",
|
||||
"code_e003": "The coffee machine is faulty (code E003) Contact service center",
|
||||
"code_e004": "The coffee machine is faulty (code E004) Contact service center",
|
||||
"code_e005": "The coffee machine is faulty (code E005) Contact service center",
|
||||
"decalcification_required": "Decalcification required",
|
||||
"water_changed_for_long_time": "Water in the tank hasn't been changed for a long time. It's recommended to change the water",
|
||||
"cleaning_milk_system": "Cleaning the milk system",
|
||||
"cleaning_brewing_system": "Cleaning the brewing system",
|
||||
"decalcification_progress": "Decalcification in progress",
|
||||
"cleaning_hydraulic_system": "Cleaning the hydraulic system",
|
||||
"check_water_tank": "Сheck the water tank",
|
||||
"cappuccinator_false": "Cappuccinator false",
|
||||
"nothing_is_selected": "Nothing is selected"
|
||||
}
|
||||
},
|
||||
"filter_retain": {
|
||||
"name": "Filter retain"
|
||||
},
|
||||
"pre_filter_retain": {
|
||||
"name": "Pre-filter retain"
|
||||
},
|
||||
"clean_retain": {
|
||||
"name": "Clean retain"
|
||||
},
|
||||
"anode_retain": {
|
||||
"name": "Anode retain"
|
||||
},
|
||||
"mode_sensor": {
|
||||
"name": "Mode",
|
||||
"state": {
|
||||
"off": "Off",
|
||||
"espresso": "Espresso",
|
||||
"ristretto": "Ristretto",
|
||||
"long_espresso": "Long espresso",
|
||||
"americano": "Americano",
|
||||
"heating": "Heating",
|
||||
"cappuccino": "Cappuccino",
|
||||
"latte": "Latte",
|
||||
"flat_white": "Flat white",
|
||||
"cortado": "Cortado",
|
||||
"double_espresso": "Double espresso",
|
||||
"double_cappuccino": "Double cappuccino",
|
||||
"double_latte": "Double latte",
|
||||
"double_long_espresso": "Double long espresso",
|
||||
"double_macchiato": "Double macchiato",
|
||||
"milk_coffee": "Milk coffee",
|
||||
"macchiato": "Macchiato",
|
||||
"latte_macchiato": "Latte macchiato",
|
||||
"hot_water": "Hot water",
|
||||
"hot_milk_foam": "Hot milk foam",
|
||||
"hot_milk": "Hot milk"
|
||||
}
|
||||
},
|
||||
"power_state": {
|
||||
"name": "Power",
|
||||
"state": {
|
||||
"power_on": "On",
|
||||
"power_off": "Off",
|
||||
"turns_on": "Turns on",
|
||||
"turns_off": "Turns off"
|
||||
}
|
||||
},
|
||||
"current_power": {
|
||||
"name": "Current power"
|
||||
},
|
||||
"outdoor_unit_temperature": {
|
||||
"name": "Temperature outdoor unit"
|
||||
}
|
||||
},
|
||||
"select": {
|
||||
"select_mode_kettle": {
|
||||
"name": "Preset",
|
||||
"state": {
|
||||
"not_selected": "Not selected",
|
||||
"black_tea": "Black tea",
|
||||
"baby_bottle": "Baby bottle",
|
||||
"instant_coffee": "Instant coffee",
|
||||
"green_tea": "Green tea",
|
||||
"flower_tea": "Flower tea",
|
||||
"tea_bag": "Tea bag",
|
||||
"red_tea": "Red tea",
|
||||
"puerh_tea": "Puerh tea",
|
||||
"oolong_tea": "Oolong tea",
|
||||
"white_tea": "White tea",
|
||||
"herbal_tea": "Herbal tea"
|
||||
}
|
||||
},
|
||||
"select_mode_cooker": {
|
||||
"name": "Recipes",
|
||||
"state": {
|
||||
"my_recipe_plus": "My recipe plus",
|
||||
"reheat": "Reheat",
|
||||
"cake": "Cake",
|
||||
"soaked_rice": "Soaked rice",
|
||||
"stew": "Stew",
|
||||
"fry": "Fry",
|
||||
"pilaf": "Pilaf",
|
||||
"yogurt": "Yogurt",
|
||||
"oatmeal": "Catmeal",
|
||||
"milk_porridge": "Milk porridge",
|
||||
"soup": "Soup",
|
||||
"meat": "Meat",
|
||||
"cottage_cheese": "Cottage cheese"
|
||||
}
|
||||
},
|
||||
"select_mode_cofeemaker": {
|
||||
"name": "Напиток",
|
||||
"state": {
|
||||
"not_selected": "Not selected",
|
||||
"espresso": "Espresso",
|
||||
"ristretto": "Ristretto",
|
||||
"long_espresso": "Long espresso",
|
||||
"americano": "Americano",
|
||||
"cappuccino": "Cappuccino",
|
||||
"latte": "Latte",
|
||||
"flat_white": "Flat white",
|
||||
"cortado": "Cortado",
|
||||
"double_espresso": "Double espresso",
|
||||
"double_cappuccino": "Double cappuccino",
|
||||
"double_latte": "Double latte",
|
||||
"double_long_espresso": "Double long espresso",
|
||||
"double_macchiato": "Double macchiato",
|
||||
"milk_coffee": "Milk coffee",
|
||||
"macchiato": "Macchiato",
|
||||
"latte_macchiato": "Latte macchiato",
|
||||
"hot_water": "Hot water",
|
||||
"hot_milk_foam": "Hot milk foam",
|
||||
"hot_milk": "Hot milk",
|
||||
"doppio": "Doppio",
|
||||
"lungo": "Lungo",
|
||||
"clearing": "Clearing",
|
||||
"heating": "Heating"
|
||||
}
|
||||
},
|
||||
"select_melody": {
|
||||
"name": "Melody",
|
||||
"state": {
|
||||
"mute": "Without sound",
|
||||
"rainstorm": "Rainstorm",
|
||||
"surf": "Surf",
|
||||
"forest": "In the forest",
|
||||
"birdsong": "Birdsong",
|
||||
"bonfire": "Bonfire"
|
||||
}
|
||||
},
|
||||
"select_irrigator": {
|
||||
"name": "Personal modes",
|
||||
"state": {
|
||||
"preset1": "Mode 1",
|
||||
"preset2": "Mode 2",
|
||||
"preset3": "Mode 3"
|
||||
}
|
||||
},
|
||||
"select_night_backlight": {
|
||||
"name": "Night backlight",
|
||||
"state": {
|
||||
"off": "Off",
|
||||
"all_on": "All on",
|
||||
"high_on": "Hight on",
|
||||
"mid_on": "Mid on",
|
||||
"low_on": "Low on"
|
||||
}
|
||||
},
|
||||
"select_swing_horizontal": {
|
||||
"name": "Swing horizontal",
|
||||
"state": {
|
||||
"off": "Swing",
|
||||
"top": "Top",
|
||||
"high": "High",
|
||||
"middle": "Middle",
|
||||
"low": "Low",
|
||||
"bottom": "Bottom"
|
||||
}
|
||||
},
|
||||
"select_swing_vertical": {
|
||||
"name": "Swing vertical",
|
||||
"state": {
|
||||
"off": "Swing",
|
||||
"left": "Left",
|
||||
"center-left": "Center-left",
|
||||
"center": "Center",
|
||||
"center-right": "Center-right",
|
||||
"right": "Right"
|
||||
}
|
||||
}
|
||||
},
|
||||
"light": {
|
||||
"night_light": {
|
||||
"name": "Night light"
|
||||
},
|
||||
"night_light_up": {
|
||||
"name": "Top backlight"
|
||||
},
|
||||
"night_light_down": {
|
||||
"name": "Bottom backlight"
|
||||
}
|
||||
},
|
||||
"binary_sensor": {
|
||||
"base_binary_sensor": {
|
||||
"name": "Position",
|
||||
"state": {
|
||||
"on": "Not on the base",
|
||||
"off": "On the base"
|
||||
}
|
||||
},
|
||||
"lid_binary_sensor": {
|
||||
"name": "Lid",
|
||||
"state": {
|
||||
"on": "Open",
|
||||
"off": "Close"
|
||||
}
|
||||
},
|
||||
"water_tank_binary_sensor": {
|
||||
"name": "Tank is removed",
|
||||
"state": {
|
||||
"on": "Yes",
|
||||
"off": "No"
|
||||
}
|
||||
},
|
||||
"cappuccinator_binary_sensor": {
|
||||
"name": "Cappuccinator",
|
||||
"state": {
|
||||
"on": "Installed",
|
||||
"off": "Not installed"
|
||||
}
|
||||
},
|
||||
"heating_binary_sensor": {
|
||||
"name": "Heating",
|
||||
"state": {
|
||||
"on": "Heats",
|
||||
"off": "Not heat"
|
||||
}
|
||||
},
|
||||
"available_binary_sensor": {
|
||||
"name": "LAN",
|
||||
"state": {
|
||||
"on": "Online",
|
||||
"off": "Offline"
|
||||
}
|
||||
}
|
||||
},
|
||||
"time": {
|
||||
"delay_start": {
|
||||
"name": "Delay start"
|
||||
},
|
||||
"cooking_time": {
|
||||
"name": "Cooking time"
|
||||
}
|
||||
},
|
||||
"button": {
|
||||
"button_stop": {
|
||||
"name": "Stop"
|
||||
},
|
||||
"button_start": {
|
||||
"name": "Start"
|
||||
},
|
||||
"button_stop_coffee": {
|
||||
"name": "Stop"
|
||||
},
|
||||
"button_start_coffee": {
|
||||
"name": "Start"
|
||||
},
|
||||
"button_reset_filter": {
|
||||
"name": "Reset time filter"
|
||||
},
|
||||
"button_reset_prefilter": {
|
||||
"name": "Reset time pre-filter"
|
||||
},
|
||||
"button_reset_tank": {
|
||||
"name": "Reset time water tank"
|
||||
}
|
||||
},
|
||||
"climate": {
|
||||
"climate": {
|
||||
"name": "Climate",
|
||||
"state_attributes": {
|
||||
"fan_mode": {
|
||||
"state": {
|
||||
"1_speed": "1 speed",
|
||||
"2_speed": "2 speed",
|
||||
"3_speed": "3 speed",
|
||||
"4_speed": "4 speed",
|
||||
"5_speed": "5 speed",
|
||||
"6_speed": "6 speed",
|
||||
"7_speed": "7 speed",
|
||||
"8_speed": "8 speed",
|
||||
"9_speed": "9 speed"
|
||||
}
|
||||
},
|
||||
"preset_mode": {
|
||||
"state": {
|
||||
"hands": "Hands",
|
||||
"auto": "Auto",
|
||||
"night": "Night",
|
||||
"turbo": "Turbo",
|
||||
"passive": "Passive"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"heater": {
|
||||
"name": "Heater",
|
||||
"state_attributes": {
|
||||
"fan_mode": {
|
||||
"name": "Heating power",
|
||||
"state": {
|
||||
"10_percent": "10 %",
|
||||
"20_percent": "20 %",
|
||||
"30_percent": "30 %",
|
||||
"40_percent": "40 %",
|
||||
"50_percent": "50 %",
|
||||
"60_percent": "60 %",
|
||||
"70_percent": "70 %",
|
||||
"80_percent": "80 %",
|
||||
"90_percent": "90 %",
|
||||
"100_percent": "100 %",
|
||||
"20_5_percent": "20 %",
|
||||
"40_5_percent": "40 %",
|
||||
"60_5_percent": "60 %",
|
||||
"80_5_percent": "80 %",
|
||||
"100_5_percent": "100 %"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"aircleaner": {
|
||||
"name": "Air cleaner",
|
||||
"state": {
|
||||
"dry": "Сlearing"
|
||||
},
|
||||
"state_attributes": {
|
||||
"preset_mode": {
|
||||
"state": {
|
||||
"hands": "Hands",
|
||||
"auto": "Auto",
|
||||
"night": "Night"
|
||||
}
|
||||
},
|
||||
"fan_mode": {
|
||||
"state": {
|
||||
"top": "Turbo"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"conditioner": {
|
||||
"name": "Conditioner",
|
||||
"state_attributes": {
|
||||
"fan_mode": {
|
||||
"state": {
|
||||
"min": "Max",
|
||||
"max": "Min"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"thermostat": {
|
||||
"name": "Thermostat",
|
||||
"state_attributes": {
|
||||
"preset_mode": {
|
||||
"state": {
|
||||
"eco": "Eco",
|
||||
"comfort": "Comfort",
|
||||
"turbo": "Turbo",
|
||||
"antifrost": "Antifrost",
|
||||
"schedule": "Schedule",
|
||||
"vacation": "Vacation",
|
||||
"manual": "Manual"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"common": {
|
||||
"all": "All devices",
|
||||
"kettle": "Kettle",
|
||||
"humidifier": "Humidifier",
|
||||
"cooker": "Cooker",
|
||||
"coffeemaker": "Coffeemaker",
|
||||
"air_cleaner": "Air cleaner",
|
||||
"irrigator": "Irrigator",
|
||||
"air_fryer": "Air Fryer",
|
||||
"boiler": "Boiler",
|
||||
"heater": "Heater",
|
||||
"cleaner": "Cleaner",
|
||||
"blender": "Blender",
|
||||
"cooktop": "Cooktop",
|
||||
"cordless_cleaner": "Cordless cleaner",
|
||||
"fan": "Fan",
|
||||
"grill": "Grill",
|
||||
"hair_care": "Hair care",
|
||||
"hood": "Hood",
|
||||
"iron": "Iron",
|
||||
"kitchen_machine": "Kitchen machine",
|
||||
"meat_grinder": "Meat grinder",
|
||||
"other": "Smart Lid",
|
||||
"oven": "Oven",
|
||||
"steamer": "Steamer",
|
||||
"toothbrush": "Toothbrush",
|
||||
"air_conditioner": "Conditioner",
|
||||
"thermostat": "Thermostat"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,669 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Это устройство уже было настроено.",
|
||||
"not_supported": "Ошибка. Не выбран тип устройства."
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "Не удалось подключиться, пожалуйста, повторите попытку.",
|
||||
"invalid_auth": "Неверная аутентификация.",
|
||||
"too_many_requests": "Слишком много запросов, повторите попытку позже.",
|
||||
"unknown": "Неожиданная ошибка.",
|
||||
"Unknown error occurred": "Неожиданная ошибка."
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"description": "Конфигурация Polaris Local MQTT.",
|
||||
"data": {
|
||||
"DEVICEID": "Выберите устройство",
|
||||
"MQTT_ROOT_TOPIC": "Префикс темы (обычно 'polaris')"
|
||||
},
|
||||
"title": "Polaris Local MQTT"
|
||||
},
|
||||
"undef": {
|
||||
"description": "Конфигурация устройства Polaris.",
|
||||
"data": {
|
||||
"DEVICETYPE": "Выберите тип устройства"
|
||||
},
|
||||
"title": "Polaris Local MQTT"
|
||||
}
|
||||
}
|
||||
},
|
||||
"entity": {
|
||||
"switch": {
|
||||
"sound_switch": {
|
||||
"name": "Звук"
|
||||
},
|
||||
"power_switch": {
|
||||
"name": "Включить"
|
||||
},
|
||||
"child_lock_switch": {
|
||||
"name": "Блокировка"
|
||||
},
|
||||
"backlight_switch": {
|
||||
"name": "Подсветка"
|
||||
},
|
||||
"backlight_bottom_switch": {
|
||||
"name": "Нижняя подсветка"
|
||||
},
|
||||
"ioniser_switch": {
|
||||
"name": "Ионизация"
|
||||
},
|
||||
"ozonation_switch": {
|
||||
"name": "Озонирование"
|
||||
},
|
||||
"warm_stream_switch": {
|
||||
"name": "Теплый пар"
|
||||
},
|
||||
"keepwarm_switch": {
|
||||
"name": "Поддержание температуры"
|
||||
},
|
||||
"ultraviolet_switch": {
|
||||
"name": "Ультрафиолет"
|
||||
},
|
||||
"smart_mode": {
|
||||
"name": "Умный режим"
|
||||
},
|
||||
"bss_mode": {
|
||||
"name": "Антибактериальная очистка"
|
||||
},
|
||||
"smart_mode_switch": {
|
||||
"name": "Массаж"
|
||||
},
|
||||
"damper_switch": {
|
||||
"name": "Рециркуляция"
|
||||
},
|
||||
"damper_heater": {
|
||||
"name": "Обнаружение открытого окна"
|
||||
},
|
||||
"display_off_heater": {
|
||||
"name": "Автоотключение дисплея"
|
||||
},
|
||||
"half_power_heater": {
|
||||
"name": "Половина мощности"
|
||||
},
|
||||
"backlight_bright": {
|
||||
"name": "Яркость 50/100"
|
||||
},
|
||||
"turbo_switch": {
|
||||
"name": "Турбо режим"
|
||||
},
|
||||
"night_switch": {
|
||||
"name": "Ночной режим"
|
||||
},
|
||||
"night_light_switch": {
|
||||
"name": "Ночная подсветка"
|
||||
},
|
||||
"self_cleaning": {
|
||||
"name": "Самоочистка"
|
||||
},
|
||||
"delicate_blowing": {
|
||||
"name": "Деликатный обдув"
|
||||
},
|
||||
"eco_mode_switch": {
|
||||
"name": "Экономичный режим"
|
||||
},
|
||||
"auto_heater_switch": {
|
||||
"name": "Автообогрев"
|
||||
},
|
||||
"quiet_mode": {
|
||||
"name": "Тихий режим"
|
||||
},
|
||||
"no_frost": {
|
||||
"name": "Антизамерзание"
|
||||
},
|
||||
"anti_fingus_switch": {
|
||||
"name": "Профилактика грибка"
|
||||
}
|
||||
},
|
||||
"water_heater": {
|
||||
"water_heater": {
|
||||
"name": "Нагрев",
|
||||
"state": {
|
||||
"off": "Выключен",
|
||||
"performance": "Кипячение",
|
||||
"high_demand": "Кипячение с удержанием",
|
||||
"electric": "Разогрев",
|
||||
"heat_pump": "Разогрев с удержанием",
|
||||
"eco": "IQ Кипячение",
|
||||
"gas": "Чайная церемония"
|
||||
}
|
||||
},
|
||||
"water_boiler": {
|
||||
"name": "Бойлер",
|
||||
"state": {
|
||||
"off": "Выключен",
|
||||
"performance": "Низкий",
|
||||
"electric": "Средний",
|
||||
"heat_pump": "Высокий",
|
||||
"eco": "Экономичный"
|
||||
}
|
||||
}
|
||||
},
|
||||
"humidifier": {
|
||||
"humidifier": {
|
||||
"name": "Увлажнитель",
|
||||
"state_attributes": {
|
||||
"mode": {
|
||||
"state": {
|
||||
"auto": "Авто",
|
||||
"comfort": "Здоровье",
|
||||
"baby": "Детский",
|
||||
"sleep": "Ночной",
|
||||
"boost": "Интенсивность",
|
||||
"home": "Ручной",
|
||||
"eco": "Увлажнение",
|
||||
"fitnes": "Фитнес",
|
||||
"yoga": "Йога",
|
||||
"meditation": "Медитация",
|
||||
"prana_hand": "Прана ручной",
|
||||
"prana_auto": "Прана авто",
|
||||
"aroma": "Арома"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"number": {
|
||||
"intensity": {
|
||||
"name": "Интенсивность"
|
||||
},
|
||||
"evaporation_rate": {
|
||||
"name": "Скорость испарения"
|
||||
},
|
||||
"set_temperature": {
|
||||
"name": "Установка температуры"
|
||||
},
|
||||
"amount": {
|
||||
"name": "Объём кофе"
|
||||
},
|
||||
"weight": {
|
||||
"name": "Крепкость напитка"
|
||||
},
|
||||
"tank": {
|
||||
"name": "Объём напитка"
|
||||
},
|
||||
"pressure": {
|
||||
"name": "Объём пенки"
|
||||
},
|
||||
"speed": {
|
||||
"name": "Объём молока"
|
||||
},
|
||||
"temperature": {
|
||||
"name": "Температура напитка"
|
||||
},
|
||||
"display_time": {
|
||||
"name": "Отключение дисплея"
|
||||
},
|
||||
"time_timer": {
|
||||
"name": "Таймер отключения"
|
||||
},
|
||||
"speed_irrigator": {
|
||||
"name": "Скорость"
|
||||
},
|
||||
"temperature_difference_eco": {
|
||||
"name": "Разница температур в режиме ECO"
|
||||
},
|
||||
"temperature_difference_antifrost": {
|
||||
"name": "Разница температур в режиме Anti frost"
|
||||
},
|
||||
"bright_backlight": {
|
||||
"name": "Яркость подсветки"
|
||||
},
|
||||
"power_cable": {
|
||||
"name": "Мощность кабеля"
|
||||
}
|
||||
},
|
||||
"sensor": {
|
||||
"temperature_sensor": {
|
||||
"name": "Температура"
|
||||
},
|
||||
"firmware_sensor": {
|
||||
"name": "Версия прошивки"
|
||||
},
|
||||
"type_sensor": {
|
||||
"name": "Тип устройства"
|
||||
},
|
||||
"humidity_sensor": {
|
||||
"name": "Влажность"
|
||||
},
|
||||
"time_to_end_sensor": {
|
||||
"name": "Оставшееся время"
|
||||
},
|
||||
"time_to_end_sensor_turbo": {
|
||||
"name": "Оставшееся время Турбо"
|
||||
},
|
||||
"quality": {
|
||||
"name": "Качество чистки"
|
||||
},
|
||||
"power_consume": {
|
||||
"name": "Потребление энергии"
|
||||
},
|
||||
"error": {
|
||||
"name": "Ошибка",
|
||||
"state": {
|
||||
"no_error": "Нет",
|
||||
"low_water": "Мало воды",
|
||||
"kettle_out_of_base": "Чайник снят с базы",
|
||||
"temperature_sensor_failure": "Ошибка термодатчика",
|
||||
"child_lock": "Сработала защита от случайного нажатия",
|
||||
"recommended_to_change_water": "Рекомендуется сменить воду в чайнике",
|
||||
"changed_water_for_long_time": "Вероятно, вы давно не меняли воду. Ее желательно прокипятить",
|
||||
"replace_filter": "Рекомендуется заменить фильтр",
|
||||
"maximum_schedules": "Максимальное количество расписаний 4",
|
||||
"clean_tank": "Почистите бак",
|
||||
"cup_not_present": "Чаша не установлена",
|
||||
"gesture_sensor_error": "Ошибка датчика жестов",
|
||||
"side_door_open": "Открыта боковая дверца",
|
||||
"waste_container_not_installed": "Контейнер для отходов не установлен",
|
||||
"drip_tray_not_installed": "Каплесборник не установлен",
|
||||
"the_brewing_unit_not_installed": "Заварочный узел не установлен",
|
||||
"missing_water_tank": "Отсутствует резервуар для воды",
|
||||
"waste_container_full": "Контейнер для отходов полон",
|
||||
"not_enough_coffee_beans": "Недостаточно кофейных зерен",
|
||||
"water_supply_blocked": "Подача воды заблокирована",
|
||||
"code_e001": "Кофемашина неисправна (код Е001) Обратитесь в сервисный центр",
|
||||
"code_e002": "Кофемашина неисправна (код Е002) Обратитесь в сервисный центр",
|
||||
"code_e003": "Кофемашина неисправна (код Е003) Обратитесь в сервисный центр",
|
||||
"code_e004": "Кофемашина неисправна (код Е004) Обратитесь в сервисный центр",
|
||||
"code_e005": "Кофемашина неисправна (код Е005) Обратитесь в сервисный центр",
|
||||
"decalcification_required": "Необходима декальцинация",
|
||||
"water_changed_for_long_time": "Вода в резервуаре давно не менялась, рекомендуем сменить воду",
|
||||
"cleaning_milk_system": "Очистка молочной системы",
|
||||
"cleaning_brewing_system": "Очистка заварочной системы",
|
||||
"decalcification_progress": "Идет декальцинация",
|
||||
"cleaning_hydraulic_system": "Очистка гидросистемы",
|
||||
"check_water_tank": "Проверьте бак с водой",
|
||||
"cappuccinator_false": "Капучинатор не установлен",
|
||||
"nothing_is_selected": "Не выбран напиток"
|
||||
}
|
||||
},
|
||||
"filter_retain": {
|
||||
"name": "Остаток фильтра"
|
||||
},
|
||||
"pre_filter_retain": {
|
||||
"name": "Остаток предфильтра"
|
||||
},
|
||||
"clean_retain": {
|
||||
"name": "Остаток до очистки бака"
|
||||
},
|
||||
"anode_retain": {
|
||||
"name": "Остаток до замены анода"
|
||||
},
|
||||
"mode_sensor": {
|
||||
"name": "Режим работы",
|
||||
"state": {
|
||||
"off": "Выключен",
|
||||
"espresso": "Эспрессо",
|
||||
"ristretto": "Ристретто",
|
||||
"long_espresso": "Лунго",
|
||||
"americano": "Американо",
|
||||
"heating": "Нагрев",
|
||||
"cappuccino": "Капучино",
|
||||
"latte": "Латте",
|
||||
"flat_white": "Флэт уайт",
|
||||
"cortado": "Кортадо",
|
||||
"double_espresso": "Двойной эспрессо",
|
||||
"double_cappuccino": "Двойной капучино",
|
||||
"double_latte": "Двойной латте",
|
||||
"double_long_espresso": "Двойной лунго",
|
||||
"double_macchiato": "Двойной макиато",
|
||||
"milk_coffee": "Кофе с молоком",
|
||||
"macchiato": "Макиато",
|
||||
"latte_macchiato": "Латте макиато",
|
||||
"hot_water": "Горячая вода",
|
||||
"hot_milk foam": "Молочная пена",
|
||||
"hot_milk": "Горячее молоко"
|
||||
}
|
||||
},
|
||||
"power_state": {
|
||||
"name": "Питание",
|
||||
"state": {
|
||||
"power_on": "Включено",
|
||||
"power_off": "Выключено",
|
||||
"turns_on": "Включается",
|
||||
"turns_off": "Выключается"
|
||||
}
|
||||
},
|
||||
"сurrent_power": {
|
||||
"name": "Текущая мощность"
|
||||
},
|
||||
"outdoor_unit_temperature": {
|
||||
"name": "Температура внешнего блока"
|
||||
}
|
||||
},
|
||||
"select": {
|
||||
"select_mode_kettle": {
|
||||
"name": "Предустановки",
|
||||
"state": {
|
||||
"not_selected": "Не выбрано",
|
||||
"black_tea": "Черный чай",
|
||||
"baby_bottle": "Детская смесь",
|
||||
"instant_coffee": "Растворимый кофе",
|
||||
"green_tea": "Зеленый чай",
|
||||
"flower_tea": "Цветочный чай",
|
||||
"tea_bag": "Пакетированный чай",
|
||||
"red_tea": "Красный чай",
|
||||
"puerh_tea": "Пуэр",
|
||||
"oolong_tea": "Улун",
|
||||
"white_tea": "Белый чай",
|
||||
"herbal_tea": "Травяной чай"
|
||||
}
|
||||
},
|
||||
"select_mode_cooker": {
|
||||
"name": "Рецепты",
|
||||
"state": {
|
||||
"my_recipe_plus": "Мой рецепт +",
|
||||
"reheat": "Разогрев",
|
||||
"cake": "Выпечка",
|
||||
"soaked_rice": "Крупа",
|
||||
"stew": "Тушение",
|
||||
"fry": "Жарка",
|
||||
"pilaf": "Плов",
|
||||
"yogurt": "Йогурт",
|
||||
"oatmeal": "Овсянка",
|
||||
"milk_porridge": "Молочная каша",
|
||||
"soup": "Суп",
|
||||
"meat": "Холодец",
|
||||
"cottage_cheese": "Творог"
|
||||
}
|
||||
},
|
||||
"select_mode_cofeemaker": {
|
||||
"name": "Напиток",
|
||||
"state": {
|
||||
"not_selected": "Не выбрано",
|
||||
"espresso": "Эспрессо",
|
||||
"ristretto": "Ристретто",
|
||||
"long_espresso": "Лунго",
|
||||
"americano": "Американо",
|
||||
"cappuccino": "Капучино",
|
||||
"latte": "Латте",
|
||||
"flat_white": "Флэт уайт",
|
||||
"cortado": "Кортадо",
|
||||
"double_espresso": "Двойной эспрессо",
|
||||
"double_cappuccino": "Двойной капучино",
|
||||
"double_latte": "Двойной латте",
|
||||
"double_long_espresso": "Двойной лунго",
|
||||
"double_macchiato": "Двойной макиато",
|
||||
"milk_coffee": "Кофе с молоком",
|
||||
"macchiato": "Макиато",
|
||||
"latte_macchiato": "Латте макиато",
|
||||
"hot_water": "Горячая вода",
|
||||
"hot_milk_foam": "Молочная пена",
|
||||
"hot_milk": "Горячее молоко",
|
||||
"doppio": "Доппио",
|
||||
"lungo": "Лунго",
|
||||
"clearing": "Очистка",
|
||||
"heating": "Подогрев"
|
||||
}
|
||||
},
|
||||
"select_melody": {
|
||||
"name": "Мелодия",
|
||||
"state": {
|
||||
"mute": "Без звука",
|
||||
"rainstorm": "Ливень",
|
||||
"surf": "Прибой",
|
||||
"forest": "В лесу",
|
||||
"birdsong": "Пение птиц",
|
||||
"bonfire": "Костер"
|
||||
}
|
||||
},
|
||||
"select_irrigator": {
|
||||
"name": "Персональные режимы",
|
||||
"state": {
|
||||
"preset1": "Режим 1",
|
||||
"preset2": "Режим 2",
|
||||
"preset3": "Режим 3"
|
||||
}
|
||||
},
|
||||
"select_night_backlight": {
|
||||
"name": "Ночная подсветка",
|
||||
"state": {
|
||||
"off": "Выключена",
|
||||
"all_on": "Весь свет включен",
|
||||
"high_on": "Верхний свет включен",
|
||||
"mid_on": "Средний свет включен",
|
||||
"low_on": "Нижний свет включен"
|
||||
}
|
||||
},
|
||||
"select_swing_horizontal": {
|
||||
"name": "Вертикальный обдув",
|
||||
"state": {
|
||||
"off": "Качание",
|
||||
"top": "Вверх",
|
||||
"high": "Выше среднего",
|
||||
"middle": "Среднее",
|
||||
"low": "Ниже среднего",
|
||||
"bottom": "Вниз"
|
||||
}
|
||||
},
|
||||
"select_swing_vertical": {
|
||||
"name": "Горизонтальный обдув",
|
||||
"state": {
|
||||
"off": "Качание",
|
||||
"left": "Влево",
|
||||
"center-left": "Левее центра",
|
||||
"center": "Центр",
|
||||
"center-right": "Правее центра",
|
||||
"right": "Вправо"
|
||||
}
|
||||
}
|
||||
},
|
||||
"light": {
|
||||
"night_light": {
|
||||
"name": "Ночник"
|
||||
},
|
||||
"night_light_up": {
|
||||
"name": "Верхняя подсветка"
|
||||
},
|
||||
"night_light_down": {
|
||||
"name": "Нижняя подсветка"
|
||||
}
|
||||
},
|
||||
"binary_sensor": {
|
||||
"base_binary_sensor": {
|
||||
"name": "Положение",
|
||||
"state": {
|
||||
"on": "Снят с базы",
|
||||
"off": "На базе"
|
||||
}
|
||||
},
|
||||
"lid_binary_sensor": {
|
||||
"name": "Крышка",
|
||||
"state": {
|
||||
"on": "Открыта",
|
||||
"off": "Закрыта"
|
||||
}
|
||||
},
|
||||
"water_tank_binary_sensor": {
|
||||
"name": "Бак снят",
|
||||
"state": {
|
||||
"on": "Да",
|
||||
"off": "Нет"
|
||||
}
|
||||
},
|
||||
"cappuccinator_binary_sensor": {
|
||||
"name": "Капучинатор",
|
||||
"state": {
|
||||
"on": "Установлен",
|
||||
"off": "Не установлен"
|
||||
}
|
||||
},
|
||||
"heating_binary_sensor": {
|
||||
"name": "Нагрев",
|
||||
"state": {
|
||||
"on": "Греет",
|
||||
"off": "Не греет"
|
||||
}
|
||||
},
|
||||
"available_binary_sensor": {
|
||||
"name": "Локальная сеть",
|
||||
"state": {
|
||||
"on": "В сети",
|
||||
"off": "Не в сети"
|
||||
}
|
||||
}
|
||||
},
|
||||
"time": {
|
||||
"delay_start": {
|
||||
"name": "Отложенный старт"
|
||||
},
|
||||
"cooking_time": {
|
||||
"name": "Время приготовления"
|
||||
}
|
||||
},
|
||||
"button": {
|
||||
"button_stop": {
|
||||
"name": "Остановить"
|
||||
},
|
||||
"button_start": {
|
||||
"name": "Запустить"
|
||||
},
|
||||
"button_stop_coffee": {
|
||||
"name": "Остановить"
|
||||
},
|
||||
"button_start_coffee": {
|
||||
"name": "Приготовить"
|
||||
},
|
||||
"button_reset_filter": {
|
||||
"name": "Сброс таймера фильтра"
|
||||
},
|
||||
"button_reset_prefilter": {
|
||||
"name": "Сброс таймера префильтра"
|
||||
},
|
||||
"button_reset_tank": {
|
||||
"name": "Сброс таймера очистки бака"
|
||||
}
|
||||
},
|
||||
"climate": {
|
||||
"climate": {
|
||||
"name": "Климат",
|
||||
"state_attributes": {
|
||||
"fan_mode": {
|
||||
"state": {
|
||||
"1_speed": "1 скорость",
|
||||
"2_speed": "2 скорость",
|
||||
"3_speed": "3 скорость",
|
||||
"4_speed": "4 скорость",
|
||||
"5_speed": "5 скорость",
|
||||
"6_speed": "6 скорость",
|
||||
"7_speed": "7 скорость",
|
||||
"8_speed": "8 скорость",
|
||||
"9_speed": "9 скорость"
|
||||
}
|
||||
},
|
||||
"preset_mode": {
|
||||
"state": {
|
||||
"hands": "Ручной",
|
||||
"auto": "Автоматический",
|
||||
"night": "Ночной",
|
||||
"turbo": "Турбо",
|
||||
"passive": "Пассивный"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"heater": {
|
||||
"name": "Конвектор",
|
||||
"state_attributes": {
|
||||
"fan_mode": {
|
||||
"name": "Мощность нагрева",
|
||||
"state": {
|
||||
"10_percent": "10 %",
|
||||
"20_percent": "20 %",
|
||||
"30_percent": "30 %",
|
||||
"40_percent": "40 %",
|
||||
"50_percent": "50 %",
|
||||
"60_percent": "60 %",
|
||||
"70_percent": "70 %",
|
||||
"80_percent": "80 %",
|
||||
"90_percent": "90 %",
|
||||
"100_percent": "100 %",
|
||||
"20_5_percent": "20 %",
|
||||
"40_5_percent": "40 %",
|
||||
"60_5_percent": "60 %",
|
||||
"80_5_percent": "80 %",
|
||||
"100_5_percent": "100 %"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"aircleaner": {
|
||||
"name": "Очиститель воздуха",
|
||||
"state": {
|
||||
"dry": "Очистка"
|
||||
},
|
||||
"state_attributes": {
|
||||
"preset_mode": {
|
||||
"state": {
|
||||
"hands": "Ручной",
|
||||
"auto": "Автоматический",
|
||||
"night": "Ночной"
|
||||
}
|
||||
},
|
||||
"fan_mode": {
|
||||
"state": {
|
||||
"top": "Турбо"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"conditioner": {
|
||||
"name": "Кондиционер",
|
||||
"state_attributes": {
|
||||
"fan_mode": {
|
||||
"state": {
|
||||
"min": "Минимум",
|
||||
"max": "Максимум"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"thermostat": {
|
||||
"name": "Термостат",
|
||||
"state_attributes": {
|
||||
"preset_mode": {
|
||||
"state": {
|
||||
"eco": "Экономичный",
|
||||
"comfort": "Комфорт",
|
||||
"turbo": "Турбо",
|
||||
"antifrost": "Антизамерзание",
|
||||
"schedule": "Расписание",
|
||||
"vacation": "Отпуск",
|
||||
"manual": "Настройка"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"common": {
|
||||
"all": "Выберите тип устройства",
|
||||
"kettle": "Чайник",
|
||||
"humidifier": "Увлажнитель",
|
||||
"cooker": "Мультиварка",
|
||||
"coffeemaker": "Кофемашина",
|
||||
"air_cleaner": "Очиститель воздуха",
|
||||
"irrigator": "Ирригатор",
|
||||
"air_fryer": "Воздухоочиститель",
|
||||
"boiler": "Бойлер",
|
||||
"heater": "Обогреватель",
|
||||
"cleaner": "Робот пылесос",
|
||||
"blender": "Блендер",
|
||||
"cooktop": "Варочная панель",
|
||||
"cordless_cleaner": "Ручной пылесос",
|
||||
"fan": "Вентилятор",
|
||||
"grill": "Гриль",
|
||||
"hair_care": "Фен",
|
||||
"hood": "Вытяжка",
|
||||
"iron": "Утюг",
|
||||
"kitchen_machine": "Кухонная машина",
|
||||
"meat_grinder": "Мясорубка",
|
||||
"other": "Умная крышка",
|
||||
"oven": "Духовка",
|
||||
"steamer": "Отпариватель",
|
||||
"toothbrush": "Зубная щетка",
|
||||
"air_conditioner": "Кондиционер",
|
||||
"thermostat": "Термостат"
|
||||
}
|
||||
}
|
||||
523
homeassistant/config/custom_components/polaris/vacuum.py
Normal file
523
homeassistant/config/custom_components/polaris/vacuum.py
Normal file
@@ -0,0 +1,523 @@
|
||||
"""The Polaris IQ Home component."""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
import logging
|
||||
from typing import Iterable, Final, Any
|
||||
import copy
|
||||
import datetime
|
||||
import os
|
||||
import voluptuous as vol
|
||||
import struct
|
||||
|
||||
|
||||
from homeassistant.components import mqtt
|
||||
from homeassistant.components.mqtt.models import ReceiveMessage
|
||||
from homeassistant.components.vacuum import (
|
||||
DOMAIN,
|
||||
ATTR_CLEANED_AREA,
|
||||
StateVacuumEntity,
|
||||
# VacuumActivity,
|
||||
VacuumEntityFeature,
|
||||
)
|
||||
from homeassistant.helpers.entity import DeviceInfo, EntityCategory
|
||||
from homeassistant.const import ATTR_ENTITY_ID, ATTR_ID
|
||||
from homeassistant.util import slugify
|
||||
from homeassistant.core import HomeAssistant, callback, ServiceCall
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers import config_validation as cv, entity_platform
|
||||
from .common import PolarisBaseEntity
|
||||
# Import global values.
|
||||
from .const import (
|
||||
MANUFACTURER,
|
||||
MQTT_ROOT_TOPIC,
|
||||
DEVICEID,
|
||||
DEVICETYPE,
|
||||
POLARIS_DEVICE,
|
||||
VACUUM,
|
||||
PolarisSelectEntityDescription,
|
||||
POLARIS_VACUUM_TYPE,
|
||||
CUSTOM_SELECT_FILE_PATH,
|
||||
SELECT_VACUUM,
|
||||
)
|
||||
|
||||
SERVICE_VACUUM_CLEANING_ROOM: Final = "vacuum_cleaning_room"
|
||||
ATTR_SELECTED_ROOMS = "rooms"
|
||||
SELECT_ROOMS = "select_rooms"
|
||||
|
||||
_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"]
|
||||
vacuumList = []
|
||||
|
||||
|
||||
# if rooms_js:
|
||||
# available_rooms = list(rooms_js.keys())
|
||||
|
||||
file_path = CUSTOM_SELECT_FILE_PATH
|
||||
if os.path.exists(file_path):
|
||||
with open(file_path, 'r', encoding='utf-8') as file:
|
||||
custom_data_rooms = json.loads(file.read())
|
||||
else:
|
||||
custom_data_rooms = None
|
||||
|
||||
if custom_data_rooms is not None and "SELECT_VACUUM_rooms" in custom_data_rooms:
|
||||
custom_data_rooms = json.loads(json.dumps(custom_data_rooms))
|
||||
rooms_js = custom_data_rooms["SELECT_VACUUM_rooms"]
|
||||
# _LOGGER.debug("rooms_js %s", rooms_js)
|
||||
else:
|
||||
rooms_js = {"no_room": {"id": "00", "coordinates": []}}
|
||||
available_rooms = list(rooms_js.keys())
|
||||
|
||||
|
||||
|
||||
# _LOGGER.debug("available_rooms read %s", available_rooms)
|
||||
|
||||
|
||||
|
||||
|
||||
if (device_type in POLARIS_VACUUM_TYPE):
|
||||
VACUUM_LC = copy.deepcopy(VACUUM)
|
||||
for description in VACUUM_LC:
|
||||
description.mqttTopicCurrentMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentMode}"
|
||||
description.mqttTopicCommandMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandMode}"
|
||||
description.mqttTopicBatteryState = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicBatteryState}"
|
||||
description.mqttTopicBatteryLevel = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicBatteryLevel}"
|
||||
description.mqttTopicStateFanMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicStateFanMode}"
|
||||
description.mqttTopicCommandFanMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandFanMode}"
|
||||
description.mqttTopicCommandFindMe = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandFindMe}"
|
||||
description.mqttTopicCommandGoArea = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandGoArea}"
|
||||
description.mqttTopicCommandTest = f"{mqtt_root}/{device_prefix_topic}/state"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
vacuumList.append(
|
||||
PolarisVacuum(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id,
|
||||
available_rooms=available_rooms,
|
||||
rooms_js=rooms_js
|
||||
)
|
||||
)
|
||||
async_add_entities(vacuumList, update_before_add=True)
|
||||
|
||||
|
||||
platform = entity_platform.current_platform.get()
|
||||
platform.async_register_entity_service(
|
||||
"select_rooms",
|
||||
{
|
||||
vol.Required(ATTR_ENTITY_ID): cv.entity_ids,
|
||||
vol.Required(SELECT_ROOMS): vol.All(cv.string, vol.In(available_rooms))
|
||||
},
|
||||
"sweep_rooms_wrapper",
|
||||
)
|
||||
|
||||
|
||||
class PolarisVacuum(PolarisBaseEntity, StateVacuumEntity):
|
||||
|
||||
entity_description: PolarisVacuumEntityDescription
|
||||
# _unrecorded_attributes = frozenset({ATTR_ROOMS})
|
||||
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
device_friendly_name: str,
|
||||
description: PolarisVacuumEntityDescription,
|
||||
mqtt_root: str,
|
||||
device_id: str | None=None,
|
||||
device_type: str | None=None,
|
||||
available_rooms: list | None=None,
|
||||
rooms_js: 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_has_entity_name = True
|
||||
|
||||
self._attr_fan_speed="min"
|
||||
self._attr_fan_speed_list = ["min", "medium", "high", "max"]
|
||||
self._attr_supported_features = (
|
||||
VacuumEntityFeature.BATTERY
|
||||
| VacuumEntityFeature.RETURN_HOME
|
||||
| VacuumEntityFeature.CLEAN_SPOT
|
||||
| VacuumEntityFeature.STOP
|
||||
# | VacuumEntityFeature.PAUSE
|
||||
| VacuumEntityFeature.START
|
||||
| VacuumEntityFeature.LOCATE
|
||||
| VacuumEntityFeature.STATE
|
||||
| VacuumEntityFeature.SEND_COMMAND
|
||||
| VacuumEntityFeature.FAN_SPEED
|
||||
| VacuumEntityFeature.STATUS
|
||||
| VacuumEntityFeature.MAP
|
||||
)
|
||||
# self._entity_component_unrecorded_attributes = frozenset({ATTR_FAN_SPEED_LIST})
|
||||
|
||||
self._attr_battery_icon="mdi:vacuum"
|
||||
self._attr_battery_level=70
|
||||
self._attr_state = "idle"
|
||||
|
||||
|
||||
|
||||
self._select_rooms = []
|
||||
self._available_rooms = available_rooms
|
||||
self._rooms_js = rooms_js
|
||||
|
||||
|
||||
|
||||
|
||||
@property
|
||||
def select_rooms(self) -> list | None:
|
||||
"""Return a list of rooms available to clean."""
|
||||
if self._select_rooms:
|
||||
# _LOGGER.debug("select_rooms : %s", self._select_rooms)
|
||||
return self._rooms
|
||||
return []
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self):
|
||||
"""Return a dictionary of device state attributes specific to sharkiq."""
|
||||
data = {}
|
||||
if self._available_rooms is not None:
|
||||
data["available_rooms"] = self._available_rooms
|
||||
if self._select_rooms is not None:
|
||||
data["select_rooms"] = self._select_rooms
|
||||
return data
|
||||
|
||||
|
||||
def int16_array_to_bytes(self, int16_array, byteorder='little'):
|
||||
"""
|
||||
Преобразует массив int16 обратно в байтовую строку.
|
||||
Аргументы:
|
||||
int16_array: Массив int16 значений (list of int).
|
||||
byteorder: Порядок байтов ('little' или 'big'), по умолчанию 'little'.
|
||||
Возвращает:
|
||||
Байтовая строка (bytes).
|
||||
Вызывает исключение ValueError:
|
||||
Если byteorder не является 'little' или 'big'.
|
||||
"""
|
||||
if byteorder not in ('little', 'big'):
|
||||
raise ValueError("Неверный порядок байтов. Допустимые значения: 'little', 'big'.")
|
||||
endian_prefix = '<' if byteorder == 'little' else '>'
|
||||
format_string = endian_prefix + 'h' * len(int16_array)
|
||||
return struct.pack(format_string, *int16_array) # * распаковывает массив в аргументы для pack
|
||||
|
||||
async def sweep_rooms_wrapper(self, select_rooms):
|
||||
# for room in self._room_manager.rooms.keys():
|
||||
# self._room_manager.rooms[room] = False
|
||||
_LOGGER.debug("room in service %s ", select_rooms)
|
||||
#for entry in mysel_rooms:
|
||||
# name = self.hass.states.get(entry).attributes['room_name']
|
||||
# _LOGGER.debug("target_rooms entry %s", entry)
|
||||
# await self.sweep_rooms(target_rooms)
|
||||
# self.async_schedule_update_ha_state(force_refresh=True)
|
||||
|
||||
|
||||
def start(self) -> None:
|
||||
"""Start or resume the cleaning task."""
|
||||
if self._attr_state != "cleaning":
|
||||
self._attr_state = "cleaning"
|
||||
self.schedule_update_ha_state()
|
||||
state_mode = self.hass.states.get(f"select.{POLARIS_DEVICE[int(self.device_type)]['class']}_{POLARIS_DEVICE[int(self.device_type)]['model'].replace('-', '_')}_select_mode_vacuum").state
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandMode, json.loads(json.dumps(SELECT_VACUUM[0].options[state_mode])))
|
||||
|
||||
def stop(self, **kwargs: Any) -> None:
|
||||
"""Stop the cleaning task, do not return to dock."""
|
||||
self._attr_state = "idle"
|
||||
self.schedule_update_ha_state()
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandMode, "0")
|
||||
|
||||
def return_to_base(self, **kwargs: Any) -> None:
|
||||
"""Return dock to charging base."""
|
||||
self._attr_state = "returning"
|
||||
self.schedule_update_ha_state()
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandMode, "5")
|
||||
|
||||
def clean_spot(self, **kwargs: Any) -> None:
|
||||
"""Perform a spot clean-up."""
|
||||
self._attr_state = "cleaning"
|
||||
self.schedule_update_ha_state()
|
||||
select_room = self.hass.states.get(f"select.{POLARIS_DEVICE[int(self.device_type)]['class']}_{POLARIS_DEVICE[int(self.device_type)]['model'].replace('-', '_')}_select_room").state
|
||||
# _LOGGER.debug("room in select %s ", select_room)
|
||||
# _LOGGER.debug("room in select %s ", self._rooms_js[select_room]["coordinate"])
|
||||
# _LOGGER.debug("int16_to_bytes %s",self.int16_array_to_bytes(self._rooms_js[select_room]["coordinate"]))
|
||||
mqtt.publish(
|
||||
self.hass, self.entity_description.mqttTopicCommandGoArea,
|
||||
self.int16_array_to_bytes(self._rooms_js[select_room]["coordinate"]),
|
||||
1,
|
||||
None,
|
||||
)
|
||||
|
||||
def set_fan_speed(self, fan_speed: str, **kwargs: Any) -> None:
|
||||
"""Set the vacuum's fan speed."""
|
||||
if fan_speed in self.fan_speed_list:
|
||||
self._attr_fan_speed = fan_speed
|
||||
self.schedule_update_ha_state()
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandFanMode, self._attr_fan_speed_list.index(fan_speed)+1)
|
||||
|
||||
async def async_locate(self, **kwargs: Any) -> None:
|
||||
"""Locate the vacuum's position."""
|
||||
await self.hass.services.async_call(
|
||||
"notify",
|
||||
"persistent_notification",
|
||||
service_data={"message": "I'm here!", "title": "Locate request"},
|
||||
)
|
||||
self._attr_state = "idle"
|
||||
self.async_write_ha_state()
|
||||
mqtt.publish(self.hass, self.entity_description.mqttTopicCommandFindMe, "true")
|
||||
|
||||
|
||||
async def async_send_command(
|
||||
self,
|
||||
command: str,
|
||||
params: dict[str, Any] | list[Any] | None = None,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Send a command to the vacuum."""
|
||||
self._attr_state = "idle"
|
||||
self.async_write_ha_state()
|
||||
|
||||
|
||||
|
||||
# def _save_log(self, message, topic) -> None:
|
||||
# file_path = "vacuum_log.txt"
|
||||
# with open(file_path, 'a+', encoding='utf-8') as file:
|
||||
# file.write(f"{datetime.datetime.now().strftime("%d-%m-%Y %H:%M:%S")} {topic} {message}\n")
|
||||
|
||||
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
@callback
|
||||
def message_received_batt_state(message):
|
||||
payload = message.payload
|
||||
self._attr_state = payload
|
||||
await mqtt.async_subscribe(self.hass, self.entity_description.mqttTopicBatteryState, message_received_batt_state, 1)
|
||||
|
||||
@callback
|
||||
def message_received_batt_level(message):
|
||||
payload = message.payload
|
||||
self._attr_battery_level = int(payload)
|
||||
self.async_write_ha_state()
|
||||
await mqtt.async_subscribe(self.hass, self.entity_description.mqttTopicBatteryLevel, message_received_batt_level, 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)
|
||||
|
||||
|
||||
|
||||
|
||||
# @callback
|
||||
# def message_received_contour(message):
|
||||
# payload = message.payload
|
||||
# self._save_log(payload, "Log contour:")
|
||||
# await mqtt.async_subscribe(self.hass, f"{self.entity_description.mqttTopicCommandTest}/contour", message_received_contour, 1, None)
|
||||
|
||||
# @callback
|
||||
# def message_received_go_area(message):
|
||||
# payload = message.payload
|
||||
# self._save_log(payload, "Log go_area:")
|
||||
# await mqtt.async_subscribe(self.hass, f"{self.entity_description.mqttTopicCommandTest}/go_area", message_received_go_area, 1, None)
|
||||
|
||||
# @callback
|
||||
# def message_received_mode(message):
|
||||
# payload = message.payload
|
||||
# self._save_log(payload, "Log mode:")
|
||||
# await mqtt.async_subscribe(self.hass, f"{self.entity_description.mqttTopicCommandTest}/mode", message_received_mode, 1)
|
||||
|
||||
# @callback
|
||||
# def message_received_map_angle(message):
|
||||
# payload = message.payload
|
||||
# self._save_log(payload, "Log map_angle:")
|
||||
# await mqtt.async_subscribe(self.hass, f"{self.entity_description.mqttTopicCommandTest}/map_angle", message_received_map_angle, 1)
|
||||
|
||||
# @callback
|
||||
# def message_received_clean_area(message):
|
||||
# payload = message.payload
|
||||
# self._save_log(payload, "Log clean_area:")
|
||||
# await mqtt.async_subscribe(self.hass, f"{self.entity_description.mqttTopicCommandTest}/clean_area", message_received_clean_area, 1)
|
||||
|
||||
# @callback
|
||||
# def message_received_program_data_0(message):
|
||||
# payload = message.payload
|
||||
# self._save_log(payload, "Log program_data_0:")
|
||||
# await mqtt.async_subscribe(self.hass, f"{self.entity_description.mqttTopicCommandTest}/program_data/0", message_received_program_data_0, 1)
|
||||
|
||||
# @callback
|
||||
# def message_received_program_data_1(message):
|
||||
# payload = message.payload
|
||||
# self._save_log(payload, "Log program_data_1:")
|
||||
# await mqtt.async_subscribe(self.hass, f"{self.entity_description.mqttTopicCommandTest}/program_data/1", message_received_program_data_1, 1)
|
||||
|
||||
# @callback
|
||||
# def message_received_program_data_2(message):
|
||||
# payload = message.payload
|
||||
# self._save_log(payload, "Log program_data_2:")
|
||||
# await mqtt.async_subscribe(self.hass, f"{self.entity_description.mqttTopicCommandTest}/program_data/2", message_received_program_data_2, 1)
|
||||
|
||||
# @callback
|
||||
# def message_received_program_data_3(message):
|
||||
# payload = message.payload
|
||||
# self._save_log(payload, "Log program_data_3:")
|
||||
# await mqtt.async_subscribe(self.hass, f"{self.entity_description.mqttTopicCommandTest}/program_data/3", message_received_program_data_3, 1)
|
||||
|
||||
# @callback
|
||||
# def message_received_program_data_4(message):
|
||||
# payload = message.payload
|
||||
# self._save_log(payload, "Log program_data_4:")
|
||||
# await mqtt.async_subscribe(self.hass, f"{self.entity_description.mqttTopicCommandTest}/program_data/4", message_received_program_data_4, 1)
|
||||
|
||||
# @callback
|
||||
# def message_received_location_current(message):
|
||||
# payload = message.payload
|
||||
# self._save_log(payload, "Log location_current:")
|
||||
# await mqtt.async_subscribe(self.hass, f"{self.entity_description.mqttTopicCommandTest}/location_current", message_received_location_current, 1)
|
||||
|
||||
# @callback
|
||||
# def message_received_map_0(message):
|
||||
# payload = message.payload
|
||||
# self._save_log(payload, "Log map_0:")
|
||||
# await mqtt.async_subscribe(self.hass, f"{self.entity_description.mqttTopicCommandTest}/map/0", message_received_map_0, 1, None)
|
||||
|
||||
# @callback
|
||||
# def message_received_map_1(message):
|
||||
# payload = message.payload
|
||||
# self._save_log(payload, "Log map_1:")
|
||||
# await mqtt.async_subscribe(self.hass, f"{self.entity_description.mqttTopicCommandTest}/map/1", message_received_map_1, 1, None)
|
||||
|
||||
# @callback
|
||||
# def message_received_virtual_wall(message):
|
||||
# payload = message.payload
|
||||
# self._save_log(payload, "Log virtual_wall:")
|
||||
# await mqtt.async_subscribe(self.hass, f"{self.entity_description.mqttTopicCommandTest}/virtual_wall", message_received_virtual_wall, 1, None)
|
||||
|
||||
# @callback
|
||||
# def message_received_no_go_area(message):
|
||||
# payload = message.payload
|
||||
# self._save_log(payload, "Log no_go_area:")
|
||||
# await mqtt.async_subscribe(self.hass, f"{self.entity_description.mqttTopicCommandTest}/no_go_area", message_received_no_go_area, 1, None)
|
||||
|
||||
# @callback
|
||||
# def message_received_map_image(message):
|
||||
# payload = message.payload
|
||||
# self._save_log(payload, "Log map_image:")
|
||||
# await mqtt.async_subscribe(self.hass, f"{self.entity_description.mqttTopicCommandTest}/map_image", message_received_map_image, 1, None)
|
||||
|
||||
# @callback
|
||||
# def message_received_map_long_0(message):
|
||||
# payload = message.payload
|
||||
# self._save_log(payload, "Log map_long_0:")
|
||||
# await mqtt.async_subscribe(self.hass, f"{self.entity_description.mqttTopicCommandTest}/map_long/0", message_received_map_long_0, 1, None)
|
||||
|
||||
# @callback
|
||||
# def message_received_map_long_1(message):
|
||||
# payload = message.payload
|
||||
# self._save_log(payload, "Log map_long_1:")
|
||||
# await mqtt.async_subscribe(self.hass, f"{self.entity_description.mqttTopicCommandTest}/map_long/1", message_received_map_long_1, 1, None)
|
||||
|
||||
# @callback
|
||||
# def message_received_map_long_2(message):
|
||||
# payload = message.payload
|
||||
# self._save_log(payload, "Log map_long_2:")
|
||||
# await mqtt.async_subscribe(self.hass, f"{self.entity_description.mqttTopicCommandTest}/map_long/2", message_received_map_long_2, 1, None)
|
||||
|
||||
# @callback
|
||||
# def message_received_map_long_3(message):
|
||||
# payload = message.payload
|
||||
# self._save_log(payload, "Log map_long_3:")
|
||||
# await mqtt.async_subscribe(self.hass, f"{self.entity_description.mqttTopicCommandTest}/map_long/3", message_received_map_long_3, 1, None)
|
||||
|
||||
# @callback
|
||||
# def message_received_map_long_4(message):
|
||||
# payload = message.payload
|
||||
# self._save_log(payload, "Log map_long_4:")
|
||||
# await mqtt.async_subscribe(self.hass, f"{self.entity_description.mqttTopicCommandTest}/map_long/4", message_received_map_long_4, 1, None)
|
||||
|
||||
# @callback
|
||||
# def message_received_map_long_5(message):
|
||||
# payload = message.payload
|
||||
# self._save_log(payload, "Log map_long_5:")
|
||||
# await mqtt.async_subscribe(self.hass, f"{self.entity_description.mqttTopicCommandTest}/map_long/5", message_received_map_long_5, 1, None)
|
||||
|
||||
# @callback
|
||||
# def message_received_map_long_6(message):
|
||||
# payload = message.payload
|
||||
# self._save_log(payload, "Log map_long_6:")
|
||||
# await mqtt.async_subscribe(self.hass, f"{self.entity_description.mqttTopicCommandTest}/map_long/6", message_received_map_long_6, 1, None)
|
||||
|
||||
# @callback
|
||||
# def message_received_map_long_7(message):
|
||||
# payload = message.payload
|
||||
# self._save_log(payload, "Log map_long_7:")
|
||||
# await mqtt.async_subscribe(self.hass, f"{self.entity_description.mqttTopicCommandTest}/map_long/7", message_received_map_long_7, 1, None)
|
||||
|
||||
# @callback
|
||||
# def message_received_map_long_8(message):
|
||||
# payload = message.payload
|
||||
# self._save_log(payload, "Log map_long_8:")
|
||||
# await mqtt.async_subscribe(self.hass, f"{self.entity_description.mqttTopicCommandTest}/map_long/8", message_received_map_long_8, 1, None)
|
||||
|
||||
# @callback
|
||||
# def message_received_map_long_9(message):
|
||||
# payload = message.payload
|
||||
# self._save_log(payload, "Log map_long_9:")
|
||||
# await mqtt.async_subscribe(self.hass, f"{self.entity_description.mqttTopicCommandTest}/map_long/9", message_received_map_long_9, 1, None)
|
||||
|
||||
# @callback
|
||||
# def message_received_map_location_0(message):
|
||||
# payload = message.payload
|
||||
# self._save_log(payload, "Log map_location_0:")
|
||||
# await mqtt.async_subscribe(self.hass, f"{self.entity_description.mqttTopicCommandTest}/map_location/0", message_received_map_location_0, 1, None)
|
||||
|
||||
# @callback
|
||||
# def message_received_map_location_1(message):
|
||||
# payload = message.payload
|
||||
# self._save_log(payload, "Log map_location_1:")
|
||||
# await mqtt.async_subscribe(self.hass, f"{self.entity_description.mqttTopicCommandTest}/map_location/1", message_received_map_location_1, 1, None)
|
||||
|
||||
# @callback
|
||||
# def message_received_map_location_2(message):
|
||||
# payload = message.payload
|
||||
# self._save_log(payload, "Log map_location_2:")
|
||||
# await mqtt.async_subscribe(self.hass, f"{self.entity_description.mqttTopicCommandTest}/map_location/2", message_received_map_location_2, 1, None)
|
||||
|
||||
# @callback
|
||||
# def message_received_map_location_3(message):
|
||||
# payload = message.payload
|
||||
# self._save_log(payload, "Log map_location_3:")
|
||||
# await mqtt.async_subscribe(self.hass, f"{self.entity_description.mqttTopicCommandTest}/map_location/3", message_received_map_location_3, 1, None)
|
||||
|
||||
# @callback
|
||||
# def message_received_map_location_4(message):
|
||||
# payload = message.payload
|
||||
# self._save_log(payload, "Log map_location_4:")
|
||||
# await mqtt.async_subscribe(self.hass, f"{self.entity_description.mqttTopicCommandTest}/map_location/4", message_received_map_location_4, 1, None)
|
||||
|
||||
# @callback
|
||||
# def message_received_map_location_5(message):
|
||||
# payload = message.payload
|
||||
# self._save_log(payload, "Log map_location_5:")
|
||||
# await mqtt.async_subscribe(self.hass, f"{self.entity_description.mqttTopicCommandTest}/map_location/5", message_received_map_location_5, 1, None)
|
||||
|
||||
244
homeassistant/config/custom_components/polaris/water_heater.py
Normal file
244
homeassistant/config/custom_components/polaris/water_heater.py
Normal file
@@ -0,0 +1,244 @@
|
||||
"""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.const import ATTR_TEMPERATURE, UnitOfTemperature
|
||||
from homeassistant.components.water_heater import DOMAIN, WaterHeaterEntity, WaterHeaterEntityFeature
|
||||
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
|
||||
# Import global values.
|
||||
from .const import (
|
||||
MANUFACTURER,
|
||||
MQTT_ROOT_TOPIC,
|
||||
DEVICEID,
|
||||
DEVICETYPE,
|
||||
POLARIS_DEVICE,
|
||||
WATER_HEATERS,
|
||||
WATER_BOILERS,
|
||||
PolarisWaterHeaterEntityDescription,
|
||||
POLARIS_KETTLE_TYPE,
|
||||
POLARIS_KETTLE_WITH_WEIGHT_TYPE,
|
||||
POLARIS_BOILER_TYPE,
|
||||
KETTLE_WITH_TEA_TIME_MODES,
|
||||
KETTLE_WITH_KEEP_WITH_WARM_MODES,
|
||||
POLARIS_KETTLE_WITH_TEA_TIME_MODE_TYPE,
|
||||
POLARIS_KETTLE_WITH_KEEP_WITH_WARM_MODE_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"]
|
||||
waterheaterList = []
|
||||
|
||||
if (device_type in POLARIS_KETTLE_TYPE) or (device_type in POLARIS_KETTLE_WITH_WEIGHT_TYPE):
|
||||
# Create water heater for kettle devices
|
||||
WATER_HEATERS_LC = copy.deepcopy(WATER_HEATERS)
|
||||
for description in WATER_HEATERS_LC:
|
||||
description.mqttTopicCommandTemperature = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandTemperature}"
|
||||
description.mqttTopicCurrentTemperature = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentTemperature}"
|
||||
description.mqttTopicTargetTemperature = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicTargetTemperature}"
|
||||
description.mqttTopicCommandMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandMode}"
|
||||
description.mqttTopicCurrentMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentMode}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
waterheaterList.append(
|
||||
PolarisWaterHeater(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
if (device_type in POLARIS_BOILER_TYPE):
|
||||
# Create water boiler
|
||||
WATER_BOILERS_LC = copy.deepcopy(WATER_BOILERS)
|
||||
for description in WATER_BOILERS_LC:
|
||||
description.mqttTopicCommandTemperature = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandTemperature}"
|
||||
description.mqttTopicCurrentTemperature = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentTemperature}"
|
||||
description.mqttTopicTargetTemperature = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicTargetTemperature}"
|
||||
description.mqttTopicCommandMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCommandMode}"
|
||||
description.mqttTopicCurrentMode = f"{mqtt_root}/{device_prefix_topic}/{description.mqttTopicCurrentMode}"
|
||||
description.device_prefix_topic = device_prefix_topic
|
||||
waterheaterList.append(
|
||||
PolarisWaterHeater(
|
||||
description=description,
|
||||
device_friendly_name=device_id,
|
||||
mqtt_root=mqtt_root,
|
||||
device_type=device_type,
|
||||
device_id=device_id
|
||||
)
|
||||
)
|
||||
async_add_entities(waterheaterList, update_before_add=True)
|
||||
|
||||
class PolarisWaterHeater(PolarisBaseEntity, WaterHeaterEntity):
|
||||
entity_description: PolarisWaterHeaterEntityDescription
|
||||
def __init__(
|
||||
self,
|
||||
device_friendly_name: str,
|
||||
description: PolarisWaterHeaterEntityDescription,
|
||||
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.payload_on = description.payload_on
|
||||
self.payload_off = description.payload_off
|
||||
self._attr_temperature_unit = UnitOfTemperature.CELSIUS
|
||||
|
||||
self._attr_min_temp = description.min_temp
|
||||
self._attr_max_temp = description.max_temp
|
||||
self._attr_target_temperature_high = description.max_temp
|
||||
self._attr_target_temperature_low = description.min_temp
|
||||
self._attr_target_temperature = description.max_temp
|
||||
self._attr_target_temperature_step = 1.0
|
||||
|
||||
self._attr_is_away_mode_on = None
|
||||
self._attr_is_on = True
|
||||
self._attr_supported_features = WaterHeaterEntityFeature.OPERATION_MODE | WaterHeaterEntityFeature.TARGET_TEMPERATURE | WaterHeaterEntityFeature.ON_OFF
|
||||
|
||||
self._attr_current_operation = description.mode
|
||||
self._modes = {}
|
||||
if (self.device_type in POLARIS_KETTLE_WITH_KEEP_WITH_WARM_MODE_TYPE):
|
||||
self._modes = KETTLE_WITH_KEEP_WITH_WARM_MODES
|
||||
# self._attr_operation_list = list(KETTLE_WITH_KEEP_WITH_WARM_MODES.keys())
|
||||
elif (self.device_type in POLARIS_KETTLE_WITH_TEA_TIME_MODE_TYPE):
|
||||
self._modes = KETTLE_WITH_TEA_TIME_MODES
|
||||
# self._attr_operation_list = list(KETTLE_WITH_TEA_TIME_MODES.keys())
|
||||
elif (self.device_type in {"802","844"}):
|
||||
self._modes = {"off": "0", "performance": "1", "electric": "2", "heat_pump": "3"}
|
||||
else:
|
||||
self._modes = description.operation_list
|
||||
self._attr_operation_list = list(self._modes.keys())
|
||||
|
||||
#self.entity_picture = "https://images.cdn.polaris-iot.com/a/8c/aad08-4d13-489c-9b0f-028486297ac1/60.webp"
|
||||
self._attr_has_entity_name = True
|
||||
self._attr_available = False
|
||||
|
||||
# _attr_precision: float
|
||||
# _attr_state: None = None
|
||||
|
||||
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
@callback
|
||||
def message_received_temp(message):
|
||||
self._attr_current_temperature = float(message.payload)
|
||||
self.async_write_ha_state()
|
||||
@callback
|
||||
def message_received_mode(message):
|
||||
self._attr_current_operation = list(self._modes.keys())[list(self._modes.values()).index(message.payload)]
|
||||
self.async_write_ha_state()
|
||||
@callback
|
||||
def message_received_targtemp(message):
|
||||
if float(message.payload) < self._attr_min_temp:
|
||||
self._attr_target_temperature = self._attr_min_temp
|
||||
else:
|
||||
self._attr_target_temperature = float(message.payload)
|
||||
self.async_write_ha_state()
|
||||
|
||||
await mqtt.async_subscribe(
|
||||
self.hass,
|
||||
self.entity_description.mqttTopicCurrentTemperature,
|
||||
message_received_temp,
|
||||
1,
|
||||
)
|
||||
await mqtt.async_subscribe(
|
||||
self.hass,
|
||||
self.entity_description.mqttTopicCurrentMode,
|
||||
message_received_mode,
|
||||
1,
|
||||
)
|
||||
await mqtt.async_subscribe(
|
||||
self.hass,
|
||||
self.entity_description.mqttTopicTargetTemperature,
|
||||
message_received_targtemp,
|
||||
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)
|
||||
|
||||
|
||||
def async_turn_on(self, **kwargs):
|
||||
self._attr_is_on = self.payload_on
|
||||
self.publishToMQTT()
|
||||
|
||||
def async_turn_off(self, **kwargs):
|
||||
self._attr_is_on = self.payload_off
|
||||
self.publishToMQTT()
|
||||
|
||||
def publishToMQTT(self):
|
||||
topic = f"{self.entity_description.mqttTopicCommandMode}"
|
||||
mqtt.publish(self.hass, topic, str(self._attr_is_on))
|
||||
|
||||
def set_operation_mode(self, operation_mode):
|
||||
topic = f"{self.entity_description.mqttTopicCommandTemperature}"
|
||||
mqtt.publish(self.hass, topic, int(self._attr_target_temperature))
|
||||
topic = f"{self.entity_description.mqttTopicCommandMode}"
|
||||
self._attr_current_operation = operation_mode
|
||||
mqtt.publish(self.hass, topic, int(self._modes[operation_mode]))
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
def set_temperature(self, **kwargs):
|
||||
self._attr_target_temperature = kwargs.get(ATTR_TEMPERATURE)
|
||||
topic = f"{self.entity_description.mqttTopicCommandTemperature}"
|
||||
mqtt.publish(self.hass, topic, int(self._attr_target_temperature))
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
@property
|
||||
def state(self) -> str | None:
|
||||
return self.current_operation
|
||||
|
||||
@property
|
||||
def operation_list(self) -> list[str] | None:
|
||||
return self._attr_operation_list
|
||||
|
||||
@property
|
||||
def current_operation(self) -> str | None:
|
||||
return self._attr_current_operation
|
||||
|
||||
@property
|
||||
def supported_features(self) -> WaterHeaterEntityFeature:
|
||||
return self._attr_supported_features
|
||||
|
||||
@property
|
||||
def min_temp(self) -> float:
|
||||
return self._attr_min_temp
|
||||
|
||||
@property
|
||||
def max_temp(self) -> float:
|
||||
return self._attr_max_temp
|
||||
Reference in New Issue
Block a user