diff --git a/homeassistant/components/number/const.py b/homeassistant/components/number/const.py index e6abd3b4d390..4400e76191b7 100644 --- a/homeassistant/components/number/const.py +++ b/homeassistant/components/number/const.py @@ -265,7 +265,7 @@ class NumberDeviceClass(StrEnum): OZONE = "ozone" """Amount of O3. - Unit of measurement: `μg/m³` + Unit of measurement: `ppb` (parts per billion), `μg/m³` """ PH = "ph" @@ -523,7 +523,10 @@ DEVICE_CLASS_UNITS: dict[NumberDeviceClass, set[type[StrEnum] | str | None]] = { }, NumberDeviceClass.NITROGEN_MONOXIDE: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, NumberDeviceClass.NITROUS_OXIDE: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, - NumberDeviceClass.OZONE: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, + NumberDeviceClass.OZONE: { + CONCENTRATION_PARTS_PER_BILLION, + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + }, NumberDeviceClass.PH: {None}, NumberDeviceClass.PM1: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, NumberDeviceClass.PM10: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, diff --git a/homeassistant/components/recorder/statistics.py b/homeassistant/components/recorder/statistics.py index 3d7e814851ce..5e8c6302012e 100644 --- a/homeassistant/components/recorder/statistics.py +++ b/homeassistant/components/recorder/statistics.py @@ -60,6 +60,7 @@ from homeassistant.util.unit_conversion import ( MassConverter, MassVolumeConcentrationConverter, NitrogenDioxideConcentrationConverter, + OzoneConcentrationConverter, PowerConverter, PressureConverter, ReactiveEnergyConverter, @@ -228,6 +229,7 @@ _SECONDARY_UNIT_CONVERTERS: list[type[BaseUnitConverter]] = [ CarbonMonoxideConcentrationConverter, NitrogenDioxideConcentrationConverter, TemperatureDeltaConverter, + OzoneConcentrationConverter, SulphurDioxideConcentrationConverter, ] diff --git a/homeassistant/components/recorder/websocket_api.py b/homeassistant/components/recorder/websocket_api.py index e2d83808887b..e497b073fdd5 100644 --- a/homeassistant/components/recorder/websocket_api.py +++ b/homeassistant/components/recorder/websocket_api.py @@ -34,6 +34,7 @@ from homeassistant.util.unit_conversion import ( MassConverter, MassVolumeConcentrationConverter, NitrogenDioxideConcentrationConverter, + OzoneConcentrationConverter, PowerConverter, PressureConverter, ReactiveEnergyConverter, @@ -94,6 +95,7 @@ UNIT_SCHEMA = vol.Schema( vol.Optional("nitrogen_dioxide"): vol.In( NitrogenDioxideConcentrationConverter.VALID_UNITS ), + vol.Optional("ozone"): vol.In(OzoneConcentrationConverter.VALID_UNITS), vol.Optional("power"): vol.In(PowerConverter.VALID_UNITS), vol.Optional("pressure"): vol.In(PressureConverter.VALID_UNITS), vol.Optional("reactive_energy"): vol.In(ReactiveEnergyConverter.VALID_UNITS), diff --git a/homeassistant/components/sensor/const.py b/homeassistant/components/sensor/const.py index 995531226dba..be6cc4ea3a53 100644 --- a/homeassistant/components/sensor/const.py +++ b/homeassistant/components/sensor/const.py @@ -64,6 +64,7 @@ from homeassistant.util.unit_conversion import ( MassConverter, MassVolumeConcentrationConverter, NitrogenDioxideConcentrationConverter, + OzoneConcentrationConverter, PowerConverter, PressureConverter, ReactiveEnergyConverter, @@ -302,7 +303,7 @@ class SensorDeviceClass(StrEnum): OZONE = "ozone" """Amount of O3. - Unit of measurement: `μg/m³` + Unit of measurement: `ppb` (parts per billion),`μg/m³` """ PH = "ph" @@ -565,6 +566,7 @@ UNIT_CONVERTERS: dict[SensorDeviceClass | str | None, type[BaseUnitConverter]] = SensorDeviceClass.ENERGY_STORAGE: EnergyConverter, SensorDeviceClass.GAS: VolumeConverter, SensorDeviceClass.NITROGEN_DIOXIDE: NitrogenDioxideConcentrationConverter, + SensorDeviceClass.OZONE: OzoneConcentrationConverter, SensorDeviceClass.POWER: PowerConverter, SensorDeviceClass.POWER_FACTOR: UnitlessRatioConverter, SensorDeviceClass.PRECIPITATION: DistanceConverter, @@ -639,7 +641,10 @@ DEVICE_CLASS_UNITS: dict[SensorDeviceClass, set[type[StrEnum] | str | None]] = { }, SensorDeviceClass.NITROGEN_MONOXIDE: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, SensorDeviceClass.NITROUS_OXIDE: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, - SensorDeviceClass.OZONE: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, + SensorDeviceClass.OZONE: { + CONCENTRATION_PARTS_PER_BILLION, + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + }, SensorDeviceClass.PH: {None}, SensorDeviceClass.PM1: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, SensorDeviceClass.PM10: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, diff --git a/homeassistant/util/unit_conversion.py b/homeassistant/util/unit_conversion.py index d3989509ca6f..daae62861a41 100644 --- a/homeassistant/util/unit_conversion.py +++ b/homeassistant/util/unit_conversion.py @@ -104,6 +104,7 @@ _AMBIENT_IDEAL_GAS_MOLAR_VOLUME = ( # m3⋅mol⁻¹ # Molar masses in g⋅mol⁻¹ _CARBON_MONOXIDE_MOLAR_MASS = 28.01 _NITROGEN_DIOXIDE_MOLAR_MASS = 46.0055 +_OZONE_MOLAR_MASS = 48.00 _SULPHUR_DIOXIDE_MOLAR_MASS = 64.066 @@ -562,6 +563,22 @@ class ReactivePowerConverter(BaseUnitConverter): } +class OzoneConcentrationConverter(BaseUnitConverter): + """Convert ozone ratio to mass per volume.""" + + UNIT_CLASS = "ozone" + _UNIT_CONVERSION: dict[str | None, float] = { + CONCENTRATION_PARTS_PER_BILLION: 1e9, + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER: ( + _OZONE_MOLAR_MASS / _AMBIENT_IDEAL_GAS_MOLAR_VOLUME * 1e6 + ), + } + VALID_UNITS = { + CONCENTRATION_PARTS_PER_BILLION, + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + } + + class SpeedConverter(BaseUnitConverter): """Utility to convert speed values.""" diff --git a/tests/components/sensor/test_init.py b/tests/components/sensor/test_init.py index 59ec2cb1966f..b25eaa0a4d0f 100644 --- a/tests/components/sensor/test_init.py +++ b/tests/components/sensor/test_init.py @@ -3109,7 +3109,6 @@ def test_device_class_converters_are_complete() -> None: SensorDeviceClass.MONETARY, SensorDeviceClass.NITROGEN_MONOXIDE, SensorDeviceClass.NITROUS_OXIDE, - SensorDeviceClass.OZONE, SensorDeviceClass.PH, SensorDeviceClass.PM1, SensorDeviceClass.PM10, diff --git a/tests/util/test_unit_conversion.py b/tests/util/test_unit_conversion.py index 2fbe10135d80..82a275e1d73f 100644 --- a/tests/util/test_unit_conversion.py +++ b/tests/util/test_unit_conversion.py @@ -57,6 +57,7 @@ from homeassistant.util.unit_conversion import ( MassConverter, MassVolumeConcentrationConverter, NitrogenDioxideConcentrationConverter, + OzoneConcentrationConverter, PowerConverter, PressureConverter, ReactiveEnergyConverter, @@ -93,6 +94,7 @@ _ALL_CONVERTERS: dict[type[BaseUnitConverter], list[str | None]] = { InformationConverter, MassConverter, ApparentPowerConverter, + OzoneConcentrationConverter, PowerConverter, PressureConverter, ReactiveEnergyConverter, @@ -167,6 +169,11 @@ _GET_UNIT_RATIO: dict[type[BaseUnitConverter], tuple[str | None, str | None, flo CONCENTRATION_PARTS_PER_BILLION, 1.912503, ), + OzoneConcentrationConverter: ( + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + CONCENTRATION_PARTS_PER_BILLION, + 1.995417, + ), PowerConverter: (UnitOfPower.WATT, UnitOfPower.KILO_WATT, 1000), PressureConverter: (UnitOfPressure.HPA, UnitOfPressure.INHG, 33.86389), ReactiveEnergyConverter: ( @@ -735,6 +742,20 @@ _CONVERTED_VALUE: dict[ (1, UnitOfMass.STONES, 14, UnitOfMass.POUNDS), (1, UnitOfMass.STONES, 224, UnitOfMass.OUNCES), ], + OzoneConcentrationConverter: [ + ( + 1, + CONCENTRATION_PARTS_PER_BILLION, + 1.995417, + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + ), + ( + 120, + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + 60.1378, + CONCENTRATION_PARTS_PER_BILLION, + ), + ], PowerConverter: [ (10, UnitOfPower.KILO_WATT, 10000, UnitOfPower.WATT), (10, UnitOfPower.MEGA_WATT, 10e6, UnitOfPower.WATT),