mirror of
https://github.com/home-assistant/core.git
synced 2025-07-16 09:47:13 +00:00
Add YoLink new device types support 5009 & 5029 (#144323)
* Leak Stop * Fix as suggested.
This commit is contained in:
parent
3ff095cc51
commit
3f59b1c376
@ -26,7 +26,7 @@ from homeassistant.helpers import (
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
|
||||
from . import api
|
||||
from .const import DOMAIN, YOLINK_EVENT
|
||||
from .const import ATTR_LORA_INFO, DOMAIN, YOLINK_EVENT
|
||||
from .coordinator import YoLinkCoordinator
|
||||
from .device_trigger import CONF_LONG_PRESS, CONF_SHORT_PRESS
|
||||
from .services import async_register_services
|
||||
@ -72,6 +72,8 @@ class YoLinkHomeMessageListener(MessageListener):
|
||||
if device_coordinator is None:
|
||||
return
|
||||
device_coordinator.dev_online = True
|
||||
if (loraInfo := msg_data.get(ATTR_LORA_INFO)) is not None:
|
||||
device_coordinator.dev_net_type = loraInfo.get("devNetType")
|
||||
device_coordinator.async_set_updated_data(msg_data)
|
||||
# handling events
|
||||
if (
|
||||
|
@ -11,6 +11,7 @@ from yolink.const import (
|
||||
ATTR_DEVICE_DOOR_SENSOR,
|
||||
ATTR_DEVICE_LEAK_SENSOR,
|
||||
ATTR_DEVICE_MOTION_SENSOR,
|
||||
ATTR_DEVICE_MULTI_WATER_METER_CONTROLLER,
|
||||
ATTR_DEVICE_VIBRATION_SENSOR,
|
||||
ATTR_DEVICE_WATER_METER_CONTROLLER,
|
||||
)
|
||||
@ -51,6 +52,7 @@ SENSOR_DEVICE_TYPE = [
|
||||
ATTR_DEVICE_VIBRATION_SENSOR,
|
||||
ATTR_DEVICE_CO_SMOKE_SENSOR,
|
||||
ATTR_DEVICE_WATER_METER_CONTROLLER,
|
||||
ATTR_DEVICE_MULTI_WATER_METER_CONTROLLER,
|
||||
]
|
||||
|
||||
|
||||
@ -96,8 +98,14 @@ SENSOR_TYPES: tuple[YoLinkBinarySensorEntityDescription, ...] = (
|
||||
state_key="alarm",
|
||||
device_class=BinarySensorDeviceClass.MOISTURE,
|
||||
value=lambda state: state.get("leak") if state is not None else None,
|
||||
# This property will be lost during valve operation.
|
||||
should_update_entity=lambda value: value is not None,
|
||||
exists_fn=lambda device: (
|
||||
device.device_type == ATTR_DEVICE_WATER_METER_CONTROLLER
|
||||
device.device_type
|
||||
in [
|
||||
ATTR_DEVICE_WATER_METER_CONTROLLER,
|
||||
ATTR_DEVICE_MULTI_WATER_METER_CONTROLLER,
|
||||
]
|
||||
),
|
||||
),
|
||||
YoLinkBinarySensorEntityDescription(
|
||||
|
@ -12,6 +12,7 @@ ATTR_VOLUME = "volume"
|
||||
ATTR_TEXT_MESSAGE = "message"
|
||||
ATTR_REPEAT = "repeat"
|
||||
ATTR_TONE = "tone"
|
||||
ATTR_LORA_INFO = "loraInfo"
|
||||
YOLINK_EVENT = f"{DOMAIN}_event"
|
||||
YOLINK_OFFLINE_TIME = 32400
|
||||
|
||||
@ -37,5 +38,7 @@ DEV_MODEL_SWITCH_YS5708_UC = "YS5708-UC"
|
||||
DEV_MODEL_SWITCH_YS5708_EC = "YS5708-EC"
|
||||
DEV_MODEL_SWITCH_YS5709_UC = "YS5709-UC"
|
||||
DEV_MODEL_SWITCH_YS5709_EC = "YS5709-EC"
|
||||
DEV_MODEL_LEAK_STOP_YS5009 = "YS5009"
|
||||
DEV_MODEL_LEAK_STOP_YS5029 = "YS5029"
|
||||
DEV_MODEL_WATER_METER_YS5018_EC = "YS5018-EC"
|
||||
DEV_MODEL_WATER_METER_YS5018_UC = "YS5018-UC"
|
||||
|
@ -14,7 +14,7 @@ from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ConfigEntryAuthFailed
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||
|
||||
from .const import ATTR_DEVICE_STATE, DOMAIN, YOLINK_OFFLINE_TIME
|
||||
from .const import ATTR_DEVICE_STATE, ATTR_LORA_INFO, DOMAIN, YOLINK_OFFLINE_TIME
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@ -47,6 +47,7 @@ class YoLinkCoordinator(DataUpdateCoordinator[dict]):
|
||||
self.device = device
|
||||
self.paired_device = paired_device
|
||||
self.dev_online = True
|
||||
self.dev_net_type = None
|
||||
|
||||
async def _async_update_data(self) -> dict:
|
||||
"""Fetch device state."""
|
||||
@ -83,5 +84,8 @@ class YoLinkCoordinator(DataUpdateCoordinator[dict]):
|
||||
)
|
||||
raise UpdateFailed from yl_client_err
|
||||
if device_state is not None:
|
||||
dev_lora_info = device_state.get(ATTR_LORA_INFO)
|
||||
if dev_lora_info is not None:
|
||||
self.dev_net_type = dev_lora_info.get("devNetType")
|
||||
return device_state
|
||||
return {}
|
||||
|
@ -15,6 +15,7 @@ from yolink.const import (
|
||||
ATTR_DEVICE_MANIPULATOR,
|
||||
ATTR_DEVICE_MOTION_SENSOR,
|
||||
ATTR_DEVICE_MULTI_OUTLET,
|
||||
ATTR_DEVICE_MULTI_WATER_METER_CONTROLLER,
|
||||
ATTR_DEVICE_OUTLET,
|
||||
ATTR_DEVICE_POWER_FAILURE_ALARM,
|
||||
ATTR_DEVICE_SIREN,
|
||||
@ -95,6 +96,7 @@ SENSOR_DEVICE_TYPE = [
|
||||
ATTR_DEVICE_VIBRATION_SENSOR,
|
||||
ATTR_DEVICE_WATER_DEPTH_SENSOR,
|
||||
ATTR_DEVICE_WATER_METER_CONTROLLER,
|
||||
ATTR_DEVICE_MULTI_WATER_METER_CONTROLLER,
|
||||
ATTR_DEVICE_LOCK,
|
||||
ATTR_DEVICE_MANIPULATOR,
|
||||
ATTR_DEVICE_CO_SMOKE_SENSOR,
|
||||
@ -116,6 +118,7 @@ BATTERY_POWER_SENSOR = [
|
||||
ATTR_DEVICE_CO_SMOKE_SENSOR,
|
||||
ATTR_DEVICE_WATER_DEPTH_SENSOR,
|
||||
ATTR_DEVICE_WATER_METER_CONTROLLER,
|
||||
ATTR_DEVICE_MULTI_WATER_METER_CONTROLLER,
|
||||
]
|
||||
|
||||
MCU_DEV_TEMPERATURE_SENSOR = [
|
||||
@ -211,14 +214,14 @@ SENSOR_TYPES: tuple[YoLinkSensorEntityDescription, ...] = (
|
||||
translation_key="power_failure_alarm",
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
options=["normal", "alert", "off"],
|
||||
exists_fn=lambda device: device.device_type in ATTR_DEVICE_POWER_FAILURE_ALARM,
|
||||
exists_fn=lambda device: device.device_type == ATTR_DEVICE_POWER_FAILURE_ALARM,
|
||||
),
|
||||
YoLinkSensorEntityDescription(
|
||||
key="mute",
|
||||
translation_key="power_failure_alarm_mute",
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
options=["muted", "unmuted"],
|
||||
exists_fn=lambda device: device.device_type in ATTR_DEVICE_POWER_FAILURE_ALARM,
|
||||
exists_fn=lambda device: device.device_type == ATTR_DEVICE_POWER_FAILURE_ALARM,
|
||||
value=lambda value: "muted" if value is True else "unmuted",
|
||||
),
|
||||
YoLinkSensorEntityDescription(
|
||||
@ -226,7 +229,7 @@ SENSOR_TYPES: tuple[YoLinkSensorEntityDescription, ...] = (
|
||||
translation_key="power_failure_alarm_volume",
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
options=["low", "medium", "high"],
|
||||
exists_fn=lambda device: device.device_type in ATTR_DEVICE_POWER_FAILURE_ALARM,
|
||||
exists_fn=lambda device: device.device_type == ATTR_DEVICE_POWER_FAILURE_ALARM,
|
||||
value=cvt_volume,
|
||||
),
|
||||
YoLinkSensorEntityDescription(
|
||||
@ -234,14 +237,14 @@ SENSOR_TYPES: tuple[YoLinkSensorEntityDescription, ...] = (
|
||||
translation_key="power_failure_alarm_beep",
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
options=["enabled", "disabled"],
|
||||
exists_fn=lambda device: device.device_type in ATTR_DEVICE_POWER_FAILURE_ALARM,
|
||||
exists_fn=lambda device: device.device_type == ATTR_DEVICE_POWER_FAILURE_ALARM,
|
||||
value=lambda value: "enabled" if value is True else "disabled",
|
||||
),
|
||||
YoLinkSensorEntityDescription(
|
||||
key="waterDepth",
|
||||
device_class=SensorDeviceClass.DISTANCE,
|
||||
native_unit_of_measurement=UnitOfLength.METERS,
|
||||
exists_fn=lambda device: device.device_type in ATTR_DEVICE_WATER_DEPTH_SENSOR,
|
||||
exists_fn=lambda device: device.device_type == ATTR_DEVICE_WATER_DEPTH_SENSOR,
|
||||
),
|
||||
YoLinkSensorEntityDescription(
|
||||
key="meter_reading",
|
||||
@ -251,7 +254,29 @@ SENSOR_TYPES: tuple[YoLinkSensorEntityDescription, ...] = (
|
||||
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||
should_update_entity=lambda value: value is not None,
|
||||
exists_fn=lambda device: (
|
||||
device.device_type in ATTR_DEVICE_WATER_METER_CONTROLLER
|
||||
device.device_type == ATTR_DEVICE_WATER_METER_CONTROLLER
|
||||
),
|
||||
),
|
||||
YoLinkSensorEntityDescription(
|
||||
key="meter_1_reading",
|
||||
translation_key="water_meter_1_reading",
|
||||
device_class=SensorDeviceClass.WATER,
|
||||
native_unit_of_measurement=UnitOfVolume.CUBIC_METERS,
|
||||
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||
should_update_entity=lambda value: value is not None,
|
||||
exists_fn=lambda device: (
|
||||
device.device_type == ATTR_DEVICE_MULTI_WATER_METER_CONTROLLER
|
||||
),
|
||||
),
|
||||
YoLinkSensorEntityDescription(
|
||||
key="meter_2_reading",
|
||||
translation_key="water_meter_2_reading",
|
||||
device_class=SensorDeviceClass.WATER,
|
||||
native_unit_of_measurement=UnitOfVolume.CUBIC_METERS,
|
||||
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||
should_update_entity=lambda value: value is not None,
|
||||
exists_fn=lambda device: (
|
||||
device.device_type == ATTR_DEVICE_MULTI_WATER_METER_CONTROLLER
|
||||
),
|
||||
),
|
||||
YoLinkSensorEntityDescription(
|
||||
|
@ -90,6 +90,12 @@
|
||||
},
|
||||
"water_meter_reading": {
|
||||
"name": "Water meter reading"
|
||||
},
|
||||
"water_meter_1_reading": {
|
||||
"name": "Water meter 1 reading"
|
||||
},
|
||||
"water_meter_2_reading": {
|
||||
"name": "Water meter 2 reading"
|
||||
}
|
||||
},
|
||||
"number": {
|
||||
@ -100,6 +106,12 @@
|
||||
"valve": {
|
||||
"meter_valve_state": {
|
||||
"name": "Valve state"
|
||||
},
|
||||
"meter_valve_1_state": {
|
||||
"name": "Valve 1"
|
||||
},
|
||||
"meter_valve_2_state": {
|
||||
"name": "Valve 2"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -6,7 +6,11 @@ from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
|
||||
from yolink.client_request import ClientRequest
|
||||
from yolink.const import ATTR_DEVICE_WATER_METER_CONTROLLER
|
||||
from yolink.const import (
|
||||
ATTR_DEVICE_MODEL_A,
|
||||
ATTR_DEVICE_MULTI_WATER_METER_CONTROLLER,
|
||||
ATTR_DEVICE_WATER_METER_CONTROLLER,
|
||||
)
|
||||
from yolink.device import YoLinkDevice
|
||||
|
||||
from homeassistant.components.valve import (
|
||||
@ -30,6 +34,7 @@ class YoLinkValveEntityDescription(ValveEntityDescription):
|
||||
|
||||
exists_fn: Callable[[YoLinkDevice], bool] = lambda _: True
|
||||
value: Callable = lambda state: state
|
||||
channel_index: int | None = None
|
||||
|
||||
|
||||
DEVICE_TYPES: tuple[YoLinkValveEntityDescription, ...] = (
|
||||
@ -42,9 +47,32 @@ DEVICE_TYPES: tuple[YoLinkValveEntityDescription, ...] = (
|
||||
== ATTR_DEVICE_WATER_METER_CONTROLLER
|
||||
and not device.device_model_name.startswith(DEV_MODEL_WATER_METER_YS5007),
|
||||
),
|
||||
YoLinkValveEntityDescription(
|
||||
key="valve_1_state",
|
||||
translation_key="meter_valve_1_state",
|
||||
device_class=ValveDeviceClass.WATER,
|
||||
value=lambda value: value != "open" if value is not None else None,
|
||||
exists_fn=lambda device: (
|
||||
device.device_type == ATTR_DEVICE_MULTI_WATER_METER_CONTROLLER
|
||||
),
|
||||
channel_index=0,
|
||||
),
|
||||
YoLinkValveEntityDescription(
|
||||
key="valve_2_state",
|
||||
translation_key="meter_valve_2_state",
|
||||
device_class=ValveDeviceClass.WATER,
|
||||
value=lambda value: value != "open" if value is not None else None,
|
||||
exists_fn=lambda device: (
|
||||
device.device_type == ATTR_DEVICE_MULTI_WATER_METER_CONTROLLER
|
||||
),
|
||||
channel_index=1,
|
||||
),
|
||||
)
|
||||
|
||||
DEVICE_TYPE = [ATTR_DEVICE_WATER_METER_CONTROLLER]
|
||||
DEVICE_TYPE = [
|
||||
ATTR_DEVICE_WATER_METER_CONTROLLER,
|
||||
ATTR_DEVICE_MULTI_WATER_METER_CONTROLLER,
|
||||
]
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
@ -102,7 +130,17 @@ class YoLinkValveEntity(YoLinkEntity, ValveEntity):
|
||||
|
||||
async def _async_invoke_device(self, state: str) -> None:
|
||||
"""Call setState api to change valve state."""
|
||||
await self.call_device(ClientRequest("setState", {"valve": state}))
|
||||
if (
|
||||
self.coordinator.device.device_type
|
||||
== ATTR_DEVICE_MULTI_WATER_METER_CONTROLLER
|
||||
):
|
||||
channel_index = self.entity_description.channel_index
|
||||
if channel_index is not None:
|
||||
await self.call_device(
|
||||
ClientRequest("setState", {"valves": {str(channel_index): state}})
|
||||
)
|
||||
else:
|
||||
await self.call_device(ClientRequest("setState", {"valve": state}))
|
||||
self._attr_is_closed = state == "close"
|
||||
self.async_write_ha_state()
|
||||
|
||||
@ -113,3 +151,11 @@ class YoLinkValveEntity(YoLinkEntity, ValveEntity):
|
||||
async def async_close_valve(self) -> None:
|
||||
"""Close valve."""
|
||||
await self._async_invoke_device("close")
|
||||
|
||||
@property
|
||||
def available(self) -> bool:
|
||||
"""Return true is device is available."""
|
||||
if self.coordinator.dev_net_type is not None:
|
||||
# When the device operates in Class A mode, it cannot be controlled.
|
||||
return self.coordinator.dev_net_type != ATTR_DEVICE_MODEL_A
|
||||
return super().available
|
||||
|
Loading…
x
Reference in New Issue
Block a user