Add demand window sensor for amberelectric (#121356)
This commit is contained in:
parent
be0cf545b2
commit
2bc7904b51
5 changed files with 123 additions and 15 deletions
|
@ -71,6 +71,18 @@ class AmberPriceSpikeBinarySensor(AmberPriceGridSensor):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class AmberDemandWindowBinarySensor(AmberPriceGridSensor):
|
||||||
|
"""Sensor to show whether demand window is active."""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_on(self) -> bool | None:
|
||||||
|
"""Return true if the binary sensor is on."""
|
||||||
|
grid = self.coordinator.data["grid"]
|
||||||
|
if "demand_window" in grid:
|
||||||
|
return grid["demand_window"] # type: ignore[no-any-return]
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
entry: ConfigEntry,
|
entry: ConfigEntry,
|
||||||
|
@ -83,6 +95,14 @@ async def async_setup_entry(
|
||||||
key="price_spike",
|
key="price_spike",
|
||||||
name=f"{entry.title} - Price Spike",
|
name=f"{entry.title} - Price Spike",
|
||||||
)
|
)
|
||||||
async_add_entities(
|
demand_window_description = BinarySensorEntityDescription(
|
||||||
[AmberPriceSpikeBinarySensor(coordinator, price_spike_description)]
|
key="demand_window",
|
||||||
|
name=f"{entry.title} - Demand Window",
|
||||||
|
translation_key="demand_window",
|
||||||
|
)
|
||||||
|
async_add_entities(
|
||||||
|
[
|
||||||
|
AmberPriceSpikeBinarySensor(coordinator, price_spike_description),
|
||||||
|
AmberDemandWindowBinarySensor(coordinator, demand_window_description),
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
|
@ -111,6 +111,9 @@ class AmberUpdateCoordinator(DataUpdateCoordinator):
|
||||||
]
|
]
|
||||||
result["grid"]["renewables"] = round(general[0].renewables)
|
result["grid"]["renewables"] = round(general[0].renewables)
|
||||||
result["grid"]["price_spike"] = general[0].spike_status.value
|
result["grid"]["price_spike"] = general[0].spike_status.value
|
||||||
|
tariff_information = general[0].tariff_information
|
||||||
|
if tariff_information:
|
||||||
|
result["grid"]["demand_window"] = tariff_information.demand_window
|
||||||
|
|
||||||
controlled_load = [
|
controlled_load = [
|
||||||
interval for interval in current if is_controlled_load(interval)
|
interval for interval in current if is_controlled_load(interval)
|
||||||
|
|
|
@ -13,6 +13,14 @@
|
||||||
"renewables": {
|
"renewables": {
|
||||||
"default": "mdi:solar-power"
|
"default": "mdi:solar-power"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"binary_sensor": {
|
||||||
|
"demand_window": {
|
||||||
|
"default": "mdi:meter-electric",
|
||||||
|
"state": {
|
||||||
|
"off": "mdi:meter-electric-outline"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ from unittest.mock import Mock, patch
|
||||||
from amberelectric.model.channel import ChannelType
|
from amberelectric.model.channel import ChannelType
|
||||||
from amberelectric.model.current_interval import CurrentInterval
|
from amberelectric.model.current_interval import CurrentInterval
|
||||||
from amberelectric.model.interval import SpikeStatus
|
from amberelectric.model.interval import SpikeStatus
|
||||||
|
from amberelectric.model.tariff_information import TariffInformation
|
||||||
from dateutil import parser
|
from dateutil import parser
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
@ -111,7 +112,7 @@ async def setup_spike(hass: HomeAssistant) -> AsyncGenerator[Mock]:
|
||||||
@pytest.mark.usefixtures("setup_no_spike")
|
@pytest.mark.usefixtures("setup_no_spike")
|
||||||
def test_no_spike_sensor(hass: HomeAssistant) -> None:
|
def test_no_spike_sensor(hass: HomeAssistant) -> None:
|
||||||
"""Testing the creation of the Amber renewables sensor."""
|
"""Testing the creation of the Amber renewables sensor."""
|
||||||
assert len(hass.states.async_all()) == 5
|
assert len(hass.states.async_all()) == 6
|
||||||
sensor = hass.states.get("binary_sensor.mock_title_price_spike")
|
sensor = hass.states.get("binary_sensor.mock_title_price_spike")
|
||||||
assert sensor
|
assert sensor
|
||||||
assert sensor.state == "off"
|
assert sensor.state == "off"
|
||||||
|
@ -122,7 +123,7 @@ def test_no_spike_sensor(hass: HomeAssistant) -> None:
|
||||||
@pytest.mark.usefixtures("setup_potential_spike")
|
@pytest.mark.usefixtures("setup_potential_spike")
|
||||||
def test_potential_spike_sensor(hass: HomeAssistant) -> None:
|
def test_potential_spike_sensor(hass: HomeAssistant) -> None:
|
||||||
"""Testing the creation of the Amber renewables sensor."""
|
"""Testing the creation of the Amber renewables sensor."""
|
||||||
assert len(hass.states.async_all()) == 5
|
assert len(hass.states.async_all()) == 6
|
||||||
sensor = hass.states.get("binary_sensor.mock_title_price_spike")
|
sensor = hass.states.get("binary_sensor.mock_title_price_spike")
|
||||||
assert sensor
|
assert sensor
|
||||||
assert sensor.state == "off"
|
assert sensor.state == "off"
|
||||||
|
@ -133,9 +134,85 @@ def test_potential_spike_sensor(hass: HomeAssistant) -> None:
|
||||||
@pytest.mark.usefixtures("setup_spike")
|
@pytest.mark.usefixtures("setup_spike")
|
||||||
def test_spike_sensor(hass: HomeAssistant) -> None:
|
def test_spike_sensor(hass: HomeAssistant) -> None:
|
||||||
"""Testing the creation of the Amber renewables sensor."""
|
"""Testing the creation of the Amber renewables sensor."""
|
||||||
assert len(hass.states.async_all()) == 5
|
assert len(hass.states.async_all()) == 6
|
||||||
sensor = hass.states.get("binary_sensor.mock_title_price_spike")
|
sensor = hass.states.get("binary_sensor.mock_title_price_spike")
|
||||||
assert sensor
|
assert sensor
|
||||||
assert sensor.state == "on"
|
assert sensor.state == "on"
|
||||||
assert sensor.attributes["icon"] == "mdi:power-plug-off"
|
assert sensor.attributes["icon"] == "mdi:power-plug-off"
|
||||||
assert sensor.attributes["spike_status"] == "spike"
|
assert sensor.attributes["spike_status"] == "spike"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
async def setup_inactive_demand_window(hass: HomeAssistant) -> AsyncGenerator[Mock]:
|
||||||
|
"""Set up general channel."""
|
||||||
|
MockConfigEntry(
|
||||||
|
domain="amberelectric",
|
||||||
|
data={
|
||||||
|
CONF_SITE_NAME: "mock_title",
|
||||||
|
CONF_API_TOKEN: MOCK_API_TOKEN,
|
||||||
|
CONF_SITE_ID: GENERAL_ONLY_SITE_ID,
|
||||||
|
},
|
||||||
|
).add_to_hass(hass)
|
||||||
|
|
||||||
|
instance = Mock()
|
||||||
|
with patch(
|
||||||
|
"amberelectric.api.AmberApi.create",
|
||||||
|
return_value=instance,
|
||||||
|
) as mock_update:
|
||||||
|
general_channel: list[CurrentInterval] = [
|
||||||
|
generate_current_interval(
|
||||||
|
ChannelType.GENERAL, parser.parse("2021-09-21T08:30:00+10:00")
|
||||||
|
),
|
||||||
|
]
|
||||||
|
general_channel[0].tariff_information = TariffInformation(demandWindow=False)
|
||||||
|
instance.get_current_price = Mock(return_value=general_channel)
|
||||||
|
assert await async_setup_component(hass, DOMAIN, {})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
yield mock_update.return_value
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
async def setup_active_demand_window(hass: HomeAssistant) -> AsyncGenerator[Mock]:
|
||||||
|
"""Set up general channel."""
|
||||||
|
MockConfigEntry(
|
||||||
|
domain="amberelectric",
|
||||||
|
data={
|
||||||
|
CONF_SITE_NAME: "mock_title",
|
||||||
|
CONF_API_TOKEN: MOCK_API_TOKEN,
|
||||||
|
CONF_SITE_ID: GENERAL_ONLY_SITE_ID,
|
||||||
|
},
|
||||||
|
).add_to_hass(hass)
|
||||||
|
|
||||||
|
instance = Mock()
|
||||||
|
with patch(
|
||||||
|
"amberelectric.api.AmberApi.create",
|
||||||
|
return_value=instance,
|
||||||
|
) as mock_update:
|
||||||
|
general_channel: list[CurrentInterval] = [
|
||||||
|
generate_current_interval(
|
||||||
|
ChannelType.GENERAL, parser.parse("2021-09-21T08:30:00+10:00")
|
||||||
|
),
|
||||||
|
]
|
||||||
|
general_channel[0].tariff_information = TariffInformation(demandWindow=True)
|
||||||
|
instance.get_current_price = Mock(return_value=general_channel)
|
||||||
|
assert await async_setup_component(hass, DOMAIN, {})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
yield mock_update.return_value
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("setup_inactive_demand_window")
|
||||||
|
def test_inactive_demand_window_sensor(hass: HomeAssistant) -> None:
|
||||||
|
"""Testing the creation of the Amber demand_window sensor."""
|
||||||
|
assert len(hass.states.async_all()) == 6
|
||||||
|
sensor = hass.states.get("binary_sensor.mock_title_demand_window")
|
||||||
|
assert sensor
|
||||||
|
assert sensor.state == "off"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("setup_active_demand_window")
|
||||||
|
def test_active_demand_window_sensor(hass: HomeAssistant) -> None:
|
||||||
|
"""Testing the creation of the Amber demand_window sensor."""
|
||||||
|
assert len(hass.states.async_all()) == 6
|
||||||
|
sensor = hass.states.get("binary_sensor.mock_title_demand_window")
|
||||||
|
assert sensor
|
||||||
|
assert sensor.state == "on"
|
||||||
|
|
|
@ -105,7 +105,7 @@ async def setup_general_and_feed_in(hass: HomeAssistant) -> AsyncGenerator[Mock]
|
||||||
|
|
||||||
async def test_general_price_sensor(hass: HomeAssistant, setup_general: Mock) -> None:
|
async def test_general_price_sensor(hass: HomeAssistant, setup_general: Mock) -> None:
|
||||||
"""Test the General Price sensor."""
|
"""Test the General Price sensor."""
|
||||||
assert len(hass.states.async_all()) == 5
|
assert len(hass.states.async_all()) == 6
|
||||||
price = hass.states.get("sensor.mock_title_general_price")
|
price = hass.states.get("sensor.mock_title_general_price")
|
||||||
assert price
|
assert price
|
||||||
assert price.state == "0.08"
|
assert price.state == "0.08"
|
||||||
|
@ -143,7 +143,7 @@ async def test_general_price_sensor(hass: HomeAssistant, setup_general: Mock) ->
|
||||||
@pytest.mark.usefixtures("setup_general_and_controlled_load")
|
@pytest.mark.usefixtures("setup_general_and_controlled_load")
|
||||||
async def test_general_and_controlled_load_price_sensor(hass: HomeAssistant) -> None:
|
async def test_general_and_controlled_load_price_sensor(hass: HomeAssistant) -> None:
|
||||||
"""Test the Controlled Price sensor."""
|
"""Test the Controlled Price sensor."""
|
||||||
assert len(hass.states.async_all()) == 8
|
assert len(hass.states.async_all()) == 9
|
||||||
price = hass.states.get("sensor.mock_title_controlled_load_price")
|
price = hass.states.get("sensor.mock_title_controlled_load_price")
|
||||||
assert price
|
assert price
|
||||||
assert price.state == "0.08"
|
assert price.state == "0.08"
|
||||||
|
@ -165,7 +165,7 @@ async def test_general_and_controlled_load_price_sensor(hass: HomeAssistant) ->
|
||||||
@pytest.mark.usefixtures("setup_general_and_feed_in")
|
@pytest.mark.usefixtures("setup_general_and_feed_in")
|
||||||
async def test_general_and_feed_in_price_sensor(hass: HomeAssistant) -> None:
|
async def test_general_and_feed_in_price_sensor(hass: HomeAssistant) -> None:
|
||||||
"""Test the Feed In sensor."""
|
"""Test the Feed In sensor."""
|
||||||
assert len(hass.states.async_all()) == 8
|
assert len(hass.states.async_all()) == 9
|
||||||
price = hass.states.get("sensor.mock_title_feed_in_price")
|
price = hass.states.get("sensor.mock_title_feed_in_price")
|
||||||
assert price
|
assert price
|
||||||
assert price.state == "-0.08"
|
assert price.state == "-0.08"
|
||||||
|
@ -188,7 +188,7 @@ async def test_general_forecast_sensor(
|
||||||
hass: HomeAssistant, setup_general: Mock
|
hass: HomeAssistant, setup_general: Mock
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the General Forecast sensor."""
|
"""Test the General Forecast sensor."""
|
||||||
assert len(hass.states.async_all()) == 5
|
assert len(hass.states.async_all()) == 6
|
||||||
price = hass.states.get("sensor.mock_title_general_forecast")
|
price = hass.states.get("sensor.mock_title_general_forecast")
|
||||||
assert price
|
assert price
|
||||||
assert price.state == "0.09"
|
assert price.state == "0.09"
|
||||||
|
@ -230,7 +230,7 @@ async def test_general_forecast_sensor(
|
||||||
@pytest.mark.usefixtures("setup_general_and_controlled_load")
|
@pytest.mark.usefixtures("setup_general_and_controlled_load")
|
||||||
async def test_controlled_load_forecast_sensor(hass: HomeAssistant) -> None:
|
async def test_controlled_load_forecast_sensor(hass: HomeAssistant) -> None:
|
||||||
"""Test the Controlled Load Forecast sensor."""
|
"""Test the Controlled Load Forecast sensor."""
|
||||||
assert len(hass.states.async_all()) == 8
|
assert len(hass.states.async_all()) == 9
|
||||||
price = hass.states.get("sensor.mock_title_controlled_load_forecast")
|
price = hass.states.get("sensor.mock_title_controlled_load_forecast")
|
||||||
assert price
|
assert price
|
||||||
assert price.state == "0.09"
|
assert price.state == "0.09"
|
||||||
|
@ -254,7 +254,7 @@ async def test_controlled_load_forecast_sensor(hass: HomeAssistant) -> None:
|
||||||
@pytest.mark.usefixtures("setup_general_and_feed_in")
|
@pytest.mark.usefixtures("setup_general_and_feed_in")
|
||||||
async def test_feed_in_forecast_sensor(hass: HomeAssistant) -> None:
|
async def test_feed_in_forecast_sensor(hass: HomeAssistant) -> None:
|
||||||
"""Test the Feed In Forecast sensor."""
|
"""Test the Feed In Forecast sensor."""
|
||||||
assert len(hass.states.async_all()) == 8
|
assert len(hass.states.async_all()) == 9
|
||||||
price = hass.states.get("sensor.mock_title_feed_in_forecast")
|
price = hass.states.get("sensor.mock_title_feed_in_forecast")
|
||||||
assert price
|
assert price
|
||||||
assert price.state == "-0.09"
|
assert price.state == "-0.09"
|
||||||
|
@ -278,7 +278,7 @@ async def test_feed_in_forecast_sensor(hass: HomeAssistant) -> None:
|
||||||
@pytest.mark.usefixtures("setup_general")
|
@pytest.mark.usefixtures("setup_general")
|
||||||
def test_renewable_sensor(hass: HomeAssistant) -> None:
|
def test_renewable_sensor(hass: HomeAssistant) -> None:
|
||||||
"""Testing the creation of the Amber renewables sensor."""
|
"""Testing the creation of the Amber renewables sensor."""
|
||||||
assert len(hass.states.async_all()) == 5
|
assert len(hass.states.async_all()) == 6
|
||||||
sensor = hass.states.get("sensor.mock_title_renewables")
|
sensor = hass.states.get("sensor.mock_title_renewables")
|
||||||
assert sensor
|
assert sensor
|
||||||
assert sensor.state == "51"
|
assert sensor.state == "51"
|
||||||
|
@ -287,7 +287,7 @@ def test_renewable_sensor(hass: HomeAssistant) -> None:
|
||||||
@pytest.mark.usefixtures("setup_general")
|
@pytest.mark.usefixtures("setup_general")
|
||||||
def test_general_price_descriptor_descriptor_sensor(hass: HomeAssistant) -> None:
|
def test_general_price_descriptor_descriptor_sensor(hass: HomeAssistant) -> None:
|
||||||
"""Test the General Price Descriptor sensor."""
|
"""Test the General Price Descriptor sensor."""
|
||||||
assert len(hass.states.async_all()) == 5
|
assert len(hass.states.async_all()) == 6
|
||||||
price = hass.states.get("sensor.mock_title_general_price_descriptor")
|
price = hass.states.get("sensor.mock_title_general_price_descriptor")
|
||||||
assert price
|
assert price
|
||||||
assert price.state == "extremely_low"
|
assert price.state == "extremely_low"
|
||||||
|
@ -298,7 +298,7 @@ def test_general_and_controlled_load_price_descriptor_sensor(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the Controlled Price Descriptor sensor."""
|
"""Test the Controlled Price Descriptor sensor."""
|
||||||
assert len(hass.states.async_all()) == 8
|
assert len(hass.states.async_all()) == 9
|
||||||
price = hass.states.get("sensor.mock_title_controlled_load_price_descriptor")
|
price = hass.states.get("sensor.mock_title_controlled_load_price_descriptor")
|
||||||
assert price
|
assert price
|
||||||
assert price.state == "extremely_low"
|
assert price.state == "extremely_low"
|
||||||
|
@ -307,7 +307,7 @@ def test_general_and_controlled_load_price_descriptor_sensor(
|
||||||
@pytest.mark.usefixtures("setup_general_and_feed_in")
|
@pytest.mark.usefixtures("setup_general_and_feed_in")
|
||||||
def test_general_and_feed_in_price_descriptor_sensor(hass: HomeAssistant) -> None:
|
def test_general_and_feed_in_price_descriptor_sensor(hass: HomeAssistant) -> None:
|
||||||
"""Test the Feed In Price Descriptor sensor."""
|
"""Test the Feed In Price Descriptor sensor."""
|
||||||
assert len(hass.states.async_all()) == 8
|
assert len(hass.states.async_all()) == 9
|
||||||
price = hass.states.get("sensor.mock_title_feed_in_price_descriptor")
|
price = hass.states.get("sensor.mock_title_feed_in_price_descriptor")
|
||||||
assert price
|
assert price
|
||||||
assert price.state == "extremely_low"
|
assert price.state == "extremely_low"
|
||||||
|
|
Loading…
Add table
Reference in a new issue