mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 21:27:38 +00:00
Add kWh as cost option for gas (#58426)
* Add kWh as cost option for GAS * Add kWh as cost option for GAS (pylint) * Add kWh as cost option for GAS (make CONST) * Change GAS_UNITS to VALID_ENERGY_UNITS * Add test for Gas cost in kWh (2) * Back off ENERGY_WATT_HOUR - unlikely for gas * Add MEGA_WATT_HOUR support (2) * Normalise pricing for MEGA_WATT_HOUR * Normalise pricing for MEGA_WATT_HOUR
This commit is contained in:
parent
0111b28a67
commit
39998f5387
@ -20,6 +20,7 @@ from homeassistant.components.sensor.recorder import reset_detected
|
|||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
ATTR_UNIT_OF_MEASUREMENT,
|
ATTR_UNIT_OF_MEASUREMENT,
|
||||||
ENERGY_KILO_WATT_HOUR,
|
ENERGY_KILO_WATT_HOUR,
|
||||||
|
ENERGY_MEGA_WATT_HOUR,
|
||||||
ENERGY_WATT_HOUR,
|
ENERGY_WATT_HOUR,
|
||||||
VOLUME_CUBIC_METERS,
|
VOLUME_CUBIC_METERS,
|
||||||
)
|
)
|
||||||
@ -43,6 +44,8 @@ SUPPORTED_STATE_CLASSES = [
|
|||||||
STATE_CLASS_TOTAL,
|
STATE_CLASS_TOTAL,
|
||||||
STATE_CLASS_TOTAL_INCREASING,
|
STATE_CLASS_TOTAL_INCREASING,
|
||||||
]
|
]
|
||||||
|
VALID_ENERGY_UNITS = [ENERGY_WATT_HOUR, ENERGY_KILO_WATT_HOUR, ENERGY_MEGA_WATT_HOUR]
|
||||||
|
VALID_ENERGY_UNITS_GAS = [VOLUME_CUBIC_METERS] + VALID_ENERGY_UNITS
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@ -289,14 +292,16 @@ class EnergyCostSensor(SensorEntity):
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
return
|
return
|
||||||
|
|
||||||
if (
|
if energy_price_state.attributes.get(ATTR_UNIT_OF_MEASUREMENT, "").endswith(
|
||||||
self._adapter.source_type == "grid"
|
f"/{ENERGY_WATT_HOUR}"
|
||||||
and energy_price_state.attributes.get(
|
|
||||||
ATTR_UNIT_OF_MEASUREMENT, ""
|
|
||||||
).endswith(f"/{ENERGY_WATT_HOUR}")
|
|
||||||
):
|
):
|
||||||
energy_price *= 1000.0
|
energy_price *= 1000.0
|
||||||
|
|
||||||
|
if energy_price_state.attributes.get(ATTR_UNIT_OF_MEASUREMENT, "").endswith(
|
||||||
|
f"/{ENERGY_MEGA_WATT_HOUR}"
|
||||||
|
):
|
||||||
|
energy_price /= 1000.0
|
||||||
|
|
||||||
else:
|
else:
|
||||||
energy_price_state = None
|
energy_price_state = None
|
||||||
energy_price = cast(float, self._config["number_energy_price"])
|
energy_price = cast(float, self._config["number_energy_price"])
|
||||||
@ -309,15 +314,18 @@ class EnergyCostSensor(SensorEntity):
|
|||||||
energy_unit = energy_state.attributes.get(ATTR_UNIT_OF_MEASUREMENT)
|
energy_unit = energy_state.attributes.get(ATTR_UNIT_OF_MEASUREMENT)
|
||||||
|
|
||||||
if self._adapter.source_type == "grid":
|
if self._adapter.source_type == "grid":
|
||||||
if energy_unit == ENERGY_WATT_HOUR:
|
if energy_unit not in VALID_ENERGY_UNITS:
|
||||||
energy_price /= 1000
|
|
||||||
elif energy_unit != ENERGY_KILO_WATT_HOUR:
|
|
||||||
energy_unit = None
|
energy_unit = None
|
||||||
|
|
||||||
elif self._adapter.source_type == "gas":
|
elif self._adapter.source_type == "gas":
|
||||||
if energy_unit != VOLUME_CUBIC_METERS:
|
if energy_unit not in VALID_ENERGY_UNITS_GAS:
|
||||||
energy_unit = None
|
energy_unit = None
|
||||||
|
|
||||||
|
if energy_unit == ENERGY_WATT_HOUR:
|
||||||
|
energy_price /= 1000
|
||||||
|
elif energy_unit == ENERGY_MEGA_WATT_HOUR:
|
||||||
|
energy_unit *= 1000
|
||||||
|
|
||||||
if energy_unit is None:
|
if energy_unit is None:
|
||||||
if not self._wrong_unit_reported:
|
if not self._wrong_unit_reported:
|
||||||
self._wrong_unit_reported = True
|
self._wrong_unit_reported = True
|
||||||
|
@ -19,6 +19,7 @@ from homeassistant.const import (
|
|||||||
ATTR_UNIT_OF_MEASUREMENT,
|
ATTR_UNIT_OF_MEASUREMENT,
|
||||||
DEVICE_CLASS_MONETARY,
|
DEVICE_CLASS_MONETARY,
|
||||||
ENERGY_KILO_WATT_HOUR,
|
ENERGY_KILO_WATT_HOUR,
|
||||||
|
ENERGY_MEGA_WATT_HOUR,
|
||||||
ENERGY_WATT_HOUR,
|
ENERGY_WATT_HOUR,
|
||||||
STATE_UNKNOWN,
|
STATE_UNKNOWN,
|
||||||
VOLUME_CUBIC_METERS,
|
VOLUME_CUBIC_METERS,
|
||||||
@ -718,6 +719,62 @@ async def test_cost_sensor_handle_wh(hass, hass_storage) -> None:
|
|||||||
assert state.state == "5.0"
|
assert state.state == "5.0"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_cost_sensor_handle_mwh(hass, hass_storage) -> None:
|
||||||
|
"""Test energy cost price from sensor entity."""
|
||||||
|
energy_attributes = {
|
||||||
|
ATTR_UNIT_OF_MEASUREMENT: ENERGY_MEGA_WATT_HOUR,
|
||||||
|
ATTR_STATE_CLASS: STATE_CLASS_TOTAL_INCREASING,
|
||||||
|
}
|
||||||
|
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": 2.0,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"flow_to": [],
|
||||||
|
"cost_adjustment_day": 0,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
hass_storage[data.STORAGE_KEY] = {
|
||||||
|
"version": 1,
|
||||||
|
"data": energy_data,
|
||||||
|
}
|
||||||
|
|
||||||
|
now = dt_util.utcnow()
|
||||||
|
|
||||||
|
# Initial state: 0.5MWh
|
||||||
|
hass.states.async_set(
|
||||||
|
"sensor.energy_consumption",
|
||||||
|
0.5,
|
||||||
|
energy_attributes,
|
||||||
|
)
|
||||||
|
|
||||||
|
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 by 1 MWh
|
||||||
|
hass.states.async_set(
|
||||||
|
"sensor.energy_consumption",
|
||||||
|
1.5,
|
||||||
|
energy_attributes,
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.energy_consumption_cost")
|
||||||
|
assert state.state == "2.0"
|
||||||
|
|
||||||
|
|
||||||
async def test_cost_sensor_handle_gas(hass, hass_storage) -> None:
|
async def test_cost_sensor_handle_gas(hass, hass_storage) -> None:
|
||||||
"""Test gas cost price from sensor entity."""
|
"""Test gas cost price from sensor entity."""
|
||||||
energy_attributes = {
|
energy_attributes = {
|
||||||
@ -767,6 +824,55 @@ async def test_cost_sensor_handle_gas(hass, hass_storage) -> None:
|
|||||||
assert state.state == "50.0"
|
assert state.state == "50.0"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_cost_sensor_handle_gas_kwh(hass, hass_storage) -> None:
|
||||||
|
"""Test gas cost price from sensor entity."""
|
||||||
|
energy_attributes = {
|
||||||
|
ATTR_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR,
|
||||||
|
ATTR_STATE_CLASS: STATE_CLASS_TOTAL_INCREASING,
|
||||||
|
}
|
||||||
|
energy_data = data.EnergyManager.default_preferences()
|
||||||
|
energy_data["energy_sources"].append(
|
||||||
|
{
|
||||||
|
"type": "gas",
|
||||||
|
"stat_energy_from": "sensor.gas_consumption",
|
||||||
|
"entity_energy_from": "sensor.gas_consumption",
|
||||||
|
"stat_cost": None,
|
||||||
|
"entity_energy_price": None,
|
||||||
|
"number_energy_price": 0.5,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
hass_storage[data.STORAGE_KEY] = {
|
||||||
|
"version": 1,
|
||||||
|
"data": energy_data,
|
||||||
|
}
|
||||||
|
|
||||||
|
now = dt_util.utcnow()
|
||||||
|
|
||||||
|
hass.states.async_set(
|
||||||
|
"sensor.gas_consumption",
|
||||||
|
100,
|
||||||
|
energy_attributes,
|
||||||
|
)
|
||||||
|
|
||||||
|
with patch("homeassistant.util.dt.utcnow", return_value=now):
|
||||||
|
await setup_integration(hass)
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.gas_consumption_cost")
|
||||||
|
assert state.state == "0.0"
|
||||||
|
|
||||||
|
# gas use bumped to 10 kWh
|
||||||
|
hass.states.async_set(
|
||||||
|
"sensor.gas_consumption",
|
||||||
|
200,
|
||||||
|
energy_attributes,
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.gas_consumption_cost")
|
||||||
|
assert state.state == "50.0"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("state_class", [None])
|
@pytest.mark.parametrize("state_class", [None])
|
||||||
async def test_cost_sensor_wrong_state_class(
|
async def test_cost_sensor_wrong_state_class(
|
||||||
hass, hass_storage, caplog, state_class
|
hass, hass_storage, caplog, state_class
|
||||||
|
Loading…
x
Reference in New Issue
Block a user