mirror of
https://github.com/home-assistant/core.git
synced 2026-08-19 21:01:05 +01:00
Fix use of ambiguous units for reactive power and energy (#161810)
This commit is contained in:
@@ -594,7 +594,8 @@ UNIT_CONVERTERS: dict[NumberDeviceClass, type[BaseUnitConverter]] = {
|
||||
}
|
||||
|
||||
# We translate units that were using using the legacy coding of μ \u00b5
|
||||
# to units using recommended coding of μ \u03bc
|
||||
# to units using recommended coding of μ \u03bc and
|
||||
# we convert alternative accepted units to the preferred unit.
|
||||
AMBIGUOUS_UNITS: dict[str | None, str] = {
|
||||
"\u00b5Sv/h": "μSv/h", # aranet: radiation rate
|
||||
"\u00b5S/cm": UnitOfConductivity.MICROSIEMENS_PER_CM,
|
||||
@@ -604,4 +605,9 @@ AMBIGUOUS_UNITS: dict[str | None, str] = {
|
||||
"\u00b5mol/s⋅m²": "μmol/s⋅m²", # fyta: light
|
||||
"\u00b5g": UnitOfMass.MICROGRAMS,
|
||||
"\u00b5s": UnitOfTime.MICROSECONDS,
|
||||
"mVAr": UnitOfReactivePower.MILLIVOLT_AMPERE_REACTIVE,
|
||||
"VAr": UnitOfReactivePower.VOLT_AMPERE_REACTIVE,
|
||||
"kVAr": UnitOfReactivePower.KILO_VOLT_AMPERE_REACTIVE,
|
||||
"VArh": UnitOfReactiveEnergy.VOLT_AMPERE_REACTIVE_HOUR,
|
||||
"kVArh": UnitOfReactiveEnergy.KILO_VOLT_AMPERE_REACTIVE_HOUR,
|
||||
}
|
||||
|
||||
@@ -840,7 +840,8 @@ STATE_CLASS_UNITS: dict[SensorStateClass | str, set[type[StrEnum] | str | None]]
|
||||
}
|
||||
|
||||
# We translate units that were using using the legacy coding of μ \u00b5
|
||||
# to units using recommended coding of μ \u03bc
|
||||
# to units using recommended coding of μ \u03bc and
|
||||
# we convert alternative accepted units to the preferred unit.
|
||||
AMBIGUOUS_UNITS: dict[str | None, str] = {
|
||||
"\u00b5Sv/h": "μSv/h", # aranet: radiation rate
|
||||
"\u00b5S/cm": UnitOfConductivity.MICROSIEMENS_PER_CM,
|
||||
@@ -850,4 +851,9 @@ AMBIGUOUS_UNITS: dict[str | None, str] = {
|
||||
"\u00b5mol/s⋅m²": "μmol/s⋅m²", # fyta: light
|
||||
"\u00b5g": UnitOfMass.MICROGRAMS,
|
||||
"\u00b5s": UnitOfTime.MICROSECONDS,
|
||||
"mVAr": UnitOfReactivePower.MILLIVOLT_AMPERE_REACTIVE,
|
||||
"VAr": UnitOfReactivePower.VOLT_AMPERE_REACTIVE,
|
||||
"kVAr": UnitOfReactivePower.KILO_VOLT_AMPERE_REACTIVE,
|
||||
"VArh": UnitOfReactiveEnergy.VOLT_AMPERE_REACTIVE_HOUR,
|
||||
"kVArh": UnitOfReactiveEnergy.KILO_VOLT_AMPERE_REACTIVE_HOUR,
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import copy
|
||||
from datetime import datetime, timedelta
|
||||
from enum import StrEnum
|
||||
import json
|
||||
import logging
|
||||
from pathlib import Path
|
||||
@@ -20,6 +21,8 @@ from homeassistant.const import (
|
||||
STATE_UNAVAILABLE,
|
||||
STATE_UNKNOWN,
|
||||
UnitOfElectricPotential,
|
||||
UnitOfReactiveEnergy,
|
||||
UnitOfReactivePower,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import Event, HomeAssistant, State, callback
|
||||
@@ -909,24 +912,113 @@ async def test_invalid_unit_of_measurement(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"hass_config",
|
||||
("hass_config", "device_class", "unit", "equivalent_unit"),
|
||||
[
|
||||
{
|
||||
mqtt.DOMAIN: {
|
||||
sensor.DOMAIN: {
|
||||
"name": "test",
|
||||
"state_topic": "test-topic",
|
||||
"device_class": "voltage",
|
||||
"unit_of_measurement": "\u00b5V", # microVolt
|
||||
pytest.param(
|
||||
{
|
||||
mqtt.DOMAIN: {
|
||||
sensor.DOMAIN: {
|
||||
"name": "test",
|
||||
"state_topic": "test-topic",
|
||||
"device_class": "voltage",
|
||||
"unit_of_measurement": "\u00b5V", # microVolt
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"voltage",
|
||||
UnitOfElectricPotential.MICROVOLT,
|
||||
"\u00b5V",
|
||||
id="microvolt",
|
||||
),
|
||||
pytest.param(
|
||||
{
|
||||
mqtt.DOMAIN: {
|
||||
sensor.DOMAIN: {
|
||||
"name": "test",
|
||||
"state_topic": "test-topic",
|
||||
"device_class": "reactive_power",
|
||||
"unit_of_measurement": "mVAr",
|
||||
}
|
||||
}
|
||||
},
|
||||
"reactive_power",
|
||||
UnitOfReactivePower.MILLIVOLT_AMPERE_REACTIVE,
|
||||
"mVAr",
|
||||
id="mvar",
|
||||
),
|
||||
pytest.param(
|
||||
{
|
||||
mqtt.DOMAIN: {
|
||||
sensor.DOMAIN: {
|
||||
"name": "test",
|
||||
"state_topic": "test-topic",
|
||||
"device_class": "reactive_power",
|
||||
"unit_of_measurement": "VAr",
|
||||
}
|
||||
}
|
||||
},
|
||||
"reactive_power",
|
||||
UnitOfReactivePower.VOLT_AMPERE_REACTIVE,
|
||||
"VAr",
|
||||
id="var",
|
||||
),
|
||||
pytest.param(
|
||||
{
|
||||
mqtt.DOMAIN: {
|
||||
sensor.DOMAIN: {
|
||||
"name": "test",
|
||||
"state_topic": "test-topic",
|
||||
"device_class": "reactive_power",
|
||||
"unit_of_measurement": "kVAr",
|
||||
}
|
||||
}
|
||||
},
|
||||
"reactive_power",
|
||||
UnitOfReactivePower.KILO_VOLT_AMPERE_REACTIVE,
|
||||
"kVAr",
|
||||
id="kvar",
|
||||
),
|
||||
pytest.param(
|
||||
{
|
||||
mqtt.DOMAIN: {
|
||||
sensor.DOMAIN: {
|
||||
"name": "test",
|
||||
"state_topic": "test-topic",
|
||||
"device_class": "reactive_energy",
|
||||
"unit_of_measurement": "VArh",
|
||||
}
|
||||
}
|
||||
},
|
||||
"reactive_energy",
|
||||
UnitOfReactiveEnergy.VOLT_AMPERE_REACTIVE_HOUR,
|
||||
"VArh",
|
||||
id="varh",
|
||||
),
|
||||
pytest.param(
|
||||
{
|
||||
mqtt.DOMAIN: {
|
||||
sensor.DOMAIN: {
|
||||
"name": "test",
|
||||
"state_topic": "test-topic",
|
||||
"device_class": "reactive_energy",
|
||||
"unit_of_measurement": "kVArh",
|
||||
}
|
||||
}
|
||||
},
|
||||
"reactive_energy",
|
||||
UnitOfReactiveEnergy.KILO_VOLT_AMPERE_REACTIVE_HOUR,
|
||||
"kVArh",
|
||||
id="kvarh",
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_device_class_with_equivalent_unit_of_measurement_received(
|
||||
hass: HomeAssistant,
|
||||
mqtt_mock_entry: MqttMockHAClientGenerator,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
device_class: str,
|
||||
unit: StrEnum,
|
||||
equivalent_unit: str,
|
||||
) -> None:
|
||||
"""Test device_class with equivalent unit of measurement."""
|
||||
assert await mqtt_mock_entry()
|
||||
@@ -935,20 +1027,17 @@ async def test_device_class_with_equivalent_unit_of_measurement_received(
|
||||
state = hass.states.get("sensor.test")
|
||||
assert state is not None
|
||||
assert state.state == "100"
|
||||
assert (
|
||||
state.attributes.get(ATTR_UNIT_OF_MEASUREMENT)
|
||||
is UnitOfElectricPotential.MICROVOLT
|
||||
)
|
||||
assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) is unit
|
||||
|
||||
caplog.clear()
|
||||
|
||||
discovery_payload = {
|
||||
"name": "bla",
|
||||
"state_topic": "test-topic2",
|
||||
"device_class": "voltage",
|
||||
"unit_of_measurement": "\u00b5V",
|
||||
"device_class": device_class,
|
||||
"unit_of_measurement": equivalent_unit,
|
||||
}
|
||||
# Now discover a sensor with an altarantive mu char
|
||||
# Now discover a sensor with an ambiguous unit
|
||||
async_fire_mqtt_message(
|
||||
hass, "homeassistant/sensor/bla/config", json.dumps(discovery_payload)
|
||||
)
|
||||
@@ -958,10 +1047,7 @@ async def test_device_class_with_equivalent_unit_of_measurement_received(
|
||||
state = hass.states.get("sensor.bla")
|
||||
assert state is not None
|
||||
assert state.state == "21"
|
||||
assert (
|
||||
state.attributes.get(ATTR_UNIT_OF_MEASUREMENT)
|
||||
is UnitOfElectricPotential.MICROVOLT
|
||||
)
|
||||
assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) is unit
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
||||
@@ -3892,6 +3892,21 @@ async def test_compile_hourly_statistics_convert_units_1(
|
||||
),
|
||||
(None, "\u00b5g", "\u03bcg", None, "mass", 13.050847, 13.333333, -10, 30),
|
||||
(None, "\u00b5s", "\u03bcs", None, "duration", 13.050847, 13.333333, -10, 30),
|
||||
(None, "mVAr", "mvar", None, "reactive_power", 13.050847, 13.333333, -10, 30),
|
||||
(None, "VAr", "var", None, "reactive_power", 13.050847, 13.333333, -10, 30),
|
||||
(None, "kVAr", "kvar", None, "reactive_power", 13.050847, 13.333333, -10, 30),
|
||||
(None, "VArh", "varh", None, "reactive_energy", 13.050847, 13.333333, -10, 30),
|
||||
(
|
||||
None,
|
||||
"kVArh",
|
||||
"kvarh",
|
||||
None,
|
||||
"reactive_energy",
|
||||
13.050847,
|
||||
13.333333,
|
||||
-10,
|
||||
30,
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_compile_hourly_statistics_equivalent_units_1(
|
||||
@@ -4032,6 +4047,16 @@ async def test_compile_hourly_statistics_equivalent_units_1(
|
||||
(SensorDeviceClass.WEIGHT, "\u00b5g", "\u03bcg", None, 13.333333, -10, 30),
|
||||
(None, "\u00b5s", "\u03bcs", None, 13.333333, -10, 30),
|
||||
(SensorDeviceClass.DURATION, "\u00b5s", "\u03bcs", None, 13.333333, -10, 30),
|
||||
(None, "mVAr", "mvar", None, 13.333333, -10, 30),
|
||||
(None, "VAr", "var", None, 13.333333, -10, 30),
|
||||
(None, "kVAr", "kvar", None, 13.333333, -10, 30),
|
||||
(None, "VArh", "varh", None, 13.333333, -10, 30),
|
||||
(None, "kVArh", "kvarh", None, 13.333333, -10, 30),
|
||||
(SensorDeviceClass.REACTIVE_POWER, "mVAr", "mvar", None, 13.333333, -10, 30),
|
||||
(SensorDeviceClass.REACTIVE_POWER, "VAr", "var", None, 13.333333, -10, 30),
|
||||
(SensorDeviceClass.REACTIVE_POWER, "kVAr", "kvar", None, 13.333333, -10, 30),
|
||||
(SensorDeviceClass.REACTIVE_ENERGY, "VArh", "varh", None, 13.333333, -10, 30),
|
||||
(SensorDeviceClass.REACTIVE_ENERGY, "kVArh", "kvarh", None, 13.333333, -10, 30),
|
||||
],
|
||||
)
|
||||
async def test_compile_hourly_statistics_equivalent_units_2(
|
||||
@@ -6008,6 +6033,11 @@ async def test_validate_statistics_unit_change_no_conversion(
|
||||
(NONE_SENSOR_ATTRIBUTES, "\u00b5mol/s⋅m²", "\u03bcmol/s⋅m²"),
|
||||
(NONE_SENSOR_ATTRIBUTES, "\u00b5g", "\u03bcg"),
|
||||
(NONE_SENSOR_ATTRIBUTES, "\u00b5s", "\u03bcs"),
|
||||
(NONE_SENSOR_ATTRIBUTES, "mVAr", "mvar"),
|
||||
(NONE_SENSOR_ATTRIBUTES, "VAr", "var"),
|
||||
(NONE_SENSOR_ATTRIBUTES, "kVAr", "kvar"),
|
||||
(NONE_SENSOR_ATTRIBUTES, "VArh", "varh"),
|
||||
(NONE_SENSOR_ATTRIBUTES, "kVArh", "kvarh"),
|
||||
],
|
||||
)
|
||||
async def test_validate_statistics_unit_change_equivalent_units(
|
||||
@@ -6105,6 +6135,11 @@ async def test_validate_statistics_unit_change_equivalent_units(
|
||||
"\u00b5s",
|
||||
"d, h, min, ms, s, w, \u03bcs",
|
||||
),
|
||||
(NONE_SENSOR_ATTRIBUTES, "reactive_power", "mvar", "mVAr", "kvar, mvar, var"),
|
||||
(NONE_SENSOR_ATTRIBUTES, "reactive_power", "var", "VAr", "kvar, mvar, var"),
|
||||
(NONE_SENSOR_ATTRIBUTES, "reactive_power", "kvar", "kVAr", "kvar, mvar, var"),
|
||||
(NONE_SENSOR_ATTRIBUTES, "reactive_energy", "varh", "VArh", "kvarh, varh"),
|
||||
(NONE_SENSOR_ATTRIBUTES, "reactive_energy", "kvarh", "kVArh", "kvarh, varh"),
|
||||
],
|
||||
)
|
||||
async def test_validate_statistics_unit_change_equivalent_units_2(
|
||||
|
||||
Reference in New Issue
Block a user