diff --git a/homeassistant/components/energy/sensor.py b/homeassistant/components/energy/sensor.py index db156a2d6cc0e..c60c5c1151986 100644 --- a/homeassistant/components/energy/sensor.py +++ b/homeassistant/components/energy/sensor.py @@ -17,6 +17,7 @@ from homeassistant.components.sensor.recorder import reset_detected from homeassistant.const import ( ATTR_UNIT_OF_MEASUREMENT, + ENERGY_GIGA_JOULE, ENERGY_KILO_WATT_HOUR, ENERGY_MEGA_WATT_HOUR, ENERGY_WATT_HOUR, @@ -44,7 +45,12 @@ SensorStateClass.TOTAL, SensorStateClass.TOTAL_INCREASING, ] -VALID_ENERGY_UNITS = [ENERGY_WATT_HOUR, ENERGY_KILO_WATT_HOUR, ENERGY_MEGA_WATT_HOUR] +VALID_ENERGY_UNITS = [ + ENERGY_WATT_HOUR, + ENERGY_KILO_WATT_HOUR, + ENERGY_MEGA_WATT_HOUR, + ENERGY_GIGA_JOULE, +] VALID_ENERGY_UNITS_GAS = [VOLUME_CUBIC_FEET, VOLUME_CUBIC_METERS] + VALID_ENERGY_UNITS _LOGGER = logging.getLogger(__name__) @@ -233,7 +239,7 @@ def _reset(self, energy_state: State) -> None: self.async_write_ha_state() @callback - def _update_cost(self) -> None: + def _update_cost(self) -> None: # noqa: C901 """Update incurred costs.""" energy_state = self.hass.states.get( cast(str, self._config[self._adapter.stat_energy_key]) @@ -289,6 +295,11 @@ def _update_cost(self) -> None: ): energy_price /= 1000.0 + if energy_price_state.attributes.get(ATTR_UNIT_OF_MEASUREMENT, "").endswith( + f"/{ENERGY_GIGA_JOULE}" + ): + energy_price /= 1000 / 3.6 + else: energy_price_state = None energy_price = cast(float, self._config["number_energy_price"]) @@ -312,6 +323,8 @@ def _update_cost(self) -> None: energy_price /= 1000 elif energy_unit == ENERGY_MEGA_WATT_HOUR: energy_price *= 1000 + elif energy_unit == ENERGY_GIGA_JOULE: + energy_price *= 1000 / 3.6 if energy_unit is None: if not self._wrong_unit_reported: diff --git a/homeassistant/components/energy/validate.py b/homeassistant/components/energy/validate.py index b704330fa285e..17ac7227bf84e 100644 --- a/homeassistant/components/energy/validate.py +++ b/homeassistant/components/energy/validate.py @@ -9,6 +9,7 @@ from homeassistant.components import recorder, sensor from homeassistant.const import ( ATTR_DEVICE_CLASS, + ENERGY_GIGA_JOULE, ENERGY_KILO_WATT_HOUR, ENERGY_MEGA_WATT_HOUR, ENERGY_WATT_HOUR, @@ -28,6 +29,7 @@ ENERGY_KILO_WATT_HOUR, ENERGY_MEGA_WATT_HOUR, ENERGY_WATT_HOUR, + ENERGY_GIGA_JOULE, ) } ENERGY_PRICE_UNITS = tuple( @@ -44,6 +46,7 @@ ENERGY_WATT_HOUR, ENERGY_KILO_WATT_HOUR, ENERGY_MEGA_WATT_HOUR, + ENERGY_GIGA_JOULE, ), sensor.SensorDeviceClass.GAS: (VOLUME_CUBIC_METERS, VOLUME_CUBIC_FEET), } diff --git a/homeassistant/components/sensor/__init__.py b/homeassistant/components/sensor/__init__.py index fbe12652f35dc..d0f8148c2e888 100644 --- a/homeassistant/components/sensor/__init__.py +++ b/homeassistant/components/sensor/__init__.py @@ -147,7 +147,7 @@ class SensorDeviceClass(StrEnum): ENERGY = "energy" """Energy. - Unit of measurement: `Wh`, `kWh`, `MWh` + Unit of measurement: `Wh`, `kWh`, `MWh`, `GJ` """ FREQUENCY = "frequency" diff --git a/homeassistant/const.py b/homeassistant/const.py index 90a2dd345502a..e853584df80e1 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -487,9 +487,10 @@ class Platform(StrEnum): POWER_VOLT_AMPERE_REACTIVE: Final = "var" # Energy units -ENERGY_WATT_HOUR: Final = "Wh" +ENERGY_GIGA_JOULE: Final = "GJ" ENERGY_KILO_WATT_HOUR: Final = "kWh" ENERGY_MEGA_WATT_HOUR: Final = "MWh" +ENERGY_WATT_HOUR: Final = "Wh" # Electric_current units ELECTRIC_CURRENT_MILLIAMPERE: Final = "mA" diff --git a/homeassistant/util/unit_conversion.py b/homeassistant/util/unit_conversion.py index 0bf895f34a008..96b9006595401 100644 --- a/homeassistant/util/unit_conversion.py +++ b/homeassistant/util/unit_conversion.py @@ -2,6 +2,7 @@ from __future__ import annotations from homeassistant.const import ( + ENERGY_GIGA_JOULE, ENERGY_KILO_WATT_HOUR, ENERGY_MEGA_WATT_HOUR, ENERGY_WATT_HOUR, @@ -158,11 +159,13 @@ class EnergyConverter(BaseUnitConverter): ENERGY_WATT_HOUR: 1 * 1000, ENERGY_KILO_WATT_HOUR: 1, ENERGY_MEGA_WATT_HOUR: 1 / 1000, + ENERGY_GIGA_JOULE: 3.6 / 1000, } VALID_UNITS = { ENERGY_WATT_HOUR, ENERGY_KILO_WATT_HOUR, ENERGY_MEGA_WATT_HOUR, + ENERGY_GIGA_JOULE, } diff --git a/tests/components/energy/test_sensor.py b/tests/components/energy/test_sensor.py index 138c2494d6643..20dc533e70f2d 100644 --- a/tests/components/energy/test_sensor.py +++ b/tests/components/energy/test_sensor.py @@ -16,6 +16,7 @@ from homeassistant.const import ( ATTR_DEVICE_CLASS, ATTR_UNIT_OF_MEASUREMENT, + ENERGY_GIGA_JOULE, ENERGY_KILO_WATT_HOUR, ENERGY_MEGA_WATT_HOUR, ENERGY_WATT_HOUR, @@ -703,6 +704,7 @@ def _compile_statistics(_): (ENERGY_WATT_HOUR, 1000), (ENERGY_KILO_WATT_HOUR, 1), (ENERGY_MEGA_WATT_HOUR, 0.001), + (ENERGY_GIGA_JOULE, 0.001 * 3.6), ], ) async def test_cost_sensor_handle_energy_units( @@ -768,6 +770,7 @@ async def test_cost_sensor_handle_energy_units( (f"EUR/{ENERGY_WATT_HOUR}", 0.001), (f"EUR/{ENERGY_KILO_WATT_HOUR}", 1), (f"EUR/{ENERGY_MEGA_WATT_HOUR}", 1000), + (f"EUR/{ENERGY_GIGA_JOULE}", 1000 / 3.6), ], ) async def test_cost_sensor_handle_price_units( diff --git a/tests/components/energy/test_validate.py b/tests/components/energy/test_validate.py index a6d1578c78906..729e7685ac591 100644 --- a/tests/components/energy/test_validate.py +++ b/tests/components/energy/test_validate.py @@ -5,6 +5,7 @@ from homeassistant.components.energy import async_get_manager, validate from homeassistant.const import ( + ENERGY_GIGA_JOULE, ENERGY_KILO_WATT_HOUR, ENERGY_MEGA_WATT_HOUR, ENERGY_WATT_HOUR, @@ -73,6 +74,7 @@ async def test_validation_empty_config(hass): ("total", ENERGY_KILO_WATT_HOUR, {}), ("total", ENERGY_KILO_WATT_HOUR, {"last_reset": "abc"}), ("measurement", ENERGY_KILO_WATT_HOUR, {"last_reset": "abc"}), + ("total_increasing", ENERGY_GIGA_JOULE, {}), ], ) async def test_validation( diff --git a/tests/util/test_unit_conversion.py b/tests/util/test_unit_conversion.py index 98be32584c68d..486d2199e18a8 100644 --- a/tests/util/test_unit_conversion.py +++ b/tests/util/test_unit_conversion.py @@ -2,6 +2,7 @@ import pytest from homeassistant.const import ( + ENERGY_GIGA_JOULE, ENERGY_KILO_WATT_HOUR, ENERGY_MEGA_WATT_HOUR, ENERGY_WATT_HOUR, @@ -78,6 +79,7 @@ (EnergyConverter, ENERGY_WATT_HOUR), (EnergyConverter, ENERGY_KILO_WATT_HOUR), (EnergyConverter, ENERGY_MEGA_WATT_HOUR), + (EnergyConverter, ENERGY_GIGA_JOULE), (MassConverter, MASS_GRAMS), (MassConverter, MASS_KILOGRAMS), (MassConverter, MASS_MICROGRAMS), @@ -268,6 +270,8 @@ def test_distance_convert( (10, ENERGY_KILO_WATT_HOUR, 0.01, ENERGY_MEGA_WATT_HOUR), (10, ENERGY_MEGA_WATT_HOUR, 10000000, ENERGY_WATT_HOUR), (10, ENERGY_MEGA_WATT_HOUR, 10000, ENERGY_KILO_WATT_HOUR), + (10, ENERGY_GIGA_JOULE, 10000 / 3.6, ENERGY_KILO_WATT_HOUR), + (10, ENERGY_GIGA_JOULE, 10 / 3.6, ENERGY_MEGA_WATT_HOUR), ], ) def test_energy_convert(