Add concentration conversion support for mg/m³ (#145325)

This commit is contained in:
Franck Nijhof 2025-05-23 15:24:18 +02:00 committed by GitHub
parent 0c9b1b5c58
commit bca4793c69
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 59 additions and 4 deletions

View File

@ -9,6 +9,7 @@ import voluptuous as vol
from homeassistant.const import (
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
CONCENTRATION_MILLIGRAMS_PER_CUBIC_METER,
CONCENTRATION_PARTS_PER_BILLION,
CONCENTRATION_PARTS_PER_MILLION,
DEGREE,
@ -370,7 +371,7 @@ class NumberDeviceClass(StrEnum):
VOLATILE_ORGANIC_COMPOUNDS = "volatile_organic_compounds"
"""Amount of VOC.
Unit of measurement: `µg/`
Unit of measurement: `µg/`, `mg/`
"""
VOLATILE_ORGANIC_COMPOUNDS_PARTS = "volatile_organic_compounds_parts"
@ -517,7 +518,8 @@ DEVICE_CLASS_UNITS: dict[NumberDeviceClass, set[type[StrEnum] | str | None]] = {
NumberDeviceClass.SULPHUR_DIOXIDE: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER},
NumberDeviceClass.TEMPERATURE: set(UnitOfTemperature),
NumberDeviceClass.VOLATILE_ORGANIC_COMPOUNDS: {
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
CONCENTRATION_MILLIGRAMS_PER_CUBIC_METER,
},
NumberDeviceClass.VOLATILE_ORGANIC_COMPOUNDS_PARTS: {
CONCENTRATION_PARTS_PER_BILLION,

View File

@ -55,6 +55,7 @@ from homeassistant.util.unit_conversion import (
EnergyDistanceConverter,
InformationConverter,
MassConverter,
MassVolumeConcentrationConverter,
PowerConverter,
PressureConverter,
ReactiveEnergyConverter,
@ -197,6 +198,9 @@ STATISTIC_UNIT_TO_UNIT_CONVERTER: dict[str | None, type[BaseUnitConverter]] = {
BloodGlucoseConcentrationConverter.VALID_UNITS,
BloodGlucoseConcentrationConverter,
),
**dict.fromkeys(
MassVolumeConcentrationConverter.VALID_UNITS, MassVolumeConcentrationConverter
),
**dict.fromkeys(ConductivityConverter.VALID_UNITS, ConductivityConverter),
**dict.fromkeys(DataRateConverter.VALID_UNITS, DataRateConverter),
**dict.fromkeys(DistanceConverter.VALID_UNITS, DistanceConverter),

View File

@ -28,6 +28,7 @@ from homeassistant.util.unit_conversion import (
EnergyDistanceConverter,
InformationConverter,
MassConverter,
MassVolumeConcentrationConverter,
PowerConverter,
PressureConverter,
ReactiveEnergyConverter,
@ -62,6 +63,9 @@ UNIT_SCHEMA = vol.Schema(
vol.Optional("blood_glucose_concentration"): vol.In(
BloodGlucoseConcentrationConverter.VALID_UNITS
),
vol.Optional("concentration"): vol.In(
MassVolumeConcentrationConverter.VALID_UNITS
),
vol.Optional("conductivity"): vol.In(ConductivityConverter.VALID_UNITS),
vol.Optional("data_rate"): vol.In(DataRateConverter.VALID_UNITS),
vol.Optional("distance"): vol.In(DistanceConverter.VALID_UNITS),

View File

@ -9,6 +9,7 @@ import voluptuous as vol
from homeassistant.const import (
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
CONCENTRATION_MILLIGRAMS_PER_CUBIC_METER,
CONCENTRATION_PARTS_PER_BILLION,
CONCENTRATION_PARTS_PER_MILLION,
DEGREE,
@ -57,6 +58,7 @@ from homeassistant.util.unit_conversion import (
EnergyDistanceConverter,
InformationConverter,
MassConverter,
MassVolumeConcentrationConverter,
PowerConverter,
PressureConverter,
ReactiveEnergyConverter,
@ -400,7 +402,7 @@ class SensorDeviceClass(StrEnum):
VOLATILE_ORGANIC_COMPOUNDS = "volatile_organic_compounds"
"""Amount of VOC.
Unit of measurement: `µg/`
Unit of measurement: `µg/`, `mg/`
"""
VOLATILE_ORGANIC_COMPOUNDS_PARTS = "volatile_organic_compounds_parts"
@ -540,6 +542,7 @@ UNIT_CONVERTERS: dict[SensorDeviceClass | str | None, type[BaseUnitConverter]] =
SensorDeviceClass.REACTIVE_ENERGY: ReactiveEnergyConverter,
SensorDeviceClass.SPEED: SpeedConverter,
SensorDeviceClass.TEMPERATURE: TemperatureConverter,
SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS: MassVolumeConcentrationConverter,
SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS_PARTS: UnitlessRatioConverter,
SensorDeviceClass.VOLTAGE: ElectricPotentialConverter,
SensorDeviceClass.VOLUME: VolumeConverter,
@ -617,7 +620,8 @@ DEVICE_CLASS_UNITS: dict[SensorDeviceClass, set[type[StrEnum] | str | None]] = {
SensorDeviceClass.SULPHUR_DIOXIDE: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER},
SensorDeviceClass.TEMPERATURE: set(UnitOfTemperature),
SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS: {
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
CONCENTRATION_MILLIGRAMS_PER_CUBIC_METER,
},
SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS_PARTS: {
CONCENTRATION_PARTS_PER_BILLION,

View File

@ -7,6 +7,8 @@ from functools import lru_cache
from math import floor, log10
from homeassistant.const import (
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
CONCENTRATION_MILLIGRAMS_PER_CUBIC_METER,
CONCENTRATION_PARTS_PER_BILLION,
CONCENTRATION_PARTS_PER_MILLION,
PERCENTAGE,
@ -686,6 +688,20 @@ class UnitlessRatioConverter(BaseUnitConverter):
}
class MassVolumeConcentrationConverter(BaseUnitConverter):
"""Utility to convert mass volume concentration values."""
UNIT_CLASS = "concentration"
_UNIT_CONVERSION: dict[str | None, float] = {
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER: 1000.0, # 1000 µg/m³ = 1 mg/m³
CONCENTRATION_MILLIGRAMS_PER_CUBIC_METER: 1.0,
}
VALID_UNITS = {
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
CONCENTRATION_MILLIGRAMS_PER_CUBIC_METER,
}
class VolumeConverter(BaseUnitConverter):
"""Utility to convert volume values."""

View File

@ -8,6 +8,8 @@ from itertools import chain
import pytest
from homeassistant.const import (
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
CONCENTRATION_MILLIGRAMS_PER_CUBIC_METER,
CONCENTRATION_PARTS_PER_BILLION,
CONCENTRATION_PARTS_PER_MILLION,
PERCENTAGE,
@ -48,6 +50,7 @@ from homeassistant.util.unit_conversion import (
EnergyDistanceConverter,
InformationConverter,
MassConverter,
MassVolumeConcentrationConverter,
PowerConverter,
PressureConverter,
ReactiveEnergyConverter,
@ -69,6 +72,7 @@ _ALL_CONVERTERS: dict[type[BaseUnitConverter], list[str | None]] = {
for converter in (
AreaConverter,
BloodGlucoseConcentrationConverter,
MassVolumeConcentrationConverter,
ConductivityConverter,
DataRateConverter,
DistanceConverter,
@ -128,6 +132,11 @@ _GET_UNIT_RATIO: dict[type[BaseUnitConverter], tuple[str | None, str | None, flo
),
InformationConverter: (UnitOfInformation.BITS, UnitOfInformation.BYTES, 8),
MassConverter: (UnitOfMass.STONES, UnitOfMass.KILOGRAMS, 0.157473),
MassVolumeConcentrationConverter: (
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
CONCENTRATION_MILLIGRAMS_PER_CUBIC_METER,
1000,
),
PowerConverter: (UnitOfPower.WATT, UnitOfPower.KILO_WATT, 1000),
PressureConverter: (UnitOfPressure.HPA, UnitOfPressure.INHG, 33.86389),
ReactiveEnergyConverter: (
@ -738,6 +747,22 @@ _CONVERTED_VALUE: dict[
(5, None, 5000000, CONCENTRATION_PARTS_PER_MILLION),
(5, PERCENTAGE, 0.05, None),
],
MassVolumeConcentrationConverter: [
# 1000 µg/m³ = 1 mg/m³
(
1000,
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
1,
CONCENTRATION_MILLIGRAMS_PER_CUBIC_METER,
),
# 2 mg/m³ = 2000 µg/m³
(
2,
CONCENTRATION_MILLIGRAMS_PER_CUBIC_METER,
2000,
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
),
],
VolumeConverter: [
(5, UnitOfVolume.LITERS, 1.32086, UnitOfVolume.GALLONS),
(5, UnitOfVolume.GALLONS, 18.92706, UnitOfVolume.LITERS),