Add device class gas and enable statistics for it (#54110)

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
Co-authored-by: Erik Montnemery <erik@montnemery.com>
This commit is contained in:
Bram Kragten 2021-08-11 18:58:19 +02:00 committed by GitHub
parent 94a264afaf
commit e23750b2a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 146 additions and 39 deletions

View File

@ -9,6 +9,7 @@ from homeassistant.components.sensor import STATE_CLASS_MEASUREMENT
from homeassistant.const import (
DEVICE_CLASS_CURRENT,
DEVICE_CLASS_ENERGY,
DEVICE_CLASS_GAS,
DEVICE_CLASS_POWER,
DEVICE_CLASS_VOLTAGE,
)
@ -256,6 +257,7 @@ SENSORS: tuple[DSMRSensorEntityDescription, ...] = (
is_gas=True,
force_update=True,
icon="mdi:fire",
device_class=DEVICE_CLASS_GAS,
last_reset=dt.utc_from_timestamp(0),
state_class=STATE_CLASS_MEASUREMENT,
),
@ -266,6 +268,7 @@ SENSORS: tuple[DSMRSensorEntityDescription, ...] = (
is_gas=True,
force_update=True,
icon="mdi:fire",
device_class=DEVICE_CLASS_GAS,
last_reset=dt.utc_from_timestamp(0),
state_class=STATE_CLASS_MEASUREMENT,
),
@ -276,6 +279,7 @@ SENSORS: tuple[DSMRSensorEntityDescription, ...] = (
is_gas=True,
force_update=True,
icon="mdi:fire",
device_class=DEVICE_CLASS_GAS,
last_reset=dt.utc_from_timestamp(0),
state_class=STATE_CLASS_MEASUREMENT,
),

View File

@ -16,7 +16,12 @@ import voluptuous as vol
from homeassistant.components.sensor import PLATFORM_SCHEMA, SensorEntity
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
from homeassistant.const import CONF_HOST, CONF_PORT, EVENT_HOMEASSISTANT_STOP
from homeassistant.const import (
CONF_HOST,
CONF_PORT,
EVENT_HOMEASSISTANT_STOP,
VOLUME_CUBIC_METERS,
)
from homeassistant.core import CoreState, HomeAssistant, callback
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback
@ -56,6 +61,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
}
)
UNIT_CONVERSION = {"m3": VOLUME_CUBIC_METERS}
async def async_setup_platform(
hass: HomeAssistant,
@ -260,7 +267,10 @@ class DSMREntity(SensorEntity):
@property
def native_unit_of_measurement(self) -> str | None:
"""Return the unit of measurement of this entity, if any."""
return self.get_dsmr_object_attr("unit")
unit_of_measurement = self.get_dsmr_object_attr("unit")
if unit_of_measurement in UNIT_CONVERSION:
return UNIT_CONVERSION[unit_of_measurement]
return unit_of_measurement
@staticmethod
def translate_tariff(value: str, dsmr_version: str) -> str | None:

View File

@ -11,13 +11,19 @@ from sqlalchemy import bindparam
from sqlalchemy.ext import baked
from sqlalchemy.orm.scoping import scoped_session
from homeassistant.const import PRESSURE_PA, TEMP_CELSIUS
from homeassistant.const import (
PRESSURE_PA,
TEMP_CELSIUS,
VOLUME_CUBIC_FEET,
VOLUME_CUBIC_METERS,
)
from homeassistant.core import Event, HomeAssistant, callback
from homeassistant.helpers import entity_registry
import homeassistant.util.dt as dt_util
import homeassistant.util.pressure as pressure_util
import homeassistant.util.temperature as temperature_util
from homeassistant.util.unit_system import UnitSystem
import homeassistant.util.volume as volume_util
from .const import DOMAIN
from .models import (
@ -64,6 +70,11 @@ UNIT_CONVERSIONS = {
)
if x is not None
else None,
VOLUME_CUBIC_METERS: lambda x, units: volume_util.convert(
x, VOLUME_CUBIC_METERS, _configured_unit(VOLUME_CUBIC_METERS, units)
)
if x is not None
else None,
}
_LOGGER = logging.getLogger(__name__)
@ -214,6 +225,10 @@ def _configured_unit(unit: str, units: UnitSystem) -> str:
return units.pressure_unit
if unit == TEMP_CELSIUS:
return units.temperature_unit
if unit == VOLUME_CUBIC_METERS:
if units.is_metric:
return VOLUME_CUBIC_METERS
return VOLUME_CUBIC_FEET
return unit

View File

@ -17,6 +17,7 @@ from homeassistant.const import (
DEVICE_CLASS_CO2,
DEVICE_CLASS_CURRENT,
DEVICE_CLASS_ENERGY,
DEVICE_CLASS_GAS,
DEVICE_CLASS_HUMIDITY,
DEVICE_CLASS_ILLUMINANCE,
DEVICE_CLASS_MONETARY,
@ -65,6 +66,7 @@ DEVICE_CLASSES: Final[list[str]] = [
DEVICE_CLASS_POWER, # power (W/kW)
DEVICE_CLASS_POWER_FACTOR, # power factor (%)
DEVICE_CLASS_VOLTAGE, # voltage (V)
DEVICE_CLASS_GAS, # gas (m³ or ft³)
]
DEVICE_CLASSES_SCHEMA: Final = vol.All(vol.Lower, vol.In(DEVICE_CLASSES))

View File

@ -16,6 +16,7 @@ from homeassistant.const import (
DEVICE_CLASS_CO2,
DEVICE_CLASS_CURRENT,
DEVICE_CLASS_ENERGY,
DEVICE_CLASS_GAS,
DEVICE_CLASS_HUMIDITY,
DEVICE_CLASS_ILLUMINANCE,
DEVICE_CLASS_POWER,
@ -46,6 +47,7 @@ CONF_IS_CO2 = "is_carbon_dioxide"
CONF_IS_CURRENT = "is_current"
CONF_IS_ENERGY = "is_energy"
CONF_IS_HUMIDITY = "is_humidity"
CONF_IS_GAS = "is_gas"
CONF_IS_ILLUMINANCE = "is_illuminance"
CONF_IS_POWER = "is_power"
CONF_IS_POWER_FACTOR = "is_power_factor"
@ -61,6 +63,7 @@ ENTITY_CONDITIONS = {
DEVICE_CLASS_CO2: [{CONF_TYPE: CONF_IS_CO2}],
DEVICE_CLASS_CURRENT: [{CONF_TYPE: CONF_IS_CURRENT}],
DEVICE_CLASS_ENERGY: [{CONF_TYPE: CONF_IS_ENERGY}],
DEVICE_CLASS_GAS: [{CONF_TYPE: CONF_IS_GAS}],
DEVICE_CLASS_HUMIDITY: [{CONF_TYPE: CONF_IS_HUMIDITY}],
DEVICE_CLASS_ILLUMINANCE: [{CONF_TYPE: CONF_IS_ILLUMINANCE}],
DEVICE_CLASS_POWER: [{CONF_TYPE: CONF_IS_POWER}],
@ -83,6 +86,7 @@ CONDITION_SCHEMA = vol.All(
CONF_IS_CO2,
CONF_IS_CURRENT,
CONF_IS_ENERGY,
CONF_IS_GAS,
CONF_IS_HUMIDITY,
CONF_IS_ILLUMINANCE,
CONF_IS_POWER,

View File

@ -19,6 +19,7 @@ from homeassistant.const import (
DEVICE_CLASS_CO2,
DEVICE_CLASS_CURRENT,
DEVICE_CLASS_ENERGY,
DEVICE_CLASS_GAS,
DEVICE_CLASS_HUMIDITY,
DEVICE_CLASS_ILLUMINANCE,
DEVICE_CLASS_POWER,
@ -44,6 +45,7 @@ CONF_CO = "carbon_monoxide"
CONF_CO2 = "carbon_dioxide"
CONF_CURRENT = "current"
CONF_ENERGY = "energy"
CONF_GAS = "gas"
CONF_HUMIDITY = "humidity"
CONF_ILLUMINANCE = "illuminance"
CONF_POWER = "power"
@ -60,6 +62,7 @@ ENTITY_TRIGGERS = {
DEVICE_CLASS_CO2: [{CONF_TYPE: CONF_CO2}],
DEVICE_CLASS_CURRENT: [{CONF_TYPE: CONF_CURRENT}],
DEVICE_CLASS_ENERGY: [{CONF_TYPE: CONF_ENERGY}],
DEVICE_CLASS_GAS: [{CONF_TYPE: CONF_GAS}],
DEVICE_CLASS_HUMIDITY: [{CONF_TYPE: CONF_HUMIDITY}],
DEVICE_CLASS_ILLUMINANCE: [{CONF_TYPE: CONF_ILLUMINANCE}],
DEVICE_CLASS_POWER: [{CONF_TYPE: CONF_POWER}],
@ -83,6 +86,7 @@ TRIGGER_SCHEMA = vol.All(
CONF_CO2,
CONF_CURRENT,
CONF_ENERGY,
CONF_GAS,
CONF_HUMIDITY,
CONF_ILLUMINANCE,
CONF_POWER,

View File

@ -11,6 +11,7 @@ from homeassistant.components.sensor import (
ATTR_STATE_CLASS,
DEVICE_CLASS_BATTERY,
DEVICE_CLASS_ENERGY,
DEVICE_CLASS_GAS,
DEVICE_CLASS_HUMIDITY,
DEVICE_CLASS_MONETARY,
DEVICE_CLASS_PRESSURE,
@ -35,11 +36,14 @@ from homeassistant.const import (
TEMP_CELSIUS,
TEMP_FAHRENHEIT,
TEMP_KELVIN,
VOLUME_CUBIC_FEET,
VOLUME_CUBIC_METERS,
)
from homeassistant.core import HomeAssistant, State
import homeassistant.util.dt as dt_util
import homeassistant.util.pressure as pressure_util
import homeassistant.util.temperature as temperature_util
import homeassistant.util.volume as volume_util
from . import ATTR_LAST_RESET, DOMAIN
@ -53,6 +57,7 @@ DEVICE_CLASS_OR_UNIT_STATISTICS = {
DEVICE_CLASS_POWER: {"mean", "min", "max"},
DEVICE_CLASS_PRESSURE: {"mean", "min", "max"},
DEVICE_CLASS_TEMPERATURE: {"mean", "min", "max"},
DEVICE_CLASS_GAS: {"sum"},
PERCENTAGE: {"mean", "min", "max"},
}
@ -62,6 +67,7 @@ DEVICE_CLASS_UNITS = {
DEVICE_CLASS_POWER: POWER_WATT,
DEVICE_CLASS_PRESSURE: PRESSURE_PA,
DEVICE_CLASS_TEMPERATURE: TEMP_CELSIUS,
DEVICE_CLASS_GAS: VOLUME_CUBIC_METERS,
}
UNIT_CONVERSIONS: dict[str, dict[str, Callable]] = {
@ -92,6 +98,11 @@ UNIT_CONVERSIONS: dict[str, dict[str, Callable]] = {
TEMP_FAHRENHEIT: temperature_util.fahrenheit_to_celsius,
TEMP_KELVIN: temperature_util.kelvin_to_celsius,
},
# Convert volume to cubic meter
DEVICE_CLASS_GAS: {
VOLUME_CUBIC_METERS: lambda x: x,
VOLUME_CUBIC_FEET: volume_util.cubic_feet_to_cubic_meter,
},
}
# Keep track of entities for which a warning about unsupported unit has been logged

View File

@ -5,6 +5,7 @@
"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_gas": "Current {entity_name} gas",
"is_humidity": "Current {entity_name} humidity",
"is_illuminance": "Current {entity_name} illuminance",
"is_power": "Current {entity_name} power",
@ -21,6 +22,7 @@
"battery_level": "{entity_name} battery level changes",
"carbon_monoxide": "{entity_name} carbon monoxide concentration changes",
"carbon_dioxide": "{entity_name} carbon dioxide concentration changes",
"gas": "{entity_name} gas changes",
"humidity": "{entity_name} humidity changes",
"illuminance": "{entity_name} illuminance changes",
"power": "{entity_name} power changes",

View File

@ -18,10 +18,12 @@ from homeassistant.const import (
ATTR_ICON,
ATTR_NAME,
ATTR_UNIT_OF_MEASUREMENT,
DEVICE_CLASS_GAS,
ENERGY_KILO_WATT_HOUR,
PERCENTAGE,
POWER_WATT,
TEMP_CELSIUS,
VOLUME_CUBIC_METERS,
)
from homeassistant.util import dt as dt_util
@ -38,7 +40,6 @@ DEFAULT_MIN_TEMP = 6.0
CURRENCY_EUR = "EUR"
VOLUME_CM3 = "CM3"
VOLUME_M3 = "M3"
VOLUME_LHOUR = "L/H"
VOLUME_LMIN = "L/MIN"
@ -125,7 +126,8 @@ SENSOR_ENTITIES = {
ATTR_NAME: "Average Daily Gas Usage",
ATTR_SECTION: "gas_usage",
ATTR_MEASUREMENT: "day_average",
ATTR_UNIT_OF_MEASUREMENT: VOLUME_M3,
ATTR_DEVICE_CLASS: DEVICE_CLASS_GAS,
ATTR_UNIT_OF_MEASUREMENT: VOLUME_CUBIC_METERS,
ATTR_ICON: "mdi:gas-cylinder",
ATTR_DEFAULT_ENABLED: False,
},
@ -133,7 +135,8 @@ SENSOR_ENTITIES = {
ATTR_NAME: "Gas Usage Today",
ATTR_SECTION: "gas_usage",
ATTR_MEASUREMENT: "day_usage",
ATTR_UNIT_OF_MEASUREMENT: VOLUME_M3,
ATTR_DEVICE_CLASS: DEVICE_CLASS_GAS,
ATTR_UNIT_OF_MEASUREMENT: VOLUME_CUBIC_METERS,
ATTR_ICON: "mdi:gas-cylinder",
},
"gas_daily_cost": {
@ -147,9 +150,10 @@ SENSOR_ENTITIES = {
ATTR_NAME: "Gas Meter",
ATTR_SECTION: "gas_usage",
ATTR_MEASUREMENT: "meter",
ATTR_UNIT_OF_MEASUREMENT: VOLUME_M3,
ATTR_UNIT_OF_MEASUREMENT: VOLUME_CUBIC_METERS,
ATTR_ICON: "mdi:gas-cylinder",
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
ATTR_DEVICE_CLASS: DEVICE_CLASS_GAS,
ATTR_LAST_RESET: dt_util.utc_from_timestamp(0),
ATTR_DEFAULT_ENABLED: False,
},
@ -321,7 +325,7 @@ SENSOR_ENTITIES = {
ATTR_NAME: "Average Daily Water Usage",
ATTR_SECTION: "water_usage",
ATTR_MEASUREMENT: "day_average",
ATTR_UNIT_OF_MEASUREMENT: VOLUME_M3,
ATTR_UNIT_OF_MEASUREMENT: VOLUME_CUBIC_METERS,
ATTR_ICON: "mdi:water",
ATTR_DEFAULT_ENABLED: False,
},
@ -329,7 +333,7 @@ SENSOR_ENTITIES = {
ATTR_NAME: "Water Usage Today",
ATTR_SECTION: "water_usage",
ATTR_MEASUREMENT: "day_usage",
ATTR_UNIT_OF_MEASUREMENT: VOLUME_M3,
ATTR_UNIT_OF_MEASUREMENT: VOLUME_CUBIC_METERS,
ATTR_ICON: "mdi:water",
ATTR_DEFAULT_ENABLED: False,
},
@ -337,7 +341,7 @@ SENSOR_ENTITIES = {
ATTR_NAME: "Water Meter",
ATTR_SECTION: "water_usage",
ATTR_MEASUREMENT: "meter",
ATTR_UNIT_OF_MEASUREMENT: VOLUME_M3,
ATTR_UNIT_OF_MEASUREMENT: VOLUME_CUBIC_METERS,
ATTR_ICON: "mdi:water",
ATTR_DEFAULT_ENABLED: False,
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,

View File

@ -247,6 +247,7 @@ DEVICE_CLASS_SIGNAL_STRENGTH: Final = "signal_strength"
DEVICE_CLASS_TEMPERATURE: Final = "temperature"
DEVICE_CLASS_TIMESTAMP: Final = "timestamp"
DEVICE_CLASS_VOLTAGE: Final = "voltage"
DEVICE_CLASS_GAS: Final = "gas"
# #### STATES ####
STATE_ON: Final = "on"

View File

@ -6,6 +6,8 @@ from numbers import Number
from homeassistant.const import (
UNIT_NOT_RECOGNIZED_TEMPLATE,
VOLUME,
VOLUME_CUBIC_FEET,
VOLUME_CUBIC_METERS,
VOLUME_FLUID_OUNCE,
VOLUME_GALLONS,
VOLUME_LITERS,
@ -17,19 +19,31 @@ VALID_UNITS: tuple[str, ...] = (
VOLUME_MILLILITERS,
VOLUME_GALLONS,
VOLUME_FLUID_OUNCE,
VOLUME_CUBIC_METERS,
VOLUME_CUBIC_FEET,
)
def __liter_to_gallon(liter: float) -> float:
def liter_to_gallon(liter: float) -> float:
"""Convert a volume measurement in Liter to Gallon."""
return liter * 0.2642
def __gallon_to_liter(gallon: float) -> float:
def gallon_to_liter(gallon: float) -> float:
"""Convert a volume measurement in Gallon to Liter."""
return gallon * 3.785
def cubic_meter_to_cubic_feet(cubic_meter: float) -> float:
"""Convert a volume measurement in cubic meter to cubic feet."""
return cubic_meter * 35.3146667
def cubic_feet_to_cubic_meter(cubic_feet: float) -> float:
"""Convert a volume measurement in cubic feet to cubic meter."""
return cubic_feet * 0.0283168466
def convert(volume: float, from_unit: str, to_unit: str) -> float:
"""Convert a temperature from one unit to another."""
if from_unit not in VALID_UNITS:
@ -45,8 +59,12 @@ def convert(volume: float, from_unit: str, to_unit: str) -> float:
result: float = volume
if from_unit == VOLUME_LITERS and to_unit == VOLUME_GALLONS:
result = __liter_to_gallon(volume)
result = liter_to_gallon(volume)
elif from_unit == VOLUME_GALLONS and to_unit == VOLUME_LITERS:
result = __gallon_to_liter(volume)
result = gallon_to_liter(volume)
elif from_unit == VOLUME_CUBIC_METERS and to_unit == VOLUME_CUBIC_FEET:
result = cubic_meter_to_cubic_feet(volume)
elif from_unit == VOLUME_CUBIC_FEET and to_unit == VOLUME_CUBIC_METERS:
result = cubic_feet_to_cubic_meter(volume)
return result

View File

@ -24,6 +24,7 @@ from homeassistant.const import (
ATTR_ICON,
ATTR_UNIT_OF_MEASUREMENT,
DEVICE_CLASS_ENERGY,
DEVICE_CLASS_GAS,
DEVICE_CLASS_POWER,
ENERGY_KILO_WATT_HOUR,
STATE_UNKNOWN,
@ -104,7 +105,7 @@ async def test_default_setup(hass, dsmr_connection_fixture):
GAS_METER_READING: MBusObject(
[
{"value": datetime.datetime.fromtimestamp(1551642213)},
{"value": Decimal(745.695), "unit": VOLUME_CUBIC_METERS},
{"value": Decimal(745.695), "unit": "m3"},
]
),
}
@ -164,7 +165,7 @@ async def test_default_setup(hass, dsmr_connection_fixture):
# check if gas consumption is parsed correctly
gas_consumption = hass.states.get("sensor.gas_consumption")
assert gas_consumption.state == "745.695"
assert gas_consumption.attributes.get(ATTR_DEVICE_CLASS) is None
assert gas_consumption.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_GAS
assert gas_consumption.attributes.get(ATTR_ICON) == "mdi:fire"
assert gas_consumption.attributes.get(ATTR_LAST_RESET) is not None
assert gas_consumption.attributes.get(ATTR_STATE_CLASS) == STATE_CLASS_MEASUREMENT
@ -228,7 +229,7 @@ async def test_v4_meter(hass, dsmr_connection_fixture):
HOURLY_GAS_METER_READING: MBusObject(
[
{"value": datetime.datetime.fromtimestamp(1551642213)},
{"value": Decimal(745.695), "unit": VOLUME_CUBIC_METERS},
{"value": Decimal(745.695), "unit": "m3"},
]
),
ELECTRICITY_ACTIVE_TARIFF: CosemObject([{"value": "0001", "unit": ""}]),
@ -263,8 +264,8 @@ async def test_v4_meter(hass, dsmr_connection_fixture):
# check if gas consumption is parsed correctly
gas_consumption = hass.states.get("sensor.gas_consumption")
assert gas_consumption.state == "745.695"
assert gas_consumption.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_GAS
assert gas_consumption.attributes.get("unit_of_measurement") == VOLUME_CUBIC_METERS
assert gas_consumption.attributes.get(ATTR_DEVICE_CLASS) is None
assert gas_consumption.attributes.get(ATTR_ICON) == "mdi:fire"
assert gas_consumption.attributes.get(ATTR_LAST_RESET) is not None
assert gas_consumption.attributes.get(ATTR_STATE_CLASS) == STATE_CLASS_MEASUREMENT
@ -299,7 +300,7 @@ async def test_v5_meter(hass, dsmr_connection_fixture):
HOURLY_GAS_METER_READING: MBusObject(
[
{"value": datetime.datetime.fromtimestamp(1551642213)},
{"value": Decimal(745.695), "unit": VOLUME_CUBIC_METERS},
{"value": Decimal(745.695), "unit": "m3"},
]
),
ELECTRICITY_ACTIVE_TARIFF: CosemObject([{"value": "0001", "unit": ""}]),
@ -334,7 +335,7 @@ async def test_v5_meter(hass, dsmr_connection_fixture):
# check if gas consumption is parsed correctly
gas_consumption = hass.states.get("sensor.gas_consumption")
assert gas_consumption.state == "745.695"
assert gas_consumption.attributes.get(ATTR_DEVICE_CLASS) is None
assert gas_consumption.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_GAS
assert gas_consumption.attributes.get(ATTR_ICON) == "mdi:fire"
assert gas_consumption.attributes.get(ATTR_LAST_RESET) is not None
assert gas_consumption.attributes.get(ATTR_STATE_CLASS) == STATE_CLASS_MEASUREMENT
@ -370,7 +371,7 @@ async def test_luxembourg_meter(hass, dsmr_connection_fixture):
HOURLY_GAS_METER_READING: MBusObject(
[
{"value": datetime.datetime.fromtimestamp(1551642213)},
{"value": Decimal(745.695), "unit": VOLUME_CUBIC_METERS},
{"value": Decimal(745.695), "unit": "m3"},
]
),
LUXEMBOURG_ELECTRICITY_USED_TARIFF_GLOBAL: CosemObject(
@ -415,7 +416,7 @@ async def test_luxembourg_meter(hass, dsmr_connection_fixture):
# check if gas consumption is parsed correctly
gas_consumption = hass.states.get("sensor.gas_consumption")
assert gas_consumption.state == "745.695"
assert gas_consumption.attributes.get(ATTR_DEVICE_CLASS) is None
assert gas_consumption.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_GAS
assert gas_consumption.attributes.get(ATTR_ICON) == "mdi:fire"
assert gas_consumption.attributes.get(ATTR_LAST_RESET) is not None
assert gas_consumption.attributes.get(ATTR_STATE_CLASS) == STATE_CLASS_MEASUREMENT
@ -450,7 +451,7 @@ async def test_belgian_meter(hass, dsmr_connection_fixture):
BELGIUM_HOURLY_GAS_METER_READING: MBusObject(
[
{"value": datetime.datetime.fromtimestamp(1551642213)},
{"value": Decimal(745.695), "unit": VOLUME_CUBIC_METERS},
{"value": Decimal(745.695), "unit": "m3"},
]
),
ELECTRICITY_ACTIVE_TARIFF: CosemObject([{"value": "0001", "unit": ""}]),
@ -485,7 +486,7 @@ async def test_belgian_meter(hass, dsmr_connection_fixture):
# check if gas consumption is parsed correctly
gas_consumption = hass.states.get("sensor.gas_consumption")
assert gas_consumption.state == "745.695"
assert gas_consumption.attributes.get(ATTR_DEVICE_CLASS) is None
assert gas_consumption.attributes.get(ATTR_DEVICE_CLASS) is DEVICE_CLASS_GAS
assert gas_consumption.attributes.get(ATTR_ICON) == "mdi:fire"
assert gas_consumption.attributes.get(ATTR_LAST_RESET) is not None
assert gas_consumption.attributes.get(ATTR_STATE_CLASS) == STATE_CLASS_MEASUREMENT

View File

@ -86,7 +86,7 @@ async def test_get_triggers(hass, device_reg, entity_reg, enable_custom_integrat
if device_class != "none"
]
triggers = await async_get_device_automations(hass, "trigger", device_entry.id)
assert len(triggers) == 13
assert len(triggers) == 14
assert triggers == expected_triggers

View File

@ -39,6 +39,11 @@ TEMPERATURE_SENSOR_ATTRIBUTES = {
"state_class": "measurement",
"unit_of_measurement": "°C",
}
GAS_SENSOR_ATTRIBUTES = {
"device_class": "gas",
"state_class": "measurement",
"unit_of_measurement": "",
}
@pytest.mark.parametrize(
@ -154,11 +159,13 @@ def test_compile_hourly_statistics_unsupported(hass_recorder, caplog, attributes
[
("energy", "kWh", "kWh", 1),
("energy", "Wh", "kWh", 1 / 1000),
("monetary", "", "", 1),
("monetary", "EUR", "EUR", 1),
("monetary", "SEK", "SEK", 1),
("gas", "", "", 1),
("gas", "ft³", "", 0.0283168466),
],
)
def test_compile_hourly_energy_statistics(
def test_compile_hourly_sum_statistics(
hass_recorder, caplog, device_class, unit, native_unit, factor
):
"""Test compiling hourly statistics."""
@ -174,7 +181,7 @@ def test_compile_hourly_energy_statistics(
}
seq = [10, 15, 20, 10, 30, 40, 50, 60, 70]
four, eight, states = record_energy_states(
four, eight, states = record_meter_states(
hass, zero, "sensor.test1", attributes, seq
)
hist = history.get_significant_states(
@ -254,14 +261,14 @@ def test_compile_hourly_energy_statistics_unsupported(hass_recorder, caplog):
seq3 = [0, 0, 5, 10, 30, 50, 60, 80, 90]
seq4 = [0, 0, 5, 10, 30, 50, 60, 80, 90]
four, eight, states = record_energy_states(
four, eight, states = record_meter_states(
hass, zero, "sensor.test1", sns1_attr, seq1
)
_, _, _states = record_energy_states(hass, zero, "sensor.test2", sns2_attr, seq2)
_, _, _states = record_meter_states(hass, zero, "sensor.test2", sns2_attr, seq2)
states = {**states, **_states}
_, _, _states = record_energy_states(hass, zero, "sensor.test3", sns3_attr, seq3)
_, _, _states = record_meter_states(hass, zero, "sensor.test3", sns3_attr, seq3)
states = {**states, **_states}
_, _, _states = record_energy_states(hass, zero, "sensor.test4", sns4_attr, seq4)
_, _, _states = record_meter_states(hass, zero, "sensor.test4", sns4_attr, seq4)
states = {**states, **_states}
hist = history.get_significant_states(
@ -336,14 +343,14 @@ def test_compile_hourly_energy_statistics_multiple(hass_recorder, caplog):
seq3 = [0, 0, 5, 10, 30, 50, 60, 80, 90]
seq4 = [0, 0, 5, 10, 30, 50, 60, 80, 90]
four, eight, states = record_energy_states(
four, eight, states = record_meter_states(
hass, zero, "sensor.test1", sns1_attr, seq1
)
_, _, _states = record_energy_states(hass, zero, "sensor.test2", sns2_attr, seq2)
_, _, _states = record_meter_states(hass, zero, "sensor.test2", sns2_attr, seq2)
states = {**states, **_states}
_, _, _states = record_energy_states(hass, zero, "sensor.test3", sns3_attr, seq3)
_, _, _states = record_meter_states(hass, zero, "sensor.test3", sns3_attr, seq3)
states = {**states, **_states}
_, _, _states = record_energy_states(hass, zero, "sensor.test4", sns4_attr, seq4)
_, _, _states = record_meter_states(hass, zero, "sensor.test4", sns4_attr, seq4)
states = {**states, **_states}
hist = history.get_significant_states(
hass, zero - timedelta.resolution, eight + timedelta.resolution
@ -632,6 +639,8 @@ def test_compile_hourly_statistics_fails(hass_recorder, caplog):
("humidity", None, None, "mean"),
("monetary", "USD", "USD", "sum"),
("monetary", "None", "None", "sum"),
("gas", "", "", "sum"),
("gas", "ft³", "", "sum"),
("pressure", "Pa", "Pa", "mean"),
("pressure", "hPa", "Pa", "mean"),
("pressure", "mbar", "Pa", "mean"),
@ -697,7 +706,7 @@ def test_list_statistic_ids_unsupported(hass_recorder, caplog, _attributes):
def record_states(hass, zero, entity_id, attributes):
"""Record some test states.
We inject a bunch of state updates for temperature sensors.
We inject a bunch of state updates for measurement sensors.
"""
attributes = dict(attributes)
@ -725,10 +734,10 @@ def record_states(hass, zero, entity_id, attributes):
return four, states
def record_energy_states(hass, zero, entity_id, _attributes, seq):
def record_meter_states(hass, zero, entity_id, _attributes, seq):
"""Record some test states.
We inject a bunch of state updates for energy sensors.
We inject a bunch of state updates for meter sensors.
"""
def set_state(entity_id, state, **kwargs):

View File

@ -9,6 +9,7 @@ from homeassistant.const import (
PERCENTAGE,
PRESSURE_HPA,
SIGNAL_STRENGTH_DECIBELS,
VOLUME_CUBIC_METERS,
)
from tests.common import MockEntity
@ -30,6 +31,7 @@ UNITS_OF_MEASUREMENT = {
sensor.DEVICE_CLASS_ENERGY: "kWh", # energy (Wh/kWh)
sensor.DEVICE_CLASS_POWER_FACTOR: PERCENTAGE, # power factor (no unit, min: -1.0, max: 1.0)
sensor.DEVICE_CLASS_VOLTAGE: "V", # voltage (V)
sensor.DEVICE_CLASS_GAS: VOLUME_CUBIC_METERS, # gas (m³)
}
ENTITIES = {}

View File

@ -3,6 +3,8 @@
import pytest
from homeassistant.const import (
VOLUME_CUBIC_FEET,
VOLUME_CUBIC_METERS,
VOLUME_FLUID_OUNCE,
VOLUME_GALLONS,
VOLUME_LITERS,
@ -47,3 +49,21 @@ def test_convert_from_gallons():
"""Test conversion from gallons to other units."""
gallons = 5
assert volume_util.convert(gallons, VOLUME_GALLONS, VOLUME_LITERS) == 18.925
def test_convert_from_cubic_meters():
"""Test conversion from cubic meter to other units."""
cubic_meters = 5
assert (
volume_util.convert(cubic_meters, VOLUME_CUBIC_METERS, VOLUME_CUBIC_FEET)
== 176.5733335
)
def test_convert_from_cubic_feet():
"""Test conversion from cubic feet to cubic meters to other units."""
cubic_feets = 500
assert (
volume_util.convert(cubic_feets, VOLUME_CUBIC_FEET, VOLUME_CUBIC_METERS)
== 14.1584233
)