From 91b4903c7edf54710d1ff183ccae045ac5649ef7 Mon Sep 17 00:00:00 2001 From: Julian Meier Date: Tue, 11 Nov 2025 20:47:49 +0100 Subject: [PATCH 1/3] Add watt-second as unit of energy --- homeassistant/components/number/const.py | 4 ++-- homeassistant/components/sensor/const.py | 4 ++-- homeassistant/const.py | 1 + homeassistant/util/unit_conversion.py | 1 + tests/components/template/test_config_flow.py | 2 +- tests/util/test_unit_conversion.py | 2 ++ 6 files changed, 9 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/number/const.py b/homeassistant/components/number/const.py index 55b8335acc5cc..b3a3763a483c4 100644 --- a/homeassistant/components/number/const.py +++ b/homeassistant/components/number/const.py @@ -175,7 +175,7 @@ class NumberDeviceClass(StrEnum): ENERGY = "energy" """Energy. - Unit of measurement: `J`, `kJ`, `MJ`, `GJ`, `mWh`, `Wh`, `kWh`, `MWh`, `GWh`, `TWh`, `cal`, `kcal`, `Mcal`, `Gcal` + Unit of measurement: `J`, `kJ`, `MJ`, `GJ`, `Ws`, `mWh`, `Wh`, `kWh`, `MWh`, `GWh`, `TWh`, `cal`, `kcal`, `Mcal`, `Gcal` """ ENERGY_DISTANCE = "energy_distance" @@ -193,7 +193,7 @@ class NumberDeviceClass(StrEnum): Use this device class for sensors measuring stored energy, for example the amount of electric energy currently stored in a battery or the capacity of a battery. - Unit of measurement: `J`, `kJ`, `MJ`, `GJ`, `mWh`, `Wh`, `kWh`, `MWh`, `GWh`, `TWh`, `cal`, `kcal`, `Mcal`, `Gcal` + Unit of measurement: `J`, `kJ`, `MJ`, `GJ`, `Ws`, `mWh`, `Wh`, `kWh`, `MWh`, `GWh`, `TWh`, `cal`, `kcal`, `Mcal`, `Gcal` """ FREQUENCY = "frequency" diff --git a/homeassistant/components/sensor/const.py b/homeassistant/components/sensor/const.py index 2731e9f6b03f5..9b9e481d3bdac 100644 --- a/homeassistant/components/sensor/const.py +++ b/homeassistant/components/sensor/const.py @@ -210,7 +210,7 @@ class SensorDeviceClass(StrEnum): Use this device class for sensors measuring energy consumption, for example electric energy consumption. - Unit of measurement: `J`, `kJ`, `MJ`, `GJ`, `mWh`, `Wh`, `kWh`, `MWh`, `GWh`, `TWh`, `cal`, `kcal`, `Mcal`, `Gcal` + Unit of measurement: `J`, `kJ`, `MJ`, `GJ`, `Ws`, `mWh`, `Wh`, `kWh`, `MWh`, `GWh`, `TWh`, `cal`, `kcal`, `Mcal`, `Gcal` """ ENERGY_DISTANCE = "energy_distance" @@ -228,7 +228,7 @@ class SensorDeviceClass(StrEnum): Use this device class for sensors measuring stored energy, for example the amount of electric energy currently stored in a battery or the capacity of a battery. - Unit of measurement: `J`, `kJ`, `MJ`, `GJ`, `mWh`, `Wh`, `kWh`, `MWh`, `GWh`, `TWh`, `cal`, `kcal`, `Mcal`, `Gcal` + Unit of measurement: `J`, `kJ`, `MJ`, `GJ`, `Ws`, `mWh`, `Wh`, `kWh`, `MWh`, `GWh`, `TWh`, `cal`, `kcal`, `Mcal`, `Gcal` """ FREQUENCY = "frequency" diff --git a/homeassistant/const.py b/homeassistant/const.py index 0ff91587e86ec..ad8646f72d85e 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -488,6 +488,7 @@ class UnitOfEnergy(StrEnum): KILO_JOULE = "kJ" MEGA_JOULE = "MJ" GIGA_JOULE = "GJ" + WATT_SECOND = "Ws" MILLIWATT_HOUR = "mWh" WATT_HOUR = "Wh" KILO_WATT_HOUR = "kWh" diff --git a/homeassistant/util/unit_conversion.py b/homeassistant/util/unit_conversion.py index b25895c3e8f43..8d4e1737814a6 100644 --- a/homeassistant/util/unit_conversion.py +++ b/homeassistant/util/unit_conversion.py @@ -334,6 +334,7 @@ class EnergyConverter(BaseUnitConverter): UnitOfEnergy.KILO_JOULE: _WH_TO_J, UnitOfEnergy.MEGA_JOULE: _WH_TO_J / 1e3, UnitOfEnergy.GIGA_JOULE: _WH_TO_J / 1e6, + UnitOfEnergy.WATT_SECOND: 3.6e6, UnitOfEnergy.MILLIWATT_HOUR: 1e6, UnitOfEnergy.WATT_HOUR: 1e3, UnitOfEnergy.KILO_WATT_HOUR: 1, diff --git a/tests/components/template/test_config_flow.py b/tests/components/template/test_config_flow.py index 08b087c2eca8b..9e5a90b31277b 100644 --- a/tests/components/template/test_config_flow.py +++ b/tests/components/template/test_config_flow.py @@ -1063,7 +1063,7 @@ async def test_config_flow_preview( ), "unit_of_measurement": ( "'None' is not a valid unit for device class 'energy'; " - "expected one of 'cal', 'Gcal', 'GJ', 'GWh', 'J', 'kcal', 'kJ', 'kWh', 'Mcal', 'MJ', 'MWh', 'mWh', 'TWh', 'Wh'" + "expected one of 'cal', 'Gcal', 'GJ', 'GWh', 'J', 'kcal', 'kJ', 'kWh', 'Mcal', 'MJ', 'MWh', 'mWh', 'TWh', 'Wh', 'Ws'" ), }, ), diff --git a/tests/util/test_unit_conversion.py b/tests/util/test_unit_conversion.py index 345c0bbfd51df..691b851f984de 100644 --- a/tests/util/test_unit_conversion.py +++ b/tests/util/test_unit_conversion.py @@ -536,12 +536,14 @@ (5, UnitOfElectricPotential.MEGAVOLT, 5e3, UnitOfElectricPotential.KILOVOLT), ], EnergyConverter: [ + (10, UnitOfEnergy.WATT_SECOND, 2.77778e-3, UnitOfEnergy.WATT_HOUR), (10, UnitOfEnergy.MILLIWATT_HOUR, 0.00001, UnitOfEnergy.KILO_WATT_HOUR), (10, UnitOfEnergy.WATT_HOUR, 10000, UnitOfEnergy.MILLIWATT_HOUR), (10, UnitOfEnergy.WATT_HOUR, 0.01, UnitOfEnergy.KILO_WATT_HOUR), (10, UnitOfEnergy.WATT_HOUR, 0.00001, UnitOfEnergy.MEGA_WATT_HOUR), (10, UnitOfEnergy.WATT_HOUR, 0.00000001, UnitOfEnergy.GIGA_WATT_HOUR), (10, UnitOfEnergy.WATT_HOUR, 0.00000000001, UnitOfEnergy.TERA_WATT_HOUR), + (10, UnitOfEnergy.KILO_WATT_HOUR, 3.6e7, UnitOfEnergy.WATT_SECOND), (10, UnitOfEnergy.KILO_WATT_HOUR, 10000, UnitOfEnergy.WATT_HOUR), (10, UnitOfEnergy.KILO_WATT_HOUR, 0.01, UnitOfEnergy.MEGA_WATT_HOUR), (10, UnitOfEnergy.MEGA_WATT_HOUR, 10000000, UnitOfEnergy.WATT_HOUR), From 82568bc2678a13dc96a36a5dd6b0a3ee5b17fd65 Mon Sep 17 00:00:00 2001 From: Julian Meier Date: Wed, 12 Nov 2025 20:47:38 +0100 Subject: [PATCH 2/3] Add constant for Wh to Ws conversion --- homeassistant/util/unit_conversion.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/homeassistant/util/unit_conversion.py b/homeassistant/util/unit_conversion.py index 8d4e1737814a6..864942d72b88a 100644 --- a/homeassistant/util/unit_conversion.py +++ b/homeassistant/util/unit_conversion.py @@ -74,6 +74,7 @@ # Energy conversion constants _WH_TO_J = 3600 # 1 Wh = 3600 J _WH_TO_CAL = _WH_TO_J / 4.184 # 1 Wh = 860.42065 cal +_WH_TO_WS = 3600 # 1 Wh = 3600 Ws # Mass conversion constants _POUND_TO_G = 453.59237 @@ -334,7 +335,7 @@ class EnergyConverter(BaseUnitConverter): UnitOfEnergy.KILO_JOULE: _WH_TO_J, UnitOfEnergy.MEGA_JOULE: _WH_TO_J / 1e3, UnitOfEnergy.GIGA_JOULE: _WH_TO_J / 1e6, - UnitOfEnergy.WATT_SECOND: 3.6e6, + UnitOfEnergy.WATT_SECOND: _WH_TO_WS * 1e3, UnitOfEnergy.MILLIWATT_HOUR: 1e6, UnitOfEnergy.WATT_HOUR: 1e3, UnitOfEnergy.KILO_WATT_HOUR: 1, From d867526c4352f384493e4397c10218a99fad77c2 Mon Sep 17 00:00:00 2001 From: Julian Meier Date: Thu, 13 Nov 2025 07:09:56 +0100 Subject: [PATCH 3/3] Remove duplicate constant --- homeassistant/util/unit_conversion.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/homeassistant/util/unit_conversion.py b/homeassistant/util/unit_conversion.py index 864942d72b88a..1667c255fd37c 100644 --- a/homeassistant/util/unit_conversion.py +++ b/homeassistant/util/unit_conversion.py @@ -72,9 +72,8 @@ _DAYS_TO_SECS = 24 * _HRS_TO_SECS # 1 day = 24 hours = 86400 seconds # Energy conversion constants -_WH_TO_J = 3600 # 1 Wh = 3600 J +_WH_TO_J = 3600 # 1 Wh = 3600 J = 3600 Ws _WH_TO_CAL = _WH_TO_J / 4.184 # 1 Wh = 860.42065 cal -_WH_TO_WS = 3600 # 1 Wh = 3600 Ws # Mass conversion constants _POUND_TO_G = 453.59237 @@ -335,7 +334,7 @@ class EnergyConverter(BaseUnitConverter): UnitOfEnergy.KILO_JOULE: _WH_TO_J, UnitOfEnergy.MEGA_JOULE: _WH_TO_J / 1e3, UnitOfEnergy.GIGA_JOULE: _WH_TO_J / 1e6, - UnitOfEnergy.WATT_SECOND: _WH_TO_WS * 1e3, + UnitOfEnergy.WATT_SECOND: _WH_TO_J * 1e3, UnitOfEnergy.MILLIWATT_HOUR: 1e6, UnitOfEnergy.WATT_HOUR: 1e3, UnitOfEnergy.KILO_WATT_HOUR: 1,