mirror of
https://github.com/home-assistant/core.git
synced 2025-07-21 12:17:07 +00:00
parent
032940f1a9
commit
fb96ef99d0
@ -14,7 +14,7 @@ from .const import DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
PLATFORMS = [Platform.COVER]
|
||||
PLATFORMS = [Platform.COVER, Platform.SENSOR]
|
||||
|
||||
type HomeeConfigEntry = ConfigEntry[Homee]
|
||||
|
||||
|
@ -1,4 +1,60 @@
|
||||
"""Constants for the homee integration."""
|
||||
|
||||
from homeassistant.const import (
|
||||
LIGHT_LUX,
|
||||
PERCENTAGE,
|
||||
UnitOfElectricCurrent,
|
||||
UnitOfElectricPotential,
|
||||
UnitOfEnergy,
|
||||
UnitOfPower,
|
||||
UnitOfSpeed,
|
||||
UnitOfTemperature,
|
||||
UnitOfTime,
|
||||
UnitOfVolume,
|
||||
)
|
||||
|
||||
# General
|
||||
DOMAIN = "homee"
|
||||
|
||||
# Sensor mappings
|
||||
HOMEE_UNIT_TO_HA_UNIT = {
|
||||
"": None,
|
||||
"n/a": None,
|
||||
"text": None,
|
||||
"%": PERCENTAGE,
|
||||
"lx": LIGHT_LUX,
|
||||
"klx": LIGHT_LUX,
|
||||
"A": UnitOfElectricCurrent.AMPERE,
|
||||
"V": UnitOfElectricPotential.VOLT,
|
||||
"kWh": UnitOfEnergy.KILO_WATT_HOUR,
|
||||
"W": UnitOfPower.WATT,
|
||||
"m/s": UnitOfSpeed.METERS_PER_SECOND,
|
||||
"km/h": UnitOfSpeed.KILOMETERS_PER_HOUR,
|
||||
"°F": UnitOfTemperature.FAHRENHEIT,
|
||||
"°C": UnitOfTemperature.CELSIUS,
|
||||
"K": UnitOfTemperature.KELVIN,
|
||||
"s": UnitOfTime.SECONDS,
|
||||
"min": UnitOfTime.MINUTES,
|
||||
"h": UnitOfTime.HOURS,
|
||||
"L": UnitOfVolume.LITERS,
|
||||
}
|
||||
OPEN_CLOSE_MAP = {
|
||||
0.0: "open",
|
||||
1.0: "closed",
|
||||
2.0: "partial",
|
||||
3.0: "opening",
|
||||
4.0: "closing",
|
||||
}
|
||||
OPEN_CLOSE_MAP_REVERSED = {
|
||||
0.0: "closed",
|
||||
1.0: "open",
|
||||
2.0: "partial",
|
||||
3.0: "cosing",
|
||||
4.0: "opening",
|
||||
}
|
||||
WINDOW_MAP = {
|
||||
0.0: "closed",
|
||||
1.0: "open",
|
||||
2.0: "tilted",
|
||||
}
|
||||
WINDOW_MAP_REVERSED = {0.0: "open", 1.0: "closed", 2.0: "tilted"}
|
||||
|
@ -1,6 +1,6 @@
|
||||
"""Base Entities for Homee integration."""
|
||||
|
||||
from pyHomee.const import AttributeType, NodeProfile, NodeState
|
||||
from pyHomee.const import AttributeState, AttributeType, NodeProfile, NodeState
|
||||
from pyHomee.model import HomeeAttribute, HomeeNode
|
||||
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
@ -11,6 +11,56 @@ from .const import DOMAIN
|
||||
from .helpers import get_name_for_enum
|
||||
|
||||
|
||||
class HomeeEntity(Entity):
|
||||
"""Represents a Homee entity consisting of a single HomeeAttribute."""
|
||||
|
||||
_attr_has_entity_name = True
|
||||
_attr_should_poll = False
|
||||
|
||||
def __init__(self, attribute: HomeeAttribute, entry: HomeeConfigEntry) -> None:
|
||||
"""Initialize the wrapper using a HomeeAttribute and target entity."""
|
||||
self._attribute = attribute
|
||||
self._attr_unique_id = (
|
||||
f"{entry.runtime_data.settings.uid}-{attribute.node_id}-{attribute.id}"
|
||||
)
|
||||
self._entry = entry
|
||||
self._attr_device_info = DeviceInfo(
|
||||
identifiers={
|
||||
(DOMAIN, f"{entry.runtime_data.settings.uid}-{attribute.node_id}")
|
||||
}
|
||||
)
|
||||
|
||||
self._host_connected = entry.runtime_data.connected
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Add the homee attribute entity to home assistant."""
|
||||
self.async_on_remove(
|
||||
self._attribute.add_on_changed_listener(self._on_node_updated)
|
||||
)
|
||||
self.async_on_remove(
|
||||
await self._entry.runtime_data.add_connection_listener(
|
||||
self._on_connection_changed
|
||||
)
|
||||
)
|
||||
|
||||
@property
|
||||
def available(self) -> bool:
|
||||
"""Return the availability of the underlying node."""
|
||||
return (self._attribute.state == AttributeState.NORMAL) and self._host_connected
|
||||
|
||||
async def async_update(self) -> None:
|
||||
"""Update entity from homee."""
|
||||
homee = self._entry.runtime_data
|
||||
await homee.update_attribute(self._attribute.node_id, self._attribute.id)
|
||||
|
||||
def _on_node_updated(self, attribute: HomeeAttribute) -> None:
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
async def _on_connection_changed(self, connected: bool) -> None:
|
||||
self._host_connected = connected
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
|
||||
class HomeeNodeEntity(Entity):
|
||||
"""Representation of an Entity that uses more than one HomeeAttribute."""
|
||||
|
||||
@ -20,7 +70,7 @@ class HomeeNodeEntity(Entity):
|
||||
def __init__(self, node: HomeeNode, entry: HomeeConfigEntry) -> None:
|
||||
"""Initialize the wrapper using a HomeeNode and target entity."""
|
||||
self._node = node
|
||||
self._attr_unique_id = f"{entry.runtime_data.settings.uid}-{node.id}"
|
||||
self._attr_unique_id = f"{entry.unique_id}-{node.id}"
|
||||
self._entry = entry
|
||||
|
||||
self._attr_device_info = DeviceInfo(
|
||||
@ -41,6 +91,23 @@ class HomeeNodeEntity(Entity):
|
||||
)
|
||||
)
|
||||
|
||||
@property
|
||||
def device_info(self) -> DeviceInfo:
|
||||
"""Return the device info."""
|
||||
# Homee hub has id -1, but is identified only by the UID.
|
||||
if self._node.id == -1:
|
||||
return DeviceInfo(
|
||||
identifiers={(DOMAIN, self._entry.runtime_data.settings.uid)},
|
||||
)
|
||||
|
||||
return DeviceInfo(
|
||||
identifiers={(DOMAIN, f"{self._entry.unique_id}-{self._node.id}")},
|
||||
name=self._node.name,
|
||||
model=get_name_for_enum(NodeProfile, self._node.profile),
|
||||
sw_version=self._get_software_version(),
|
||||
via_device=(DOMAIN, self._entry.runtime_data.settings.uid),
|
||||
)
|
||||
|
||||
@property
|
||||
def available(self) -> bool:
|
||||
"""Return the availability of the underlying node."""
|
||||
|
@ -1,16 +1,16 @@
|
||||
"""Helper functions for the homee custom component."""
|
||||
|
||||
from enum import IntEnum
|
||||
import logging
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_name_for_enum(att_class, att_id) -> str:
|
||||
def get_name_for_enum(att_class: type[IntEnum], att_id: int) -> str | None:
|
||||
"""Return the enum item name for a given integer."""
|
||||
try:
|
||||
attribute_name = att_class(att_id).name
|
||||
item = att_class(att_id)
|
||||
except ValueError:
|
||||
_LOGGER.warning("Value %s does not exist in %s", att_id, att_class.__name__)
|
||||
return "Unknown"
|
||||
|
||||
return attribute_name
|
||||
return None
|
||||
return item.name.lower()
|
||||
|
12
homeassistant/components/homee/icons.json
Normal file
12
homeassistant/components/homee/icons.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"entity": {
|
||||
"sensor": {
|
||||
"link_quality": {
|
||||
"default": "mdi:signal"
|
||||
},
|
||||
"window_position": {
|
||||
"default": "mdi:window-closed"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
303
homeassistant/components/homee/sensor.py
Normal file
303
homeassistant/components/homee/sensor.py
Normal file
@ -0,0 +1,303 @@
|
||||
"""The homee sensor platform."""
|
||||
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
|
||||
from pyHomee.const import AttributeType, NodeState
|
||||
from pyHomee.model import HomeeAttribute, HomeeNode
|
||||
|
||||
from homeassistant.components.sensor import (
|
||||
SensorDeviceClass,
|
||||
SensorEntity,
|
||||
SensorEntityDescription,
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from . import HomeeConfigEntry
|
||||
from .const import (
|
||||
HOMEE_UNIT_TO_HA_UNIT,
|
||||
OPEN_CLOSE_MAP,
|
||||
OPEN_CLOSE_MAP_REVERSED,
|
||||
WINDOW_MAP,
|
||||
WINDOW_MAP_REVERSED,
|
||||
)
|
||||
from .entity import HomeeEntity, HomeeNodeEntity
|
||||
from .helpers import get_name_for_enum
|
||||
|
||||
|
||||
def get_open_close_value(attribute: HomeeAttribute) -> str | None:
|
||||
"""Return the open/close value."""
|
||||
vals = OPEN_CLOSE_MAP if not attribute.is_reversed else OPEN_CLOSE_MAP_REVERSED
|
||||
return vals.get(attribute.current_value)
|
||||
|
||||
|
||||
def get_window_value(attribute: HomeeAttribute) -> str | None:
|
||||
"""Return the states of a window open sensor."""
|
||||
vals = WINDOW_MAP if not attribute.is_reversed else WINDOW_MAP_REVERSED
|
||||
return vals.get(attribute.current_value)
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class HomeeSensorEntityDescription(SensorEntityDescription):
|
||||
"""A class that describes Homee sensor entities."""
|
||||
|
||||
value_fn: Callable[[HomeeAttribute], str | float | None] = (
|
||||
lambda value: value.current_value
|
||||
)
|
||||
native_unit_of_measurement_fn: Callable[[str], str | None] = (
|
||||
lambda homee_unit: HOMEE_UNIT_TO_HA_UNIT[homee_unit]
|
||||
)
|
||||
|
||||
|
||||
SENSOR_DESCRIPTIONS: dict[AttributeType, HomeeSensorEntityDescription] = {
|
||||
AttributeType.ACCUMULATED_ENERGY_USE: HomeeSensorEntityDescription(
|
||||
key="energy",
|
||||
device_class=SensorDeviceClass.ENERGY,
|
||||
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||
),
|
||||
AttributeType.BATTERY_LEVEL: HomeeSensorEntityDescription(
|
||||
key="battery",
|
||||
device_class=SensorDeviceClass.BATTERY,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
AttributeType.BRIGHTNESS: HomeeSensorEntityDescription(
|
||||
key="brightness",
|
||||
device_class=SensorDeviceClass.ILLUMINANCE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=(
|
||||
lambda attribute: attribute.current_value * 1000
|
||||
if attribute.unit == "klx"
|
||||
else attribute.current_value
|
||||
),
|
||||
),
|
||||
AttributeType.CURRENT: HomeeSensorEntityDescription(
|
||||
key="current",
|
||||
device_class=SensorDeviceClass.CURRENT,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
AttributeType.CURRENT_ENERGY_USE: HomeeSensorEntityDescription(
|
||||
key="power",
|
||||
device_class=SensorDeviceClass.POWER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
AttributeType.CURRENT_VALVE_POSITION: HomeeSensorEntityDescription(
|
||||
key="valve_position",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
AttributeType.DAWN: HomeeSensorEntityDescription(
|
||||
key="dawn",
|
||||
device_class=SensorDeviceClass.ILLUMINANCE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
AttributeType.DEVICE_TEMPERATURE: HomeeSensorEntityDescription(
|
||||
key="device_temperature",
|
||||
device_class=SensorDeviceClass.TEMPERATURE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
AttributeType.LEVEL: HomeeSensorEntityDescription(
|
||||
key="level",
|
||||
device_class=SensorDeviceClass.VOLUME,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
AttributeType.LINK_QUALITY: HomeeSensorEntityDescription(
|
||||
key="link_quality",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
AttributeType.POSITION: HomeeSensorEntityDescription(
|
||||
key="position",
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
AttributeType.RAIN_FALL_LAST_HOUR: HomeeSensorEntityDescription(
|
||||
key="rainfall_hour",
|
||||
device_class=SensorDeviceClass.PRECIPITATION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
AttributeType.RAIN_FALL_TODAY: HomeeSensorEntityDescription(
|
||||
key="rainfall_day",
|
||||
device_class=SensorDeviceClass.PRECIPITATION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
AttributeType.RELATIVE_HUMIDITY: HomeeSensorEntityDescription(
|
||||
key="humidity",
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
AttributeType.TEMPERATURE: HomeeSensorEntityDescription(
|
||||
key="temperature",
|
||||
device_class=SensorDeviceClass.TEMPERATURE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
AttributeType.TOTAL_ACCUMULATED_ENERGY_USE: HomeeSensorEntityDescription(
|
||||
key="total_energy",
|
||||
device_class=SensorDeviceClass.ENERGY,
|
||||
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||
),
|
||||
AttributeType.TOTAL_CURRENT: HomeeSensorEntityDescription(
|
||||
key="total_current",
|
||||
device_class=SensorDeviceClass.CURRENT,
|
||||
),
|
||||
AttributeType.TOTAL_CURRENT_ENERGY_USE: HomeeSensorEntityDescription(
|
||||
key="total_power",
|
||||
device_class=SensorDeviceClass.POWER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
AttributeType.TOTAL_VOLTAGE: HomeeSensorEntityDescription(
|
||||
key="total_voltage",
|
||||
device_class=SensorDeviceClass.VOLTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
AttributeType.UP_DOWN: HomeeSensorEntityDescription(
|
||||
key="up_down",
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
options=[
|
||||
"open",
|
||||
"closed",
|
||||
"partial",
|
||||
"opening",
|
||||
"closing",
|
||||
],
|
||||
value_fn=get_open_close_value,
|
||||
),
|
||||
AttributeType.UV: HomeeSensorEntityDescription(
|
||||
key="uv",
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
AttributeType.VOLTAGE: HomeeSensorEntityDescription(
|
||||
key="voltage",
|
||||
device_class=SensorDeviceClass.VOLTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
AttributeType.WIND_SPEED: HomeeSensorEntityDescription(
|
||||
key="wind_speed",
|
||||
device_class=SensorDeviceClass.WIND_SPEED,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
AttributeType.WINDOW_POSITION: HomeeSensorEntityDescription(
|
||||
key="window_position",
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
options=["closed", "open", "tilted"],
|
||||
value_fn=get_window_value,
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class HomeeNodeSensorEntityDescription(SensorEntityDescription):
|
||||
"""Describes Homee node sensor entities."""
|
||||
|
||||
value_fn: Callable[[HomeeNode], str | None]
|
||||
|
||||
|
||||
NODE_SENSOR_DESCRIPTIONS: tuple[HomeeNodeSensorEntityDescription, ...] = (
|
||||
HomeeNodeSensorEntityDescription(
|
||||
key="state",
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
options=[
|
||||
"available",
|
||||
"unavailable",
|
||||
"update_in_progress",
|
||||
"waiting_for_attributes",
|
||||
"initializing",
|
||||
"user_interaction_required",
|
||||
"password_required",
|
||||
"host_unavailable",
|
||||
"delete_in_progress",
|
||||
"cosi_connected",
|
||||
"blocked",
|
||||
"waiting_for_wakeup",
|
||||
"remote_node_deleted",
|
||||
"firmware_update_in_progress",
|
||||
],
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
entity_registry_enabled_default=False,
|
||||
value_fn=lambda node: get_name_for_enum(NodeState, node.state),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: HomeeConfigEntry,
|
||||
async_add_devices: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Add the homee platform for the sensor components."""
|
||||
|
||||
devices: list[HomeeSensor | HomeeNodeSensor] = []
|
||||
for node in config_entry.runtime_data.nodes:
|
||||
# Node properties that are sensors.
|
||||
devices.extend(
|
||||
HomeeNodeSensor(node, config_entry, description)
|
||||
for description in NODE_SENSOR_DESCRIPTIONS
|
||||
)
|
||||
|
||||
# Node attributes that are sensors.
|
||||
devices.extend(
|
||||
HomeeSensor(attribute, config_entry, SENSOR_DESCRIPTIONS[attribute.type])
|
||||
for attribute in node.attributes
|
||||
if attribute.type in SENSOR_DESCRIPTIONS and not attribute.editable
|
||||
)
|
||||
|
||||
if devices:
|
||||
async_add_devices(devices)
|
||||
|
||||
|
||||
class HomeeSensor(HomeeEntity, SensorEntity):
|
||||
"""Representation of a homee sensor."""
|
||||
|
||||
entity_description: HomeeSensorEntityDescription
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
attribute: HomeeAttribute,
|
||||
entry: HomeeConfigEntry,
|
||||
description: HomeeSensorEntityDescription,
|
||||
) -> None:
|
||||
"""Initialize a homee sensor entity."""
|
||||
super().__init__(attribute, entry)
|
||||
self.entity_description = description
|
||||
self._attr_translation_key = description.key
|
||||
if attribute.instance > 0:
|
||||
self._attr_translation_key = f"{description.translation_key}_instance"
|
||||
self._attr_translation_placeholders = {"instance": str(attribute.instance)}
|
||||
|
||||
@property
|
||||
def native_value(self) -> float | str | None:
|
||||
"""Return the native value of the sensor."""
|
||||
return self.entity_description.value_fn(self._attribute)
|
||||
|
||||
@property
|
||||
def native_unit_of_measurement(self) -> str | None:
|
||||
"""Return the native unit of the sensor."""
|
||||
return self.entity_description.native_unit_of_measurement_fn(
|
||||
self._attribute.unit
|
||||
)
|
||||
|
||||
|
||||
class HomeeNodeSensor(HomeeNodeEntity, SensorEntity):
|
||||
"""Represents a sensor based on a node's property."""
|
||||
|
||||
entity_description: HomeeNodeSensorEntityDescription
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
node: HomeeNode,
|
||||
entry: HomeeConfigEntry,
|
||||
description: HomeeNodeSensorEntityDescription,
|
||||
) -> None:
|
||||
"""Initialize a homee node sensor entity."""
|
||||
super().__init__(node, entry)
|
||||
self.entity_description = description
|
||||
self._attr_translation_key = f"node_{description.key}"
|
||||
self._node = node
|
||||
self._attr_unique_id = f"{self._attr_unique_id}-{description.key}"
|
||||
|
||||
@property
|
||||
def native_value(self) -> str | None:
|
||||
"""Return the sensors value."""
|
||||
return self.entity_description.value_fn(self._node)
|
@ -24,5 +24,84 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"entity": {
|
||||
"sensor": {
|
||||
"brightness_instance": {
|
||||
"name": "Illuminance {instance}"
|
||||
},
|
||||
"current_instance": {
|
||||
"name": "Current {instance}"
|
||||
},
|
||||
"dawn": {
|
||||
"name": "Dawn"
|
||||
},
|
||||
"device_temperature": {
|
||||
"name": "Device temperature"
|
||||
},
|
||||
"energy_instance": {
|
||||
"name": "Energy {instance}"
|
||||
},
|
||||
"level": {
|
||||
"name": "Level"
|
||||
},
|
||||
"link_quality": {
|
||||
"name": "Link quality"
|
||||
},
|
||||
"node_state": {
|
||||
"name": "Node state"
|
||||
},
|
||||
"position": {
|
||||
"name": "Position"
|
||||
},
|
||||
"power_instance": {
|
||||
"name": "Power {instance}"
|
||||
},
|
||||
"rainfall_hour": {
|
||||
"name": "Rainfall last hour"
|
||||
},
|
||||
"rainfall_day": {
|
||||
"name": "Rainfall today"
|
||||
},
|
||||
"total_current": {
|
||||
"name": "Total current"
|
||||
},
|
||||
"total_energy": {
|
||||
"name": "Total energy"
|
||||
},
|
||||
"total_power": {
|
||||
"name": "Total power"
|
||||
},
|
||||
"total_voltage": {
|
||||
"name": "Total voltage"
|
||||
},
|
||||
"up_down": {
|
||||
"name": "State",
|
||||
"state": {
|
||||
"open": "[%key:common::state::open%]",
|
||||
"closed": "[%key:common::state::closed%]",
|
||||
"partial": "Partially open",
|
||||
"opening": "Opening",
|
||||
"closing": "Closing"
|
||||
}
|
||||
},
|
||||
"uv": {
|
||||
"name": "Ultraviolet"
|
||||
},
|
||||
"valve_position": {
|
||||
"name": "Valve position"
|
||||
},
|
||||
"voltage_instance": {
|
||||
"name": "Voltage {instance}"
|
||||
},
|
||||
"window_position": {
|
||||
"name": "Window position",
|
||||
"state": {
|
||||
"closed": "[%key:common::state::closed%]",
|
||||
"open": "[%key:common::state::open%]",
|
||||
"tilted": "Tilted"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user