mirror of
https://github.com/XiaoMi/ha_xiaomi_home.git
synced 2026-01-12 03:40:43 +08:00
Compare commits
6 Commits
8bbf02438f
...
8325be9dbf
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8325be9dbf | ||
|
|
f5bc880c62 | ||
|
|
4c7b6d570d | ||
|
|
b95a2c18ee | ||
|
|
5dc6f400c2 | ||
|
|
006a445e3a |
@ -47,11 +47,12 @@ Light entities for Xiaomi Home.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
import logging
|
||||
from typing import Any, Optional
|
||||
from typing import Any, Optional, List, Dict
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_registry import async_get as async_get_entity_registry
|
||||
from homeassistant.components.light import (
|
||||
ATTR_BRIGHTNESS,
|
||||
ATTR_COLOR_TEMP_KELVIN,
|
||||
@ -86,7 +87,7 @@ async def async_setup_entry(
|
||||
for miot_device in device_list:
|
||||
for data in miot_device.entity_list.get('light', []):
|
||||
new_entities.append(
|
||||
Light(miot_device=miot_device, entity_data=data))
|
||||
Light(miot_device=miot_device, entity_data=data, hass=hass))
|
||||
|
||||
if new_entities:
|
||||
async_add_entities(new_entities)
|
||||
@ -106,10 +107,13 @@ class Light(MIoTServiceEntity, LightEntity):
|
||||
_mode_map: Optional[dict[Any, Any]]
|
||||
|
||||
def __init__(
|
||||
self, miot_device: MIoTDevice, entity_data: MIoTEntityData
|
||||
self, miot_device: MIoTDevice, entity_data: MIoTEntityData,hass: HomeAssistant
|
||||
) -> None:
|
||||
"""Initialize the Light."""
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
self.hass = hass
|
||||
self.miot_device = miot_device
|
||||
self._command_send_mode_entity_id = None
|
||||
self._attr_color_mode = None
|
||||
self._attr_supported_color_modes = set()
|
||||
self._attr_supported_features = LightEntityFeature(0)
|
||||
@ -252,42 +256,178 @@ class Light(MIoTServiceEntity, LightEntity):
|
||||
"""
|
||||
# on
|
||||
# Dirty logic for lumi.gateway.mgl03 indicator light
|
||||
if self._prop_on:
|
||||
value_on = True if self._prop_on.format_ == bool else 1
|
||||
await self.set_property_async(
|
||||
prop=self._prop_on, value=value_on)
|
||||
# brightness
|
||||
# Determine whether the device sends the light-on properties in batches or one by one
|
||||
# Search entityid through unique_id to avoid the user modifying entityid and causing command_send_mode to not match
|
||||
# 获取开灯模式
|
||||
if self._command_send_mode_entity_id is None:
|
||||
entity_registry = async_get_entity_registry(self.hass)
|
||||
device_id = list(
|
||||
self.miot_device.device_info.get("identifiers"))[0][1]
|
||||
self._command_send_mode_entity_id = entity_registry.async_get_entity_id(
|
||||
"select", DOMAIN, f"select.light_{device_id}_command_send_mode")
|
||||
if self._command_send_mode_entity_id is None:
|
||||
_LOGGER.error(
|
||||
"light command_send_mode not found, %s",
|
||||
self.entity_id,
|
||||
)
|
||||
return
|
||||
command_send_mode = self.hass.states.get(
|
||||
self._command_send_mode_entity_id)
|
||||
|
||||
# 判断是先发送亮度还是先发送色温
|
||||
send_brightness_first = False
|
||||
if ATTR_BRIGHTNESS in kwargs:
|
||||
brightness = brightness_to_value(
|
||||
self._brightness_scale, kwargs[ATTR_BRIGHTNESS])
|
||||
await self.set_property_async(
|
||||
prop=self._prop_brightness, value=brightness,
|
||||
write_ha_state=False)
|
||||
# color-temperature
|
||||
if ATTR_COLOR_TEMP_KELVIN in kwargs:
|
||||
await self.set_property_async(
|
||||
prop=self._prop_color_temp,
|
||||
value=kwargs[ATTR_COLOR_TEMP_KELVIN],
|
||||
write_ha_state=False)
|
||||
self._attr_color_mode = ColorMode.COLOR_TEMP
|
||||
# rgb color
|
||||
if ATTR_RGB_COLOR in kwargs:
|
||||
r = kwargs[ATTR_RGB_COLOR][0]
|
||||
g = kwargs[ATTR_RGB_COLOR][1]
|
||||
b = kwargs[ATTR_RGB_COLOR][2]
|
||||
rgb = (r << 16) | (g << 8) | b
|
||||
await self.set_property_async(
|
||||
prop=self._prop_color, value=rgb,
|
||||
write_ha_state=False)
|
||||
self._attr_color_mode = ColorMode.RGB
|
||||
# mode
|
||||
if ATTR_EFFECT in kwargs:
|
||||
await self.set_property_async(
|
||||
prop=self._prop_mode,
|
||||
value=self.get_map_key(
|
||||
map_=self._mode_map, value=kwargs[ATTR_EFFECT]),
|
||||
write_ha_state=False)
|
||||
self.async_write_ha_state()
|
||||
brightness_new = kwargs[ATTR_BRIGHTNESS]
|
||||
brightness_old = self.brightness
|
||||
if brightness_old and brightness_new <= brightness_old:
|
||||
send_brightness_first = True
|
||||
|
||||
# 开始发送开灯命令
|
||||
if command_send_mode and command_send_mode.state == "Send Together":
|
||||
set_properties_list: List[Dict[str, Any]] = []
|
||||
# mode
|
||||
if ATTR_EFFECT in kwargs:
|
||||
set_properties_list.append({
|
||||
"prop":self._prop_mode,
|
||||
"value":self.get_map_key(
|
||||
map_=self._mode_map,value=kwargs[ATTR_EFFECT]),
|
||||
})
|
||||
# brightness
|
||||
if send_brightness_first and ATTR_BRIGHTNESS in kwargs:
|
||||
brightness = brightness_to_value(
|
||||
self._brightness_scale,kwargs[ATTR_BRIGHTNESS])
|
||||
set_properties_list.append({
|
||||
"prop": self._prop_brightness,
|
||||
"value": brightness
|
||||
})
|
||||
# color-temperature
|
||||
if ATTR_COLOR_TEMP_KELVIN in kwargs:
|
||||
set_properties_list.append({
|
||||
"prop": self._prop_color_temp,
|
||||
"value": kwargs[ATTR_COLOR_TEMP_KELVIN],
|
||||
})
|
||||
self._attr_color_mode = ColorMode.COLOR_TEMP
|
||||
# rgb color
|
||||
if ATTR_RGB_COLOR in kwargs:
|
||||
r = kwargs[ATTR_RGB_COLOR][0]
|
||||
g = kwargs[ATTR_RGB_COLOR][1]
|
||||
b = kwargs[ATTR_RGB_COLOR][2]
|
||||
rgb = (r << 16) | (g << 8) | b
|
||||
set_properties_list.append({
|
||||
"prop": self._prop_color,
|
||||
"value": rgb
|
||||
})
|
||||
self._attr_color_mode = ColorMode.RGB
|
||||
# brightness
|
||||
if not send_brightness_first and ATTR_BRIGHTNESS in kwargs:
|
||||
brightness = brightness_to_value(
|
||||
self._brightness_scale,kwargs[ATTR_BRIGHTNESS])
|
||||
set_properties_list.append({
|
||||
"prop": self._prop_brightness,
|
||||
"value": brightness
|
||||
})
|
||||
|
||||
if self._prop_on:
|
||||
value_on = True if self._prop_on.format_ == bool else 1
|
||||
set_properties_list.append({
|
||||
"prop": self._prop_on,
|
||||
"value": value_on
|
||||
})
|
||||
await self.set_properties_async(set_properties_list,write_ha_state=False)
|
||||
self.async_write_ha_state()
|
||||
|
||||
elif command_send_mode and command_send_mode.state == "Send Turn On First":
|
||||
set_properties_list: List[Dict[str, Any]] = []
|
||||
if self._prop_on:
|
||||
value_on = True if self._prop_on.format_ == bool else 1
|
||||
set_properties_list.append({
|
||||
"prop": self._prop_on,
|
||||
"value": value_on
|
||||
})
|
||||
# mode
|
||||
if ATTR_EFFECT in kwargs:
|
||||
set_properties_list.append({
|
||||
"prop":
|
||||
self._prop_mode,
|
||||
"value":
|
||||
self.get_map_key(
|
||||
map_=self._mode_map,value=kwargs[ATTR_EFFECT]),
|
||||
})
|
||||
# brightness
|
||||
if send_brightness_first and ATTR_BRIGHTNESS in kwargs:
|
||||
brightness = brightness_to_value(
|
||||
self._brightness_scale,kwargs[ATTR_BRIGHTNESS])
|
||||
set_properties_list.append({
|
||||
"prop": self._prop_brightness,
|
||||
"value": brightness
|
||||
})
|
||||
# color-temperature
|
||||
if ATTR_COLOR_TEMP_KELVIN in kwargs:
|
||||
set_properties_list.append({
|
||||
"prop": self._prop_color_temp,
|
||||
"value": kwargs[ATTR_COLOR_TEMP_KELVIN],
|
||||
})
|
||||
self._attr_color_mode = ColorMode.COLOR_TEMP
|
||||
# rgb color
|
||||
if ATTR_RGB_COLOR in kwargs:
|
||||
r = kwargs[ATTR_RGB_COLOR][0]
|
||||
g = kwargs[ATTR_RGB_COLOR][1]
|
||||
b = kwargs[ATTR_RGB_COLOR][2]
|
||||
rgb = (r << 16) | (g << 8) | b
|
||||
set_properties_list.append({
|
||||
"prop": self._prop_color,
|
||||
"value": rgb
|
||||
})
|
||||
self._attr_color_mode = ColorMode.RGB
|
||||
# brightness
|
||||
if not send_brightness_first and ATTR_BRIGHTNESS in kwargs:
|
||||
brightness = brightness_to_value(
|
||||
self._brightness_scale,kwargs[ATTR_BRIGHTNESS])
|
||||
set_properties_list.append({
|
||||
"prop": self._prop_brightness,
|
||||
"value": brightness
|
||||
})
|
||||
|
||||
await self.set_properties_async(set_properties_list,write_ha_state=False)
|
||||
self.async_write_ha_state()
|
||||
|
||||
else:
|
||||
if self._prop_on:
|
||||
value_on = True if self._prop_on.format_ == bool else 1
|
||||
await self.set_property_async(
|
||||
prop=self._prop_on, value=value_on)
|
||||
# brightness
|
||||
if ATTR_BRIGHTNESS in kwargs:
|
||||
brightness = brightness_to_value(
|
||||
self._brightness_scale, kwargs[ATTR_BRIGHTNESS])
|
||||
await self.set_property_async(
|
||||
prop=self._prop_brightness, value=brightness,
|
||||
write_ha_state=False)
|
||||
# color-temperature
|
||||
if ATTR_COLOR_TEMP_KELVIN in kwargs:
|
||||
await self.set_property_async(
|
||||
prop=self._prop_color_temp,
|
||||
value=kwargs[ATTR_COLOR_TEMP_KELVIN],
|
||||
write_ha_state=False)
|
||||
self._attr_color_mode = ColorMode.COLOR_TEMP
|
||||
# rgb color
|
||||
if ATTR_RGB_COLOR in kwargs:
|
||||
r = kwargs[ATTR_RGB_COLOR][0]
|
||||
g = kwargs[ATTR_RGB_COLOR][1]
|
||||
b = kwargs[ATTR_RGB_COLOR][2]
|
||||
rgb = (r << 16) | (g << 8) | b
|
||||
await self.set_property_async(
|
||||
prop=self._prop_color, value=rgb,
|
||||
write_ha_state=False)
|
||||
self._attr_color_mode = ColorMode.RGB
|
||||
# mode
|
||||
if ATTR_EFFECT in kwargs:
|
||||
await self.set_property_async(
|
||||
prop=self._prop_mode,
|
||||
value=self.get_map_key(
|
||||
map_=self._mode_map, value=kwargs[ATTR_EFFECT]),
|
||||
write_ha_state=False)
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_turn_off(self, **kwargs) -> None:
|
||||
"""Turn the light off."""
|
||||
|
||||
@ -46,7 +46,7 @@ off Xiaomi or its affiliates' products.
|
||||
MIoT client instance.
|
||||
"""
|
||||
from copy import deepcopy
|
||||
from typing import Any, Callable, Optional, final
|
||||
from typing import Any, Callable, Optional, final, Dict, List
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
@ -710,6 +710,84 @@ class MIoTClient:
|
||||
f'{self._i18n.translate("miot.client.device_exec_error")}, '
|
||||
f'{self._i18n.translate("error.common.-10007")}')
|
||||
|
||||
async def set_props_async(
|
||||
self, props_list: List[Dict[str, Any]],
|
||||
) -> bool:
|
||||
# props_list = [{'did': str, 'siid': int, 'piid': int, 'value': Any}......]
|
||||
# 判断是不是只有一个did
|
||||
did_set = {prop["did"] for prop in props_list}
|
||||
if len(did_set) != 1:
|
||||
raise MIoTClientError(f"more than one or no did once, {did_set}")
|
||||
did = did_set.pop()
|
||||
|
||||
if did not in self._device_list_cache:
|
||||
raise MIoTClientError(f"did not exist, {did}")
|
||||
# Priority local control
|
||||
if self._ctrl_mode == CtrlMode.AUTO:
|
||||
# Gateway control
|
||||
device_gw = self._device_list_gateway.get(did, None)
|
||||
if (
|
||||
device_gw and device_gw.get("online", False)
|
||||
and device_gw.get("specv2_access", False) and "group_id" in device_gw
|
||||
):
|
||||
mips = self._mips_local.get(device_gw["group_id"], None)
|
||||
if mips is None:
|
||||
_LOGGER.error(
|
||||
"no gateway route, %s, try control through cloud",
|
||||
device_gw)
|
||||
else:
|
||||
result = await mips.set_props_async(
|
||||
did=did,props_list=props_list)
|
||||
_LOGGER.debug("gateway set props, %s -> %s", props_list, result)
|
||||
rc = [(r or {}).get("code",
|
||||
MIoTErrorCode.CODE_MIPS_INVALID_RESULT.value)
|
||||
for r in result]
|
||||
if all(t in [0, 1] for t in rc):
|
||||
return True
|
||||
else:
|
||||
raise MIoTClientError(
|
||||
self.__get_exec_error_with_rc(rc=next(x for x in rc if x not in (0, 1))))
|
||||
# Lan control
|
||||
device_lan = self._device_list_lan.get(did, None)
|
||||
if device_lan and device_lan.get("online", False):
|
||||
result = await self._miot_lan.set_props_async(
|
||||
did=did, props_list=props_list)
|
||||
_LOGGER.debug("lan set props, %s -> %s", props_list, result)
|
||||
rc = [(r or {}).get("code",
|
||||
MIoTErrorCode.CODE_MIPS_INVALID_RESULT.value)
|
||||
for r in result]
|
||||
if all(t in [0, 1] for t in rc):
|
||||
return True
|
||||
else:
|
||||
raise MIoTClientError(
|
||||
self.__get_exec_error_with_rc(rc=next(x for x in rc if x not in (0, 1))))
|
||||
# Cloud control
|
||||
device_cloud = self._device_list_cloud.get(did, None)
|
||||
if device_cloud and device_cloud.get("online", False):
|
||||
result = await self._http.set_props_async(params=props_list)
|
||||
_LOGGER.debug(
|
||||
"cloud set props, %s, result, %s",
|
||||
props_list, result)
|
||||
if result and len(result) == len(props_list):
|
||||
rc = [(r or {}).get("code",
|
||||
MIoTErrorCode.CODE_MIPS_INVALID_RESULT.value)
|
||||
for r in result]
|
||||
if all(t in [0, 1] for t in rc):
|
||||
return True
|
||||
if any(t in [-704010000, -704042011] for t in rc):
|
||||
# Device remove or offline
|
||||
_LOGGER.error("device may be removed or offline, %s", did)
|
||||
self._main_loop.create_task(
|
||||
await
|
||||
self.__refresh_cloud_device_with_dids_async(dids=[did]))
|
||||
raise MIoTClientError(
|
||||
self.__get_exec_error_with_rc(rc=next(x for x in rc if x not in (0, 1))))
|
||||
|
||||
# Show error message
|
||||
raise MIoTClientError(
|
||||
f'{self._i18n.translate("miot.client.device_exec_error")}, '
|
||||
f'{self._i18n.translate("error.common.-10007")}')
|
||||
|
||||
def request_refresh_prop(
|
||||
self, did: str, siid: int, piid: int
|
||||
) -> None:
|
||||
|
||||
@ -825,6 +825,22 @@ class MIoTHttpClient:
|
||||
|
||||
return res_obj['result']
|
||||
|
||||
async def set_props_async(self, params: list) -> list:
|
||||
"""
|
||||
params = [{"did": "xxxx", "siid": 2, "piid": 1, "value": False}]
|
||||
"""
|
||||
res_obj = await self.__mihome_api_post_async(
|
||||
url_path='/app/v2/miotspec/prop/set',
|
||||
data={
|
||||
'params': params
|
||||
},
|
||||
timeout=15
|
||||
)
|
||||
if 'result' not in res_obj:
|
||||
raise MIoTHttpError('invalid response result')
|
||||
|
||||
return res_obj['result']
|
||||
|
||||
async def action_async(
|
||||
self, did: str, siid: int, aiid: int, in_list: list[dict]
|
||||
) -> dict:
|
||||
|
||||
@ -47,7 +47,7 @@ MIoT device instance.
|
||||
"""
|
||||
import asyncio
|
||||
from abc import abstractmethod
|
||||
from typing import Any, Callable, Optional
|
||||
from typing import Any, Callable, Optional, Dict, List
|
||||
import logging
|
||||
|
||||
from homeassistant.helpers.entity import Entity
|
||||
@ -1082,6 +1082,49 @@ class MIoTServiceEntity(Entity):
|
||||
self.async_write_ha_state()
|
||||
return True
|
||||
|
||||
async def set_properties_async(
|
||||
self, set_properties_list: List[Dict[str, Any]],
|
||||
update_value: bool = True, write_ha_state: bool = True,
|
||||
) -> bool:
|
||||
# set_properties_list = [{'prop': Optional[MIoTSpecProperty],
|
||||
# 'value': Any}....]
|
||||
for set_property in set_properties_list:
|
||||
prop = set_property.get("prop")
|
||||
value = set_property.get("value")
|
||||
if not prop:
|
||||
raise RuntimeError(
|
||||
f'set property failed, property is None, '
|
||||
f'{self.entity_id}, {self.name}')
|
||||
value = prop.value_format(value)
|
||||
value = prop.value_precision(value)
|
||||
# 因为下面还有判断在这个循环里 所以这里要赋值回去
|
||||
set_property["value"] = value
|
||||
if prop not in self.entity_data.props:
|
||||
raise RuntimeError(
|
||||
f'set property failed, unknown property, '
|
||||
f'{self.entity_id}, {self.name}, {prop.name}')
|
||||
if not prop.writable:
|
||||
raise RuntimeError(
|
||||
f'set property failed, not writable, '
|
||||
f'{self.entity_id}, {self.name}, {prop.name}')
|
||||
try:
|
||||
await self.miot_device.miot_client.set_props_async([{
|
||||
"did": self.miot_device.did,
|
||||
"siid": set_property["prop"].service.iid,
|
||||
"piid": set_property["prop"].iid,
|
||||
"value": set_property["value"],
|
||||
} for set_property in set_properties_list])
|
||||
except MIoTClientError as e:
|
||||
raise RuntimeError(
|
||||
f"{e}, {self.entity_id}, {self.name}, {'&'.join([set_property['prop'].name for set_property in set_properties_list])}") from e
|
||||
if update_value:
|
||||
for set_property in set_properties_list:
|
||||
self._prop_value_map[
|
||||
set_property["prop"]] = set_property["value"]
|
||||
if write_ha_state:
|
||||
self.async_write_ha_state()
|
||||
return True
|
||||
|
||||
async def get_property_async(self, prop: MIoTSpecProperty) -> Any:
|
||||
if not prop:
|
||||
_LOGGER.error(
|
||||
|
||||
@ -58,7 +58,7 @@ import secrets
|
||||
import socket
|
||||
import struct
|
||||
import threading
|
||||
from typing import Any, Callable, Coroutine, Optional, final
|
||||
from typing import Any, Callable, Coroutine, Optional, final, Dict, List
|
||||
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
||||
from cryptography.hazmat.primitives import padding
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
@ -857,6 +857,29 @@ class MIoTLan:
|
||||
return result_obj
|
||||
raise MIoTError('Invalid result', MIoTErrorCode.CODE_INTERNAL_ERROR)
|
||||
|
||||
@final
|
||||
async def set_props_async(
|
||||
self,did: str,props_list: List[Dict[str, Any]],
|
||||
timeout_ms: int = 10000) -> dict:
|
||||
# props_list = [{'did': did, 'siid': siid, 'piid': piid, 'value': value}......]
|
||||
self.__assert_service_ready()
|
||||
result_obj = await self.__call_api_async(
|
||||
did=did, msg={
|
||||
'method': 'set_properties',
|
||||
'params': props_list,
|
||||
}, timeout_ms=timeout_ms)
|
||||
if result_obj:
|
||||
if (
|
||||
'result' in result_obj and
|
||||
len(result_obj['result']) == len(props_list)
|
||||
and result_obj['result'][0].get('did') == did
|
||||
and all('code' in item for item in result_obj['result'])
|
||||
):
|
||||
return result_obj['result']
|
||||
if 'code' in result_obj:
|
||||
return result_obj
|
||||
raise MIoTError('Invalid result', MIoTErrorCode.CODE_INTERNAL_ERROR)
|
||||
|
||||
@final
|
||||
async def action_async(
|
||||
self, did: str, siid: int, aiid: int, in_list: list,
|
||||
|
||||
@ -56,7 +56,7 @@ import threading
|
||||
from abc import ABC, abstractmethod
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum, auto
|
||||
from typing import Any, Callable, Optional, final, Coroutine
|
||||
from typing import Any, Callable, Optional, final, Coroutine, Dict, List
|
||||
|
||||
from paho.mqtt.client import (
|
||||
MQTT_ERR_SUCCESS,
|
||||
@ -1342,6 +1342,41 @@ class MipsLocalClient(_MipsClient):
|
||||
'code': MIoTErrorCode.CODE_INTERNAL_ERROR.value,
|
||||
'message': 'Invalid result'}
|
||||
|
||||
@final
|
||||
async def set_props_async(
|
||||
self, did: str, props_list: List[Dict[str, Any]],
|
||||
timeout_ms: int = 10000
|
||||
) -> dict:
|
||||
# props_list= [{
|
||||
# 'did': did,
|
||||
# 'siid': siid,
|
||||
# 'piid': piid,
|
||||
# 'value': value
|
||||
# }]
|
||||
payload_obj: dict = {
|
||||
"did": did,
|
||||
"rpc": {
|
||||
"id": self.__gen_mips_id,
|
||||
"method": "set_properties",
|
||||
"params": props_list,
|
||||
}
|
||||
}
|
||||
result_obj = await self.__request_async(
|
||||
topic="proxy/rpcReq",
|
||||
payload=json.dumps(payload_obj),
|
||||
timeout_ms=timeout_ms)
|
||||
if result_obj:
|
||||
if ("result" in result_obj and
|
||||
len(result_obj["result"]) == len(props_list) and
|
||||
result_obj["result"][0].get("did") == did and
|
||||
all("code" in item for item in result_obj["result"])):
|
||||
return result_obj["result"]
|
||||
if "error" in result_obj:
|
||||
return result_obj["error"]
|
||||
return {
|
||||
'code': MIoTErrorCode.CODE_INTERNAL_ERROR.value,
|
||||
'message': 'Invalid result'}
|
||||
|
||||
@final
|
||||
async def action_async(
|
||||
self, did: str, siid: int, aiid: int, in_list: list,
|
||||
|
||||
@ -52,6 +52,8 @@ from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.components.select import SelectEntity
|
||||
from homeassistant.helpers.entity import EntityCategory
|
||||
from homeassistant.helpers.restore_state import RestoreEntity
|
||||
|
||||
from .miot.const import DOMAIN
|
||||
from .miot.miot_device import MIoTDevice, MIoTPropertyEntity
|
||||
@ -75,6 +77,17 @@ async def async_setup_entry(
|
||||
if new_entities:
|
||||
async_add_entities(new_entities)
|
||||
|
||||
# create select for light
|
||||
new_light_select_entities = []
|
||||
for miot_device in device_list:
|
||||
# Add it to all devices with light entities, because some bathroom heaters and clothes drying racks also have lights.
|
||||
# if "device:light" in miot_device.spec_instance.urn:
|
||||
if miot_device.entity_list.get("light", []):
|
||||
device_id = list(miot_device.device_info.get("identifiers"))[0][1]
|
||||
new_light_select_entities.append(
|
||||
LightCommandSendMode(hass=hass, device_id=device_id))
|
||||
if new_light_select_entities:
|
||||
async_add_entities(new_light_select_entities)
|
||||
|
||||
class Select(MIoTPropertyEntity, SelectEntity):
|
||||
"""Select entities for Xiaomi Home."""
|
||||
@ -94,3 +107,38 @@ class Select(MIoTPropertyEntity, SelectEntity):
|
||||
def current_option(self) -> Optional[str]:
|
||||
"""Return the current selected option."""
|
||||
return self.get_vlist_description(value=self._value)
|
||||
|
||||
|
||||
class LightCommandSendMode(SelectEntity, RestoreEntity):
|
||||
"""To control whether to turn on the light, you need to send the light-on command first and
|
||||
then send other color temperatures and brightness or send them all at the same time.
|
||||
The default is to send one by one."""
|
||||
|
||||
def __init__(self, hass: HomeAssistant, device_id: str):
|
||||
super().__init__()
|
||||
self.hass = hass
|
||||
self._device_id = device_id
|
||||
self._attr_name = "Command Send Mode"
|
||||
self.entity_id = f"select.light_{device_id}_command_send_mode"
|
||||
self._attr_unique_id = self.entity_id
|
||||
self._attr_options = [
|
||||
"Send One by One", "Send Turn On First", "Send Together"
|
||||
]
|
||||
self._attr_device_info = {"identifiers": {(DOMAIN, device_id)}}
|
||||
self._attr_current_option = self._attr_options[0]
|
||||
self._attr_entity_category = EntityCategory.CONFIG
|
||||
|
||||
async def async_select_option(self, option: str):
|
||||
if option in self._attr_options:
|
||||
self._attr_current_option = option
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
await super().async_added_to_hass()
|
||||
if (last_state := await self.async_get_last_state()
|
||||
) and last_state.state in self._attr_options:
|
||||
self._attr_current_option = last_state.state
|
||||
|
||||
@property
|
||||
def current_option(self):
|
||||
return self._attr_current_option
|
||||
|
||||
Loading…
Reference in New Issue
Block a user