diff --git a/homeassistant/components/energy/sensor.py b/homeassistant/components/energy/sensor.py index e228e11d00d777..6c430fab3604df 100644 --- a/homeassistant/components/energy/sensor.py +++ b/homeassistant/components/energy/sensor.py @@ -715,6 +715,9 @@ def _update_state(self) -> None: self._attr_native_value = None return + self._attr_native_unit_of_measurement = source_state.attributes.get( + ATTR_UNIT_OF_MEASUREMENT + ) self._attr_native_value = value * -1 elif self._is_combined: @@ -763,13 +766,11 @@ async def async_added_to_hass(self) -> None: # Check first sensor if source_entry := entity_reg.async_get(self._source_sensors[0]): device_id = source_entry.device_id - # For combined mode, always use Watts because we may have different source units; for inverted mode, copy source unit + # Combined mode always emits Watts because we convert + # heterogeneous source units internally. For inverted mode the + # unit is copied from the source state in _update_state. if self._is_combined: self._attr_native_unit_of_measurement = UnitOfPower.WATT - else: - self._attr_native_unit_of_measurement = ( - source_entry.unit_of_measurement - ) # Get source name from registry source_name = source_entry.name or source_entry.original_name # Assign power sensor to same device as source sensor(s) diff --git a/tests/components/energy/test_sensor.py b/tests/components/energy/test_sensor.py index ffdf754e38d935..dd15b891a9bf4b 100644 --- a/tests/components/energy/test_sensor.py +++ b/tests/components/energy/test_sensor.py @@ -1427,6 +1427,92 @@ async def test_power_sensor_manager_creation( state = hass.states.get("sensor.battery_power_inverted") assert state is not None assert float(state.state) == -100.0 + assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == UnitOfPower.WATT + + +async def test_power_sensor_inverted_propagates_unit( + recorder_mock: Recorder, hass: HomeAssistant +) -> None: + """Test inverted power sensor copies unit from the source state.""" + assert await async_setup_component(hass, "energy", {"energy": {}}) + manager = await async_get_manager(hass) + manager.data = manager.default_preferences() + + # Use a non-default unit to prove we copy from the source rather than + # hard-coding Watts. + hass.states.async_set( + "sensor.battery_power", + "1.5", + {ATTR_UNIT_OF_MEASUREMENT: UnitOfPower.KILO_WATT}, + ) + await hass.async_block_till_done() + + await manager.async_update( + { + "energy_sources": [ + { + "type": "battery", + "stat_energy_from": "sensor.battery_energy_from", + "stat_energy_to": "sensor.battery_energy_to", + "power_config": { + "stat_rate_inverted": "sensor.battery_power", + }, + } + ], + } + ) + await hass.async_block_till_done() + + state = hass.states.get("sensor.battery_power_inverted") + assert state is not None + assert float(state.state) == -1.5 + assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == UnitOfPower.KILO_WATT + + # Source switches to Watts — the inverted sensor should follow. + hass.states.async_set( + "sensor.battery_power", + "200.0", + {ATTR_UNIT_OF_MEASUREMENT: UnitOfPower.WATT}, + ) + await hass.async_block_till_done() + + state = hass.states.get("sensor.battery_power_inverted") + assert state is not None + assert float(state.state) == -200.0 + assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == UnitOfPower.WATT + + +async def test_power_sensor_inverted_source_without_unit( + recorder_mock: Recorder, hass: HomeAssistant +) -> None: + """Test inverted sensor reports no unit when source has none.""" + assert await async_setup_component(hass, "energy", {"energy": {}}) + manager = await async_get_manager(hass) + manager.data = manager.default_preferences() + + hass.states.async_set("sensor.battery_power", "100.0") + await hass.async_block_till_done() + + await manager.async_update( + { + "energy_sources": [ + { + "type": "battery", + "stat_energy_from": "sensor.battery_energy_from", + "stat_energy_to": "sensor.battery_energy_to", + "power_config": { + "stat_rate_inverted": "sensor.battery_power", + }, + } + ], + } + ) + await hass.async_block_till_done() + + state = hass.states.get("sensor.battery_power_inverted") + assert state is not None + assert float(state.state) == -100.0 + assert ATTR_UNIT_OF_MEASUREMENT not in state.attributes async def test_power_sensor_manager_cleanup(