1
mirror of https://github.com/home-assistant/core synced 2024-08-15 18:25:44 +02:00

Add volume to SensorDeviceClass (#77960)

* Add volume to SensorDeviceClass

* Adjust recorder

* Adjust tests

* Adjust sensor UNIT_CONVERTERS

* Adjust recorder

* Update strings.json
This commit is contained in:
epenet 2022-09-27 18:37:52 +01:00 committed by GitHub
parent d8a15f3dda
commit 12e4d18038
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 113 additions and 23 deletions

View File

@ -13,8 +13,6 @@ from homeassistant.const import (
ENERGY_KILO_WATT_HOUR,
ENERGY_MEGA_WATT_HOUR,
ENERGY_WATT_HOUR,
VOLUME_CUBIC_FEET,
VOLUME_CUBIC_METERS,
)
from homeassistant.core import HomeAssistant, callback, valid_entity_id
from homeassistant.helpers import config_validation as cv
@ -27,6 +25,7 @@ from homeassistant.util.unit_conversion import (
PressureConverter,
SpeedConverter,
TemperatureConverter,
VolumeConverter,
)
from .const import MAX_QUEUE_BACKLOG
@ -131,7 +130,7 @@ async def ws_handle_get_statistics_during_period(
vol.Optional("pressure"): vol.In(PressureConverter.VALID_UNITS),
vol.Optional("speed"): vol.In(SpeedConverter.VALID_UNITS),
vol.Optional("temperature"): vol.In(TemperatureConverter.VALID_UNITS),
vol.Optional("volume"): vol.Any(VOLUME_CUBIC_FEET, VOLUME_CUBIC_METERS),
vol.Optional("volume"): vol.In(VolumeConverter.VALID_UNITS),
}
),
}
@ -336,7 +335,10 @@ async def ws_adjust_sum_statistics(
ENERGY_WATT_HOUR,
):
return True
if statistics_unit == VOLUME_CUBIC_METERS and display_unit == VOLUME_CUBIC_FEET:
if (
statistics_unit == VolumeConverter.NORMALIZED_UNIT
and display_unit in VolumeConverter.VALID_UNITS
):
return True
return False

View File

@ -64,6 +64,7 @@ from homeassistant.util.unit_conversion import (
PressureConverter,
SpeedConverter,
TemperatureConverter,
VolumeConverter,
)
from .const import CONF_STATE_CLASS # noqa: F401
@ -185,6 +186,9 @@ class SensorDeviceClass(StrEnum):
# voltage (V)
VOLTAGE = "voltage"
# volume (VOLUME_*)
VOLUME = "volume"
DEVICE_CLASSES_SCHEMA: Final = vol.All(vol.Lower, vol.Coerce(SensorDeviceClass))
@ -221,6 +225,7 @@ UNIT_CONVERTERS: dict[str, type[BaseUnitConverter]] = {
SensorDeviceClass.PRESSURE: PressureConverter,
SensorDeviceClass.SPEED: SpeedConverter,
SensorDeviceClass.TEMPERATURE: TemperatureConverter,
SensorDeviceClass.VOLUME: VolumeConverter,
}
UNIT_RATIOS: dict[str, dict[str, float]] = {
@ -232,6 +237,7 @@ UNIT_RATIOS: dict[str, dict[str, float]] = {
TEMP_FAHRENHEIT: 1.8,
TEMP_KELVIN: 1.0,
},
SensorDeviceClass.VOLUME: VolumeConverter.UNIT_CONVERSION,
}
# mypy: disallow-any-generics

View File

@ -58,9 +58,10 @@ CONF_IS_REACTIVE_POWER = "is_reactive_power"
CONF_IS_SIGNAL_STRENGTH = "is_signal_strength"
CONF_IS_SULPHUR_DIOXIDE = "is_sulphur_dioxide"
CONF_IS_TEMPERATURE = "is_temperature"
CONF_IS_VALUE = "is_value"
CONF_IS_VOLATILE_ORGANIC_COMPOUNDS = "is_volatile_organic_compounds"
CONF_IS_VOLTAGE = "is_voltage"
CONF_IS_VALUE = "is_value"
CONF_IS_VOLUME = "is_volume"
ENTITY_CONDITIONS = {
SensorDeviceClass.APPARENT_POWER: [{CONF_TYPE: CONF_IS_APPARENT_POWER}],
@ -94,6 +95,7 @@ ENTITY_CONDITIONS = {
{CONF_TYPE: CONF_IS_VOLATILE_ORGANIC_COMPOUNDS}
],
SensorDeviceClass.VOLTAGE: [{CONF_TYPE: CONF_IS_VOLTAGE}],
SensorDeviceClass.VOLUME: [{CONF_TYPE: CONF_IS_VOLUME}],
DEVICE_CLASS_NONE: [{CONF_TYPE: CONF_IS_VALUE}],
}

View File

@ -57,9 +57,10 @@ CONF_SIGNAL_STRENGTH = "signal_strength"
CONF_SPEED = "speed"
CONF_SULPHUR_DIOXIDE = "sulphur_dioxide"
CONF_TEMPERATURE = "temperature"
CONF_VALUE = "value"
CONF_VOLATILE_ORGANIC_COMPOUNDS = "volatile_organic_compounds"
CONF_VOLTAGE = "voltage"
CONF_VALUE = "value"
CONF_VOLUME = "volume"
ENTITY_TRIGGERS = {
SensorDeviceClass.APPARENT_POWER: [{CONF_TYPE: CONF_APPARENT_POWER}],
@ -93,6 +94,7 @@ ENTITY_TRIGGERS = {
{CONF_TYPE: CONF_VOLATILE_ORGANIC_COMPOUNDS}
],
SensorDeviceClass.VOLTAGE: [{CONF_TYPE: CONF_VOLTAGE}],
SensorDeviceClass.VOLUME: [{CONF_TYPE: CONF_VOLUME}],
DEVICE_CLASS_NONE: [{CONF_TYPE: CONF_VALUE}],
}

View File

@ -61,11 +61,12 @@ DEFAULT_STATISTICS = {
UNIT_CONVERTERS: dict[str, type[BaseUnitConverter]] = {
SensorDeviceClass.DISTANCE: DistanceConverter,
SensorDeviceClass.ENERGY: EnergyConverter,
SensorDeviceClass.GAS: VolumeConverter,
SensorDeviceClass.POWER: PowerConverter,
SensorDeviceClass.PRESSURE: PressureConverter,
SensorDeviceClass.SPEED: SpeedConverter,
SensorDeviceClass.TEMPERATURE: TemperatureConverter,
SensorDeviceClass.GAS: VolumeConverter,
SensorDeviceClass.VOLUME: VolumeConverter,
}
# Keep track of entities for which a warning about decreasing value has been logged

View File

@ -6,7 +6,10 @@
"is_battery_level": "Current {entity_name} battery level",
"is_carbon_monoxide": "Current {entity_name} carbon monoxide concentration level",
"is_carbon_dioxide": "Current {entity_name} carbon dioxide concentration level",
"is_current": "Current {entity_name} current",
"is_distance": "Current {entity_name} distance",
"is_energy": "Current {entity_name} energy",
"is_frequency": "Current {entity_name} frequency",
"is_gas": "Current {entity_name} gas",
"is_humidity": "Current {entity_name} humidity",
"is_illuminance": "Current {entity_name} illuminance",
@ -19,26 +22,27 @@
"is_pm10": "Current {entity_name} PM10 concentration level",
"is_pm25": "Current {entity_name} PM2.5 concentration level",
"is_power": "Current {entity_name} power",
"is_power_factor": "Current {entity_name} power factor",
"is_pressure": "Current {entity_name} pressure",
"is_reactive_power": "Current {entity_name} reactive power",
"is_signal_strength": "Current {entity_name} signal strength",
"is_speed": "Current {entity_name} speed",
"is_sulphur_dioxide": "Current {entity_name} sulphur dioxide concentration level",
"is_temperature": "Current {entity_name} temperature",
"is_current": "Current {entity_name} current",
"is_energy": "Current {entity_name} energy",
"is_frequency": "Current {entity_name} frequency",
"is_power_factor": "Current {entity_name} power factor",
"is_value": "Current {entity_name} value",
"is_volatile_organic_compounds": "Current {entity_name} volatile organic compounds concentration level",
"is_voltage": "Current {entity_name} voltage",
"is_value": "Current {entity_name} value"
"is_volume": "Current {entity_name} volume"
},
"trigger_type": {
"apparent_power": "{entity_name} apparent power changes",
"battery_level": "{entity_name} battery level changes",
"carbon_monoxide": "{entity_name} carbon monoxide concentration changes",
"carbon_dioxide": "{entity_name} carbon dioxide concentration changes",
"current": "{entity_name} current changes",
"distance": "{entity_name} distance changes",
"energy": "{entity_name} energy changes",
"frequency": "{entity_name} frequency changes",
"gas": "{entity_name} gas changes",
"humidity": "{entity_name} humidity changes",
"illuminance": "{entity_name} illuminance changes",
@ -51,19 +55,17 @@
"pm10": "{entity_name} PM10 concentration changes",
"pm25": "{entity_name} PM2.5 concentration changes",
"power": "{entity_name} power changes",
"power_factor": "{entity_name} power factor changes",
"pressure": "{entity_name} pressure changes",
"reactive_power": "{entity_name} reactive power changes",
"signal_strength": "{entity_name} signal strength changes",
"speed": "{entity_name} speed changes",
"sulphur_dioxide": "{entity_name} sulphur dioxide concentration changes",
"temperature": "{entity_name} temperature changes",
"current": "{entity_name} current changes",
"energy": "{entity_name} energy changes",
"frequency": "{entity_name} frequency changes",
"power_factor": "{entity_name} power factor changes",
"value": "{entity_name} value changes",
"volatile_organic_compounds": "{entity_name} volatile organic compounds concentration changes",
"voltage": "{entity_name} voltage changes",
"value": "{entity_name} value changes"
"volume": "{entity_name} volume changes"
}
},
"state": {

View File

@ -30,7 +30,8 @@
"is_temperature": "Current {entity_name} temperature",
"is_value": "Current {entity_name} value",
"is_volatile_organic_compounds": "Current {entity_name} volatile organic compounds concentration level",
"is_voltage": "Current {entity_name} voltage"
"is_voltage": "Current {entity_name} voltage",
"is_volume": "Current {entity_name} volume"
},
"trigger_type": {
"apparent_power": "{entity_name} apparent power changes",
@ -62,7 +63,8 @@
"temperature": "{entity_name} temperature changes",
"value": "{entity_name} value changes",
"volatile_organic_compounds": "{entity_name} volatile organic compounds concentration changes",
"voltage": "{entity_name} voltage changes"
"voltage": "{entity_name} voltage changes",
"volume": "{entity_name} volume changes"
}
},
"state": {

View File

@ -100,6 +100,26 @@ TEMPERATURE_SENSOR_F_ATTRIBUTES = {
"state_class": "measurement",
"unit_of_measurement": "°F",
}
VOLUME_SENSOR_FT3_ATTRIBUTES = {
"device_class": "volume",
"state_class": "measurement",
"unit_of_measurement": "ft³",
}
VOLUME_SENSOR_M3_ATTRIBUTES = {
"device_class": "volume",
"state_class": "measurement",
"unit_of_measurement": "",
}
VOLUME_SENSOR_FT3_ATTRIBUTES_TOTAL = {
"device_class": "volume",
"state_class": "total",
"unit_of_measurement": "ft³",
}
VOLUME_SENSOR_M3_ATTRIBUTES_TOTAL = {
"device_class": "volume",
"state_class": "total",
"unit_of_measurement": "",
}
async def test_statistics_during_period(hass, hass_ws_client, recorder_mock):
@ -175,6 +195,8 @@ async def test_statistics_during_period(hass, hass_ws_client, recorder_mock):
(TEMPERATURE_SENSOR_C_ATTRIBUTES, 10, 10, {"temperature": "°C"}, 10),
(TEMPERATURE_SENSOR_C_ATTRIBUTES, 10, 10, {"temperature": "°F"}, 50),
(TEMPERATURE_SENSOR_C_ATTRIBUTES, 10, 10, {"temperature": "K"}, 283.15),
(VOLUME_SENSOR_M3_ATTRIBUTES, 10, 10, {"volume": ""}, 10),
(VOLUME_SENSOR_M3_ATTRIBUTES, 10, 10, {"volume": "ft³"}, 353.14666),
],
)
async def test_statistics_during_period_unit_conversion(
@ -266,6 +288,8 @@ async def test_statistics_during_period_unit_conversion(
(ENERGY_SENSOR_KWH_ATTRIBUTES, 10, 10, {"energy": "Wh"}, 10000),
(GAS_SENSOR_M3_ATTRIBUTES, 10, 10, {"volume": ""}, 10),
(GAS_SENSOR_M3_ATTRIBUTES, 10, 10, {"volume": "ft³"}, 353.147),
(VOLUME_SENSOR_M3_ATTRIBUTES_TOTAL, 10, 10, {"volume": ""}, 10),
(VOLUME_SENSOR_M3_ATTRIBUTES_TOTAL, 10, 10, {"volume": "ft³"}, 353.147),
],
)
async def test_sum_statistics_during_period_unit_conversion(
@ -583,6 +607,10 @@ async def test_statistics_during_period_bad_end_time(
(METRIC_SYSTEM, TEMPERATURE_SENSOR_C_ATTRIBUTES, "°C", "°C", "temperature"),
(IMPERIAL_SYSTEM, TEMPERATURE_SENSOR_F_ATTRIBUTES, "°F", "°C", "temperature"),
(METRIC_SYSTEM, TEMPERATURE_SENSOR_F_ATTRIBUTES, "°F", "°C", "temperature"),
(IMPERIAL_SYSTEM, VOLUME_SENSOR_FT3_ATTRIBUTES, "ft³", "", "volume"),
(METRIC_SYSTEM, VOLUME_SENSOR_FT3_ATTRIBUTES, "ft³", "", "volume"),
(IMPERIAL_SYSTEM, VOLUME_SENSOR_FT3_ATTRIBUTES_TOTAL, "ft³", "", "volume"),
(METRIC_SYSTEM, VOLUME_SENSOR_FT3_ATTRIBUTES_TOTAL, "ft³", "", "volume"),
],
)
async def test_list_statistic_ids(
@ -1376,6 +1404,8 @@ async def test_backup_end_without_start(
(METRIC_SYSTEM, SPEED_SENSOR_MPH_ATTRIBUTES, "m/s", "speed"),
(METRIC_SYSTEM, TEMPERATURE_SENSOR_C_ATTRIBUTES, "°C", "temperature"),
(METRIC_SYSTEM, TEMPERATURE_SENSOR_F_ATTRIBUTES, "°C", "temperature"),
(METRIC_SYSTEM, VOLUME_SENSOR_FT3_ATTRIBUTES, "", "volume"),
(METRIC_SYSTEM, VOLUME_SENSOR_M3_ATTRIBUTES, "", "volume"),
],
)
async def test_get_statistics_metadata(

View File

@ -23,6 +23,10 @@ from homeassistant.const import (
STATE_UNKNOWN,
TEMP_CELSIUS,
TEMP_FAHRENHEIT,
VOLUME_CUBIC_FEET,
VOLUME_CUBIC_METERS,
VOLUME_FLUID_OUNCE,
VOLUME_LITERS,
)
from homeassistant.core import State
from homeassistant.helpers import entity_registry as er
@ -549,6 +553,31 @@ async def test_custom_unit(
100,
SensorDeviceClass.SPEED,
),
# Volume
(
VOLUME_CUBIC_METERS,
VOLUME_CUBIC_FEET,
VOLUME_CUBIC_FEET,
100,
3531,
SensorDeviceClass.VOLUME,
),
(
VOLUME_FLUID_OUNCE,
VOLUME_LITERS,
VOLUME_LITERS,
78,
2.3,
SensorDeviceClass.VOLUME,
),
(
VOLUME_CUBIC_METERS,
"peer_distance",
VOLUME_CUBIC_METERS,
100,
100,
SensorDeviceClass.VOLUME,
),
],
)
async def test_custom_unit_change(

View File

@ -98,6 +98,8 @@ def set_time_zone():
("speed", "mph", "mph", "m/s", "speed", 13.050847, -10, 30),
("temperature", "°C", "°C", "°C", "temperature", 13.050847, -10, 30),
("temperature", "°F", "°F", "°C", "temperature", 13.050847, -10, 30),
("volume", "", "", "", "volume", 13.050847, -10, 30),
("volume", "ft³", "ft³", "", "volume", 13.050847, -10, 30),
],
)
def test_compile_hourly_statistics(
@ -359,18 +361,22 @@ def test_compile_hourly_statistics_unsupported(hass_recorder, caplog, attributes
(IMPERIAL_SYSTEM, "distance", "mi", "mi", "m", "distance", 1),
(IMPERIAL_SYSTEM, "energy", "kWh", "kWh", "kWh", "energy", 1),
(IMPERIAL_SYSTEM, "energy", "Wh", "Wh", "kWh", "energy", 1),
(IMPERIAL_SYSTEM, "monetary", "EUR", "EUR", "EUR", None, 1),
(IMPERIAL_SYSTEM, "monetary", "SEK", "SEK", "SEK", None, 1),
(IMPERIAL_SYSTEM, "gas", "", "", "", "volume", 1),
(IMPERIAL_SYSTEM, "gas", "ft³", "ft³", "", "volume", 1),
(IMPERIAL_SYSTEM, "monetary", "EUR", "EUR", "EUR", None, 1),
(IMPERIAL_SYSTEM, "monetary", "SEK", "SEK", "SEK", None, 1),
(IMPERIAL_SYSTEM, "volume", "", "", "", "volume", 1),
(IMPERIAL_SYSTEM, "volume", "ft³", "ft³", "", "volume", 1),
(METRIC_SYSTEM, "distance", "m", "m", "m", "distance", 1),
(METRIC_SYSTEM, "distance", "mi", "mi", "m", "distance", 1),
(METRIC_SYSTEM, "energy", "kWh", "kWh", "kWh", "energy", 1),
(METRIC_SYSTEM, "energy", "Wh", "Wh", "kWh", "energy", 1),
(METRIC_SYSTEM, "monetary", "EUR", "EUR", "EUR", None, 1),
(METRIC_SYSTEM, "monetary", "SEK", "SEK", "SEK", None, 1),
(METRIC_SYSTEM, "gas", "", "", "", "volume", 1),
(METRIC_SYSTEM, "gas", "ft³", "ft³", "", "volume", 1),
(METRIC_SYSTEM, "monetary", "EUR", "EUR", "EUR", None, 1),
(METRIC_SYSTEM, "monetary", "SEK", "SEK", "SEK", None, 1),
(METRIC_SYSTEM, "volume", "", "", "", "volume", 1),
(METRIC_SYSTEM, "volume", "ft³", "ft³", "", "volume", 1),
],
)
async def test_compile_hourly_sum_statistics_amount(
@ -1569,6 +1575,8 @@ def test_compile_hourly_energy_statistics_multiple(hass_recorder, caplog):
("speed", "mph", 30),
("temperature", "°C", 30),
("temperature", "°F", 30),
("volume", "", 30),
("volume", "ft³", 30),
],
)
def test_compile_hourly_statistics_unchanged(
@ -1660,6 +1668,8 @@ def test_compile_hourly_statistics_partially_unavailable(hass_recorder, caplog):
("speed", "mph", 30),
("temperature", "°C", 30),
("temperature", "°F", 30),
("volume", "", 30),
("volume", "ft³", 30),
],
)
def test_compile_hourly_statistics_unavailable(
@ -1751,6 +1761,10 @@ def test_compile_hourly_statistics_fails(hass_recorder, caplog):
("measurement", "speed", "mph", "mph", "m/s", "speed", "mean"),
("measurement", "temperature", "°C", "°C", "°C", "temperature", "mean"),
("measurement", "temperature", "°F", "°F", "°C", "temperature", "mean"),
("measurement", "volume", "", "", "", "volume", "mean"),
("measurement", "volume", "ft³", "ft³", "", "volume", "mean"),
("total", "volume", "", "", "", "volume", "sum"),
("total", "volume", "ft³", "ft³", "", "volume", "sum"),
],
)
def test_list_statistic_ids(