Add YoLink Water Meter Support (#114148)
* Add YS-5006/5007/5008 Water Meter Support * Add YoLink Water Meter Support * Update .coveragerc * fix as suggestion
This commit is contained in:
parent
54a69a2687
commit
63b4fd09c1
6 changed files with 142 additions and 0 deletions
|
@ -1687,6 +1687,7 @@ omit =
|
||||||
homeassistant/components/yolink/services.py
|
homeassistant/components/yolink/services.py
|
||||||
homeassistant/components/yolink/siren.py
|
homeassistant/components/yolink/siren.py
|
||||||
homeassistant/components/yolink/switch.py
|
homeassistant/components/yolink/switch.py
|
||||||
|
homeassistant/components/yolink/valve.py
|
||||||
homeassistant/components/youless/__init__.py
|
homeassistant/components/youless/__init__.py
|
||||||
homeassistant/components/youless/sensor.py
|
homeassistant/components/youless/sensor.py
|
||||||
homeassistant/components/zabbix/*
|
homeassistant/components/zabbix/*
|
||||||
|
|
|
@ -46,6 +46,7 @@ PLATFORMS = [
|
||||||
Platform.SENSOR,
|
Platform.SENSOR,
|
||||||
Platform.SIREN,
|
Platform.SIREN,
|
||||||
Platform.SWITCH,
|
Platform.SWITCH,
|
||||||
|
Platform.VALVE,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -14,3 +14,5 @@ ATTR_REPEAT = "repeat"
|
||||||
ATTR_TONE = "tone"
|
ATTR_TONE = "tone"
|
||||||
YOLINK_EVENT = f"{DOMAIN}_event"
|
YOLINK_EVENT = f"{DOMAIN}_event"
|
||||||
YOLINK_OFFLINE_TIME = 32400
|
YOLINK_OFFLINE_TIME = 32400
|
||||||
|
|
||||||
|
DEV_MODEL_WATER_METER_YS5007 = "YS5007"
|
||||||
|
|
|
@ -24,6 +24,7 @@ from yolink.const import (
|
||||||
ATTR_DEVICE_THERMOSTAT,
|
ATTR_DEVICE_THERMOSTAT,
|
||||||
ATTR_DEVICE_VIBRATION_SENSOR,
|
ATTR_DEVICE_VIBRATION_SENSOR,
|
||||||
ATTR_DEVICE_WATER_DEPTH_SENSOR,
|
ATTR_DEVICE_WATER_DEPTH_SENSOR,
|
||||||
|
ATTR_DEVICE_WATER_METER_CONTROLLER,
|
||||||
ATTR_GARAGE_DOOR_CONTROLLER,
|
ATTR_GARAGE_DOOR_CONTROLLER,
|
||||||
)
|
)
|
||||||
from yolink.device import YoLinkDevice
|
from yolink.device import YoLinkDevice
|
||||||
|
@ -41,6 +42,7 @@ from homeassistant.const import (
|
||||||
EntityCategory,
|
EntityCategory,
|
||||||
UnitOfLength,
|
UnitOfLength,
|
||||||
UnitOfTemperature,
|
UnitOfTemperature,
|
||||||
|
UnitOfVolume,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
@ -76,6 +78,7 @@ SENSOR_DEVICE_TYPE = [
|
||||||
ATTR_DEVICE_THERMOSTAT,
|
ATTR_DEVICE_THERMOSTAT,
|
||||||
ATTR_DEVICE_VIBRATION_SENSOR,
|
ATTR_DEVICE_VIBRATION_SENSOR,
|
||||||
ATTR_DEVICE_WATER_DEPTH_SENSOR,
|
ATTR_DEVICE_WATER_DEPTH_SENSOR,
|
||||||
|
ATTR_DEVICE_WATER_METER_CONTROLLER,
|
||||||
ATTR_DEVICE_LOCK,
|
ATTR_DEVICE_LOCK,
|
||||||
ATTR_DEVICE_MANIPULATOR,
|
ATTR_DEVICE_MANIPULATOR,
|
||||||
ATTR_DEVICE_CO_SMOKE_SENSOR,
|
ATTR_DEVICE_CO_SMOKE_SENSOR,
|
||||||
|
@ -96,6 +99,7 @@ BATTERY_POWER_SENSOR = [
|
||||||
ATTR_DEVICE_MANIPULATOR,
|
ATTR_DEVICE_MANIPULATOR,
|
||||||
ATTR_DEVICE_CO_SMOKE_SENSOR,
|
ATTR_DEVICE_CO_SMOKE_SENSOR,
|
||||||
ATTR_DEVICE_WATER_DEPTH_SENSOR,
|
ATTR_DEVICE_WATER_DEPTH_SENSOR,
|
||||||
|
ATTR_DEVICE_WATER_METER_CONTROLLER,
|
||||||
]
|
]
|
||||||
|
|
||||||
MCU_DEV_TEMPERATURE_SENSOR = [
|
MCU_DEV_TEMPERATURE_SENSOR = [
|
||||||
|
@ -202,6 +206,17 @@ SENSOR_TYPES: tuple[YoLinkSensorEntityDescription, ...] = (
|
||||||
native_unit_of_measurement=UnitOfLength.METERS,
|
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 in ATTR_DEVICE_WATER_DEPTH_SENSOR,
|
||||||
),
|
),
|
||||||
|
YoLinkSensorEntityDescription(
|
||||||
|
key="meter_reading",
|
||||||
|
translation_key="water_meter_reading",
|
||||||
|
device_class=SensorDeviceClass.WATER,
|
||||||
|
icon="mdi:gauge",
|
||||||
|
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
|
||||||
|
in ATTR_DEVICE_WATER_METER_CONTROLLER,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -73,12 +73,20 @@
|
||||||
"enabled": "[%key:common::state::enabled%]",
|
"enabled": "[%key:common::state::enabled%]",
|
||||||
"disabled": "[%key:common::state::disabled%]"
|
"disabled": "[%key:common::state::disabled%]"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"water_meter_reading": {
|
||||||
|
"name": "Water meter reading"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"number": {
|
"number": {
|
||||||
"config_volume": {
|
"config_volume": {
|
||||||
"name": "Volume"
|
"name": "Volume"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"valve": {
|
||||||
|
"meter_valve_state": {
|
||||||
|
"name": "Valve state"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"services": {
|
"services": {
|
||||||
|
|
115
homeassistant/components/yolink/valve.py
Normal file
115
homeassistant/components/yolink/valve.py
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
"""YoLink Valve."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
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.device import YoLinkDevice
|
||||||
|
|
||||||
|
from homeassistant.components.valve import (
|
||||||
|
ValveDeviceClass,
|
||||||
|
ValveEntity,
|
||||||
|
ValveEntityDescription,
|
||||||
|
ValveEntityFeature,
|
||||||
|
)
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
from homeassistant.core import HomeAssistant, callback
|
||||||
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
|
from .const import DEV_MODEL_WATER_METER_YS5007, DOMAIN
|
||||||
|
from .coordinator import YoLinkCoordinator
|
||||||
|
from .entity import YoLinkEntity
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class YoLinkValveEntityDescription(ValveEntityDescription):
|
||||||
|
"""YoLink ValveEntityDescription."""
|
||||||
|
|
||||||
|
exists_fn: Callable[[YoLinkDevice], bool] = lambda _: True
|
||||||
|
value: Callable = lambda state: state
|
||||||
|
|
||||||
|
|
||||||
|
DEVICE_TYPES: tuple[YoLinkValveEntityDescription, ...] = (
|
||||||
|
YoLinkValveEntityDescription(
|
||||||
|
key="valve_state",
|
||||||
|
translation_key="meter_valve_state",
|
||||||
|
device_class=ValveDeviceClass.WATER,
|
||||||
|
value=lambda value: value == "closed" if value is not None else None,
|
||||||
|
exists_fn=lambda device: device.device_type
|
||||||
|
== ATTR_DEVICE_WATER_METER_CONTROLLER
|
||||||
|
and not device.device_model_name.startswith(DEV_MODEL_WATER_METER_YS5007),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
DEVICE_TYPE = [ATTR_DEVICE_WATER_METER_CONTROLLER]
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
config_entry: ConfigEntry,
|
||||||
|
async_add_entities: AddEntitiesCallback,
|
||||||
|
) -> None:
|
||||||
|
"""Set up YoLink valve from a config entry."""
|
||||||
|
device_coordinators = hass.data[DOMAIN][config_entry.entry_id].device_coordinators
|
||||||
|
valve_device_coordinators = [
|
||||||
|
device_coordinator
|
||||||
|
for device_coordinator in device_coordinators.values()
|
||||||
|
if device_coordinator.device.device_type in DEVICE_TYPE
|
||||||
|
]
|
||||||
|
async_add_entities(
|
||||||
|
YoLinkValveEntity(config_entry, valve_device_coordinator, description)
|
||||||
|
for valve_device_coordinator in valve_device_coordinators
|
||||||
|
for description in DEVICE_TYPES
|
||||||
|
if description.exists_fn(valve_device_coordinator.device)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class YoLinkValveEntity(YoLinkEntity, ValveEntity):
|
||||||
|
"""YoLink Valve Entity."""
|
||||||
|
|
||||||
|
entity_description: YoLinkValveEntityDescription
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
config_entry: ConfigEntry,
|
||||||
|
coordinator: YoLinkCoordinator,
|
||||||
|
description: YoLinkValveEntityDescription,
|
||||||
|
) -> None:
|
||||||
|
"""Init YoLink valve."""
|
||||||
|
super().__init__(config_entry, coordinator)
|
||||||
|
self._attr_supported_features = (
|
||||||
|
ValveEntityFeature.OPEN | ValveEntityFeature.CLOSE
|
||||||
|
)
|
||||||
|
self.entity_description = description
|
||||||
|
self._attr_unique_id = (
|
||||||
|
f"{coordinator.device.device_id} {self.entity_description.key}"
|
||||||
|
)
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def update_entity_state(self, state: dict[str, str | list[str]]) -> None:
|
||||||
|
"""Update HA Entity State."""
|
||||||
|
if (
|
||||||
|
attr_val := self.entity_description.value(
|
||||||
|
state.get(self.entity_description.key)
|
||||||
|
)
|
||||||
|
) is None:
|
||||||
|
return
|
||||||
|
self._attr_is_closed = attr_val
|
||||||
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
async def _async_invoke_device(self, state: str) -> None:
|
||||||
|
"""Call setState api to change valve state."""
|
||||||
|
await self.call_device(ClientRequest("setState", {"valve": state}))
|
||||||
|
self._attr_is_closed = state == "close"
|
||||||
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
async def async_open_valve(self) -> None:
|
||||||
|
"""Open the valve."""
|
||||||
|
await self._async_invoke_device("open")
|
||||||
|
|
||||||
|
async def async_close_valve(self) -> None:
|
||||||
|
"""Close valve."""
|
||||||
|
await self._async_invoke_device("close")
|
Loading…
Add table
Add a link
Reference in a new issue