Cost sensor handle consumption sensor in Wh (#53746)

This commit is contained in:
Paulus Schoutsen 2021-07-30 02:00:52 -07:00 committed by GitHub
parent 05a7853720
commit 2cbcd5f2a9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 107 additions and 6 deletions

View file

@ -3,6 +3,7 @@ from __future__ import annotations
from dataclasses import dataclass from dataclasses import dataclass
from functools import partial from functools import partial
import logging
from typing import Any, Final, Literal, TypeVar, cast from typing import Any, Final, Literal, TypeVar, cast
from homeassistant.components.sensor import ( from homeassistant.components.sensor import (
@ -11,6 +12,11 @@ from homeassistant.components.sensor import (
STATE_CLASS_MEASUREMENT, STATE_CLASS_MEASUREMENT,
SensorEntity, SensorEntity,
) )
from homeassistant.const import (
ATTR_UNIT_OF_MEASUREMENT,
ENERGY_KILO_WATT_HOUR,
ENERGY_WATT_HOUR,
)
from homeassistant.core import HomeAssistant, State, callback, split_entity_id from homeassistant.core import HomeAssistant, State, callback, split_entity_id
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.event import async_track_state_change_event from homeassistant.helpers.event import async_track_state_change_event
@ -20,6 +26,8 @@ import homeassistant.util.dt as dt_util
from .const import DOMAIN from .const import DOMAIN
from .data import EnergyManager, async_get_manager from .data import EnergyManager, async_get_manager
_LOGGER = logging.getLogger(__name__)
async def async_setup_platform( async def async_setup_platform(
hass: HomeAssistant, hass: HomeAssistant,
@ -188,6 +196,12 @@ class EnergyCostSensor(SensorEntity):
energy_price = float(energy_price_state.state) energy_price = float(energy_price_state.state)
except ValueError: except ValueError:
return return
if energy_price_state.attributes.get(ATTR_UNIT_OF_MEASUREMENT, "").endswith(
f"/{ENERGY_WATT_HOUR}"
):
energy_price *= 1000.0
else: else:
energy_price_state = None energy_price_state = None
energy_price = cast(float, self._flow["number_energy_price"]) energy_price = cast(float, self._flow["number_energy_price"])
@ -197,6 +211,16 @@ class EnergyCostSensor(SensorEntity):
self._reset(energy_state) self._reset(energy_state)
return return
energy_unit = energy_state.attributes.get(ATTR_UNIT_OF_MEASUREMENT)
if energy_unit == ENERGY_WATT_HOUR:
energy_price /= 1000
elif energy_unit != ENERGY_KILO_WATT_HOUR:
_LOGGER.warning(
"Found unexpected unit %s for %s", energy_unit, energy_state.entity_id
)
return
if ( if (
energy_state.attributes[ATTR_LAST_RESET] energy_state.attributes[ATTR_LAST_RESET]
!= self._last_energy_sensor_state.attributes[ATTR_LAST_RESET] != self._last_energy_sensor_state.attributes[ATTR_LAST_RESET]

View file

@ -16,6 +16,8 @@ from homeassistant.const import (
ATTR_DEVICE_CLASS, ATTR_DEVICE_CLASS,
ATTR_UNIT_OF_MEASUREMENT, ATTR_UNIT_OF_MEASUREMENT,
DEVICE_CLASS_MONETARY, DEVICE_CLASS_MONETARY,
ENERGY_KILO_WATT_HOUR,
ENERGY_WATT_HOUR,
) )
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
@ -133,7 +135,9 @@ async def test_cost_sensor_price_entity(
# Optionally initialize dependent entities # Optionally initialize dependent entities
if initial_energy is not None: if initial_energy is not None:
hass.states.async_set( hass.states.async_set(
usage_sensor_entity_id, initial_energy, {"last_reset": last_reset} usage_sensor_entity_id,
initial_energy,
{"last_reset": last_reset, ATTR_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR},
) )
hass.states.async_set("sensor.energy_price", "1") hass.states.async_set("sensor.energy_price", "1")
@ -152,7 +156,12 @@ async def test_cost_sensor_price_entity(
if initial_energy is None: if initial_energy is None:
with patch("homeassistant.util.dt.utcnow", return_value=now): with patch("homeassistant.util.dt.utcnow", return_value=now):
hass.states.async_set( hass.states.async_set(
usage_sensor_entity_id, "0", {"last_reset": last_reset} usage_sensor_entity_id,
"0",
{
"last_reset": last_reset,
ATTR_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR,
},
) )
await hass.async_block_till_done() await hass.async_block_till_done()
@ -169,7 +178,11 @@ async def test_cost_sensor_price_entity(
# # assert entry.unique_id == "energy_energy_consumption cost" # # assert entry.unique_id == "energy_energy_consumption cost"
# Energy use bumped to 10 kWh # Energy use bumped to 10 kWh
hass.states.async_set(usage_sensor_entity_id, "10", {"last_reset": last_reset}) hass.states.async_set(
usage_sensor_entity_id,
"10",
{"last_reset": last_reset, ATTR_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR},
)
await hass.async_block_till_done() await hass.async_block_till_done()
state = hass.states.get(cost_sensor_entity_id) state = hass.states.get(cost_sensor_entity_id)
assert state.state == "10.0" # 0 EUR + (10-0) kWh * 1 EUR/kWh = 10 EUR assert state.state == "10.0" # 0 EUR + (10-0) kWh * 1 EUR/kWh = 10 EUR
@ -189,7 +202,11 @@ async def test_cost_sensor_price_entity(
assert state.state == "10.0" # 10 EUR + (10-10) kWh * 2 EUR/kWh = 10 EUR assert state.state == "10.0" # 10 EUR + (10-10) kWh * 2 EUR/kWh = 10 EUR
# Additional consumption is using the new price # Additional consumption is using the new price
hass.states.async_set(usage_sensor_entity_id, "14.5", {"last_reset": last_reset}) hass.states.async_set(
usage_sensor_entity_id,
"14.5",
{"last_reset": last_reset, ATTR_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR},
)
await hass.async_block_till_done() await hass.async_block_till_done()
state = hass.states.get(cost_sensor_entity_id) state = hass.states.get(cost_sensor_entity_id)
assert state.state == "19.0" # 10 EUR + (14.5-10) kWh * 2 EUR/kWh = 19 EUR assert state.state == "19.0" # 10 EUR + (14.5-10) kWh * 2 EUR/kWh = 19 EUR
@ -202,13 +219,21 @@ async def test_cost_sensor_price_entity(
# Energy sensor is reset, with start point at 4kWh # Energy sensor is reset, with start point at 4kWh
last_reset = (now + timedelta(seconds=1)).isoformat() last_reset = (now + timedelta(seconds=1)).isoformat()
hass.states.async_set(usage_sensor_entity_id, "4", {"last_reset": last_reset}) hass.states.async_set(
usage_sensor_entity_id,
"4",
{"last_reset": last_reset, ATTR_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR},
)
await hass.async_block_till_done() await hass.async_block_till_done()
state = hass.states.get(cost_sensor_entity_id) state = hass.states.get(cost_sensor_entity_id)
assert state.state == "0.0" # 0 EUR + (4-4) kWh * 2 EUR/kWh = 0 EUR assert state.state == "0.0" # 0 EUR + (4-4) kWh * 2 EUR/kWh = 0 EUR
# Energy use bumped to 10 kWh # Energy use bumped to 10 kWh
hass.states.async_set(usage_sensor_entity_id, "10", {"last_reset": last_reset}) hass.states.async_set(
usage_sensor_entity_id,
"10",
{"last_reset": last_reset, ATTR_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR},
)
await hass.async_block_till_done() await hass.async_block_till_done()
state = hass.states.get(cost_sensor_entity_id) state = hass.states.get(cost_sensor_entity_id)
assert state.state == "12.0" # 0 EUR + (10-4) kWh * 2 EUR/kWh = 12 EUR assert state.state == "12.0" # 0 EUR + (10-4) kWh * 2 EUR/kWh = 12 EUR
@ -218,3 +243,55 @@ async def test_cost_sensor_price_entity(
statistics = await hass.loop.run_in_executor(None, _compile_statistics, hass) statistics = await hass.loop.run_in_executor(None, _compile_statistics, hass)
assert cost_sensor_entity_id in statistics assert cost_sensor_entity_id in statistics
assert statistics[cost_sensor_entity_id]["stat"]["sum"] == 31.0 assert statistics[cost_sensor_entity_id]["stat"]["sum"] == 31.0
async def test_cost_sensor_handle_wh(hass, hass_storage) -> None:
"""Test energy cost price from sensor entity."""
energy_data = data.EnergyManager.default_preferences()
energy_data["energy_sources"].append(
{
"type": "grid",
"flow_from": [
{
"stat_energy_from": "sensor.energy_consumption",
"entity_energy_from": "sensor.energy_consumption",
"stat_cost": None,
"entity_energy_price": None,
"number_energy_price": 0.5,
}
],
"flow_to": [],
"cost_adjustment_day": 0,
}
)
hass_storage[data.STORAGE_KEY] = {
"version": 1,
"data": energy_data,
}
now = dt_util.utcnow()
last_reset = dt_util.utc_from_timestamp(0).isoformat()
hass.states.async_set(
"sensor.energy_consumption",
10000,
{"last_reset": last_reset, "unit_of_measurement": ENERGY_WATT_HOUR},
)
with patch("homeassistant.util.dt.utcnow", return_value=now):
await setup_integration(hass)
state = hass.states.get("sensor.energy_consumption_cost")
assert state.state == "0.0"
# Energy use bumped to 10 kWh
hass.states.async_set(
"sensor.energy_consumption",
20000,
{"last_reset": last_reset, "unit_of_measurement": ENERGY_WATT_HOUR},
)
await hass.async_block_till_done()
state = hass.states.get("sensor.energy_consumption_cost")
assert state.state == "5.0"