Add more mysensors sensor attributes (#53566)
This commit is contained in:
parent
27d42e0cd8
commit
a133eae88e
5 changed files with 141 additions and 45 deletions
|
@ -1,16 +1,27 @@
|
||||||
"""Support for MySensors sensors."""
|
"""Support for MySensors sensors."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
from awesomeversion import AwesomeVersion
|
from awesomeversion import AwesomeVersion
|
||||||
|
|
||||||
from homeassistant.components import mysensors
|
from homeassistant.components import mysensors
|
||||||
from homeassistant.components.sensor import DOMAIN, SensorEntity
|
from homeassistant.components.sensor import (
|
||||||
|
DOMAIN,
|
||||||
|
STATE_CLASS_MEASUREMENT,
|
||||||
|
SensorEntity,
|
||||||
|
)
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONDUCTIVITY,
|
CONDUCTIVITY,
|
||||||
DEGREE,
|
DEGREE,
|
||||||
|
DEVICE_CLASS_CURRENT,
|
||||||
|
DEVICE_CLASS_ENERGY,
|
||||||
DEVICE_CLASS_HUMIDITY,
|
DEVICE_CLASS_HUMIDITY,
|
||||||
|
DEVICE_CLASS_ILLUMINANCE,
|
||||||
|
DEVICE_CLASS_POWER,
|
||||||
DEVICE_CLASS_TEMPERATURE,
|
DEVICE_CLASS_TEMPERATURE,
|
||||||
|
DEVICE_CLASS_VOLTAGE,
|
||||||
ELECTRIC_CURRENT_AMPERE,
|
ELECTRIC_CURRENT_AMPERE,
|
||||||
ELECTRIC_POTENTIAL_MILLIVOLT,
|
ELECTRIC_POTENTIAL_MILLIVOLT,
|
||||||
ELECTRIC_POTENTIAL_VOLT,
|
ELECTRIC_POTENTIAL_VOLT,
|
||||||
|
@ -30,42 +41,68 @@ from homeassistant.const import (
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
from homeassistant.util.dt import utc_from_timestamp
|
||||||
|
|
||||||
from .const import MYSENSORS_DISCOVERY, DiscoveryInfo
|
from .const import MYSENSORS_DISCOVERY, DiscoveryInfo
|
||||||
from .helpers import on_unload
|
from .helpers import on_unload
|
||||||
|
|
||||||
SENSORS: dict[str, list[str | None] | dict[str, list[str | None]]] = {
|
SENSORS: dict[str, list[str | None] | dict[str, list[str | None]]] = {
|
||||||
"V_TEMP": [None, None, DEVICE_CLASS_TEMPERATURE],
|
"V_TEMP": [None, None, DEVICE_CLASS_TEMPERATURE, STATE_CLASS_MEASUREMENT],
|
||||||
"V_HUM": [PERCENTAGE, "mdi:water-percent", DEVICE_CLASS_HUMIDITY],
|
"V_HUM": [
|
||||||
"V_DIMMER": [PERCENTAGE, "mdi:percent", None],
|
PERCENTAGE,
|
||||||
"V_PERCENTAGE": [PERCENTAGE, "mdi:percent", None],
|
"mdi:water-percent",
|
||||||
"V_PRESSURE": [None, "mdi:gauge", None],
|
DEVICE_CLASS_HUMIDITY,
|
||||||
"V_FORECAST": [None, "mdi:weather-partly-cloudy", None],
|
STATE_CLASS_MEASUREMENT,
|
||||||
"V_RAIN": [None, "mdi:weather-rainy", None],
|
],
|
||||||
"V_RAINRATE": [None, "mdi:weather-rainy", None],
|
"V_DIMMER": [PERCENTAGE, "mdi:percent", None, None],
|
||||||
"V_WIND": [None, "mdi:weather-windy", None],
|
"V_PERCENTAGE": [PERCENTAGE, "mdi:percent", None, None],
|
||||||
"V_GUST": [None, "mdi:weather-windy", None],
|
"V_PRESSURE": [None, "mdi:gauge", None, None],
|
||||||
"V_DIRECTION": [DEGREE, "mdi:compass", None],
|
"V_FORECAST": [None, "mdi:weather-partly-cloudy", None, None],
|
||||||
"V_WEIGHT": [MASS_KILOGRAMS, "mdi:weight-kilogram", None],
|
"V_RAIN": [None, "mdi:weather-rainy", None, None],
|
||||||
"V_DISTANCE": [LENGTH_METERS, "mdi:ruler", None],
|
"V_RAINRATE": [None, "mdi:weather-rainy", None, None],
|
||||||
"V_IMPEDANCE": ["ohm", None, None],
|
"V_WIND": [None, "mdi:weather-windy", None, None],
|
||||||
"V_WATT": [POWER_WATT, None, None],
|
"V_GUST": [None, "mdi:weather-windy", None, None],
|
||||||
"V_KWH": [ENERGY_KILO_WATT_HOUR, None, None],
|
"V_DIRECTION": [DEGREE, "mdi:compass", None, None],
|
||||||
"V_LIGHT_LEVEL": [PERCENTAGE, "mdi:white-balance-sunny", None],
|
"V_WEIGHT": [MASS_KILOGRAMS, "mdi:weight-kilogram", None, None],
|
||||||
"V_FLOW": [LENGTH_METERS, "mdi:gauge", None],
|
"V_DISTANCE": [LENGTH_METERS, "mdi:ruler", None, None],
|
||||||
"V_VOLUME": [f"{VOLUME_CUBIC_METERS}", None, None],
|
"V_IMPEDANCE": ["ohm", None, None, None],
|
||||||
|
"V_WATT": [POWER_WATT, None, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT],
|
||||||
|
"V_KWH": [
|
||||||
|
ENERGY_KILO_WATT_HOUR,
|
||||||
|
None,
|
||||||
|
DEVICE_CLASS_ENERGY,
|
||||||
|
STATE_CLASS_MEASUREMENT,
|
||||||
|
],
|
||||||
|
"V_LIGHT_LEVEL": [PERCENTAGE, "mdi:white-balance-sunny", None, None],
|
||||||
|
"V_FLOW": [LENGTH_METERS, "mdi:gauge", None, None],
|
||||||
|
"V_VOLUME": [VOLUME_CUBIC_METERS, None, None, None],
|
||||||
"V_LEVEL": {
|
"V_LEVEL": {
|
||||||
"S_SOUND": [SOUND_PRESSURE_DB, "mdi:volume-high", None],
|
"S_SOUND": [SOUND_PRESSURE_DB, "mdi:volume-high", None, None],
|
||||||
"S_VIBRATION": [FREQUENCY_HERTZ, None, None],
|
"S_VIBRATION": [FREQUENCY_HERTZ, None, None, None],
|
||||||
"S_LIGHT_LEVEL": [LIGHT_LUX, "mdi:white-balance-sunny", None],
|
"S_LIGHT_LEVEL": [
|
||||||
|
LIGHT_LUX,
|
||||||
|
"mdi:white-balance-sunny",
|
||||||
|
DEVICE_CLASS_ILLUMINANCE,
|
||||||
|
STATE_CLASS_MEASUREMENT,
|
||||||
|
],
|
||||||
},
|
},
|
||||||
"V_VOLTAGE": [ELECTRIC_POTENTIAL_VOLT, "mdi:flash", None],
|
"V_VOLTAGE": [
|
||||||
"V_CURRENT": [ELECTRIC_CURRENT_AMPERE, "mdi:flash-auto", None],
|
ELECTRIC_POTENTIAL_VOLT,
|
||||||
"V_PH": ["pH", None, None],
|
"mdi:flash",
|
||||||
"V_ORP": [ELECTRIC_POTENTIAL_MILLIVOLT, None, None],
|
DEVICE_CLASS_VOLTAGE,
|
||||||
"V_EC": [CONDUCTIVITY, None, None],
|
STATE_CLASS_MEASUREMENT,
|
||||||
"V_VAR": ["var", None, None],
|
],
|
||||||
"V_VA": [POWER_VOLT_AMPERE, None, None],
|
"V_CURRENT": [
|
||||||
|
ELECTRIC_CURRENT_AMPERE,
|
||||||
|
"mdi:flash-auto",
|
||||||
|
DEVICE_CLASS_CURRENT,
|
||||||
|
STATE_CLASS_MEASUREMENT,
|
||||||
|
],
|
||||||
|
"V_PH": ["pH", None, None, None],
|
||||||
|
"V_ORP": [ELECTRIC_POTENTIAL_MILLIVOLT, None, None, None],
|
||||||
|
"V_EC": [CONDUCTIVITY, None, None, None],
|
||||||
|
"V_VAR": ["var", None, None, None],
|
||||||
|
"V_VA": [POWER_VOLT_AMPERE, None, None, None],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -124,6 +161,20 @@ class MySensorsSensor(mysensors.device.MySensorsEntity, SensorEntity):
|
||||||
"""Return the icon to use in the frontend, if any."""
|
"""Return the icon to use in the frontend, if any."""
|
||||||
return self._get_sensor_type()[1]
|
return self._get_sensor_type()[1]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def last_reset(self) -> datetime | None:
|
||||||
|
"""Return the time when the sensor was last reset, if any."""
|
||||||
|
set_req = self.gateway.const.SetReq
|
||||||
|
|
||||||
|
if set_req(self.value_type).name == "V_KWH":
|
||||||
|
return utc_from_timestamp(0)
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def state_class(self) -> str | None:
|
||||||
|
"""Return the state class of this entity."""
|
||||||
|
return self._get_sensor_type()[3]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def unit_of_measurement(self) -> str | None:
|
def unit_of_measurement(self) -> str | None:
|
||||||
"""Return the unit of measurement of this entity."""
|
"""Return the unit of measurement of this entity."""
|
||||||
|
@ -148,10 +199,12 @@ class MySensorsSensor(mysensors.device.MySensorsEntity, SensorEntity):
|
||||||
pres = self.gateway.const.Presentation
|
pres = self.gateway.const.Presentation
|
||||||
set_req = self.gateway.const.SetReq
|
set_req = self.gateway.const.SetReq
|
||||||
|
|
||||||
_sensor_type = SENSORS.get(set_req(self.value_type).name, [None, None, None])
|
_sensor_type = SENSORS.get(
|
||||||
|
set_req(self.value_type).name, [None, None, None, None]
|
||||||
|
)
|
||||||
if isinstance(_sensor_type, dict):
|
if isinstance(_sensor_type, dict):
|
||||||
sensor_type = _sensor_type.get(
|
sensor_type = _sensor_type.get(
|
||||||
pres(self.child_type).name, [None, None, None]
|
pres(self.child_type).name, [None, None, None, None]
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
sensor_type = _sensor_type
|
sensor_type = _sensor_type
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
"""Support for MySensors switches."""
|
"""Support for MySensors switches."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from contextlib import suppress
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
@ -109,18 +108,6 @@ async def async_setup_entry(
|
||||||
class MySensorsSwitch(mysensors.device.MySensorsEntity, SwitchEntity):
|
class MySensorsSwitch(mysensors.device.MySensorsEntity, SwitchEntity):
|
||||||
"""Representation of the value of a MySensors Switch child node."""
|
"""Representation of the value of a MySensors Switch child node."""
|
||||||
|
|
||||||
@property
|
|
||||||
def current_power_w(self) -> float | None:
|
|
||||||
"""Return the current power usage in W."""
|
|
||||||
set_req = self.gateway.const.SetReq
|
|
||||||
value = self._values.get(set_req.V_WATT)
|
|
||||||
float_value: float | None = None
|
|
||||||
if value is not None:
|
|
||||||
with suppress(ValueError):
|
|
||||||
float_value = float(value)
|
|
||||||
|
|
||||||
return float_value
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_on(self) -> bool:
|
def is_on(self) -> bool:
|
||||||
"""Return True if switch is on."""
|
"""Return True if switch is on."""
|
||||||
|
|
|
@ -156,3 +156,17 @@ def gps_sensor(gateway_nodes, gps_sensor_state) -> Sensor:
|
||||||
nodes = update_gateway_nodes(gateway_nodes, gps_sensor_state)
|
nodes = update_gateway_nodes(gateway_nodes, gps_sensor_state)
|
||||||
node = nodes[1]
|
node = nodes[1]
|
||||||
return node
|
return node
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="power_sensor_state", scope="session")
|
||||||
|
def power_sensor_state_fixture() -> dict:
|
||||||
|
"""Load the power sensor state."""
|
||||||
|
return load_nodes_state("mysensors/power_sensor_state.json")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def power_sensor(gateway_nodes, power_sensor_state) -> Sensor:
|
||||||
|
"""Load the power sensor."""
|
||||||
|
nodes = update_gateway_nodes(gateway_nodes, power_sensor_state)
|
||||||
|
node = nodes[1]
|
||||||
|
return node
|
||||||
|
|
|
@ -1,6 +1,15 @@
|
||||||
"""Provide tests for mysensors sensor platform."""
|
"""Provide tests for mysensors sensor platform."""
|
||||||
|
|
||||||
|
|
||||||
|
from homeassistant.components.sensor import ATTR_STATE_CLASS, STATE_CLASS_MEASUREMENT
|
||||||
|
from homeassistant.const import (
|
||||||
|
ATTR_DEVICE_CLASS,
|
||||||
|
ATTR_UNIT_OF_MEASUREMENT,
|
||||||
|
DEVICE_CLASS_POWER,
|
||||||
|
POWER_WATT,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def test_gps_sensor(hass, gps_sensor, integration):
|
async def test_gps_sensor(hass, gps_sensor, integration):
|
||||||
"""Test a gps sensor."""
|
"""Test a gps sensor."""
|
||||||
entity_id = "sensor.gps_sensor_1_1"
|
entity_id = "sensor.gps_sensor_1_1"
|
||||||
|
@ -8,3 +17,15 @@ async def test_gps_sensor(hass, gps_sensor, integration):
|
||||||
state = hass.states.get(entity_id)
|
state = hass.states.get(entity_id)
|
||||||
|
|
||||||
assert state.state == "40.741894,-73.989311,12"
|
assert state.state == "40.741894,-73.989311,12"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_power_sensor(hass, power_sensor, integration):
|
||||||
|
"""Test a power sensor."""
|
||||||
|
entity_id = "sensor.power_sensor_1_1"
|
||||||
|
|
||||||
|
state = hass.states.get(entity_id)
|
||||||
|
|
||||||
|
assert state.state == "1200"
|
||||||
|
assert state.attributes[ATTR_DEVICE_CLASS] == DEVICE_CLASS_POWER
|
||||||
|
assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == POWER_WATT
|
||||||
|
assert state.attributes[ATTR_STATE_CLASS] == STATE_CLASS_MEASUREMENT
|
||||||
|
|
21
tests/fixtures/mysensors/power_sensor_state.json
vendored
Normal file
21
tests/fixtures/mysensors/power_sensor_state.json
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"1": {
|
||||||
|
"sensor_id": 1,
|
||||||
|
"children": {
|
||||||
|
"1": {
|
||||||
|
"id": 1,
|
||||||
|
"type": 13,
|
||||||
|
"description": "",
|
||||||
|
"values": {
|
||||||
|
"17": "1200"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": 17,
|
||||||
|
"sketch_name": "Power Sensor",
|
||||||
|
"sketch_version": "1.0",
|
||||||
|
"battery_level": 0,
|
||||||
|
"protocol_version": "2.3.2",
|
||||||
|
"heartbeat": 0
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue