Skip to content

Commit 7c01073

Browse files
Merge pull request #28 from BottlecapDave/develop
Next release
2 parents 555f123 + 54f68ca commit 7c01073

File tree

6 files changed

+43
-21
lines changed

6 files changed

+43
-21
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Target timeframes was a feature that has been extracted out of the [Octopus Energy integration](https://github.com/BottlecapDave/HomeAssistant-OctopusEnergy). The idea is you can configure binary sensors that will find and turn on during the most optimal time periods based on external data sources, targeting either the lowest or highest values. What these values represent can be anything. In the original integration, the values represented cost of energy, and so the cheapest periods were discovered. But it could represent other things like
44

5-
* Temperature to turn on sprinklers during the hottest times of the day
5+
* Energy prices to turn on devices when cost is the cheapest
66
* Carbon emissions to turn on devices when renewables on the grid are at their highest
77
* Solar generation to turn on devices when the most energy is being generated.
88

_docs/blueprints/target_timeframes_octopus_energy_carbon_intensity.yaml

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,6 @@ blueprint:
1414
- sensor
1515
integration: target_timeframes
1616
multiple: false
17-
octopus_energy_previous_day_rates:
18-
name: Previous day rates
19-
description: The previous day rates event sensor supplied by Octopus Energy. More information can be found at https://bottlecapdave.github.io/HomeAssistant-OctopusEnergy/entities/electricity/#previous-day-rates.
20-
selector:
21-
entity:
22-
filter:
23-
- domain:
24-
- event
25-
integration: octopus_energy
26-
multiple: false
2717
octopus_energy_current_day_rates:
2818
name: Current day rates
2919
description: The current day rates event sensor supplied by Octopus Energy. More information can be found at https://bottlecapdave.github.io/HomeAssistant-OctopusEnergy/entities/electricity/#current-day-rates.
@@ -61,6 +51,13 @@ blueprint:
6151
selector:
6252
number:
6353
mode: box
54+
octopus_energy_weighting:
55+
name: Octopus Energy rate weighting
56+
description: The weighting to apply to the Octopus Energy rates when calculating the final value for the period.
57+
default: 0.7
58+
selector:
59+
number:
60+
mode: box
6461
carbon_intensity_current_day_rates:
6562
name: Current day rates
6663
description: The current day rates event sensor supplied by Carbon Intensity. More information can be found at https://bottlecapdave.github.io/HomeAssistant-CarbonIntensity/entities/#current-day-rates.
@@ -81,20 +78,26 @@ blueprint:
8178
- event
8279
integration: carbon_intensity
8380
multiple: false
81+
carbon_intensity_weighting:
82+
name: Carbon Intensity forecast weighting
83+
description: The weighting to apply to the Carbon Intensity forecast when calculating the final value for the period.
84+
default: 0.3
85+
selector:
86+
number:
87+
mode: box
8488
variables:
8589
target_timeframe_data_source_sensor: !input target_timeframe_data_source_sensor
86-
octopus_energy_previous_day_rates: !input octopus_energy_previous_day_rates
8790
octopus_energy_current_day_rates: !input octopus_energy_current_day_rates
8891
octopus_energy_next_day_rates: !input octopus_energy_next_day_rates
8992
octopus_energy_free_electricity: !input octopus_energy_free_electricity
9093
octopus_energy_free_electricity_weighting: !input octopus_energy_free_electricity_weighting
9194
carbon_intensity_current_day_rates: !input carbon_intensity_current_day_rates
9295
carbon_intensity_next_day_rates: !input carbon_intensity_next_day_rates
96+
octopus_energy_weighting: !input octopus_energy_weighting
97+
carbon_intensity_weighting: !input carbon_intensity_weighting
9398
mode: queued
9499
max: 4
95100
triggers:
96-
- platform: state
97-
entity_id: !input octopus_energy_previous_day_rates
98101
- platform: state
99102
entity_id: !input octopus_energy_current_day_rates
100103
- platform: state
@@ -110,9 +113,6 @@ action:
110113
- action: target_timeframes.update_target_timeframe_data_source
111114
data: >
112115
{%- set all_oe_rates = [] -%}
113-
{%- if state_attr(octopus_energy_previous_day_rates, 'rates') != None -%}
114-
{%- set all_oe_rates = all_oe_rates + state_attr(octopus_energy_previous_day_rates, 'rates') -%}
115-
{%- endif -%}
116116
{%- if state_attr(octopus_energy_current_day_rates, 'rates') != None -%}
117117
{%- set all_oe_rates = all_oe_rates + state_attr(octopus_energy_current_day_rates, 'rates') -%}
118118
{%- endif -%}
@@ -132,12 +132,19 @@ action:
132132
{%- set all_ci_rates = all_ci_rates + state_attr(carbon_intensity_next_day_rates, 'rates') -%}
133133
{%- endif -%}
134134
135+
{%- set min_rate = all_oe_rates | map(attribute='value_inc_vat') | min -%}
136+
{%- set max_rate = all_oe_rates | map(attribute='value_inc_vat') | max -%}
137+
{%- set min_carbon = all_ci_rates | map(attribute='intensity_forecast') | min -%}
138+
{%- set max_carbon = all_ci_rates | map(attribute='intensity_forecast') | max -%}
139+
{%- set rate_diff = max_rate - min_rate if max_rate - min_rate != 0 else 1 %}
140+
{%- set carbon_diff = max_carbon - min_carbon if max_carbon - min_carbon != 0 else 1 %}
141+
135142
{%- set data = namespace(new_rates=[]) -%}
136143
{%- for rate in all_oe_rates -%}
137144
{%- set start = rate["start"] | as_timestamp | timestamp_utc -%}
138145
{%- set end = rate["end"] | as_timestamp | timestamp_utc -%}
139-
{%- set value = rate["value_inc_vat"] | float -%}
140-
146+
{%- set value = (((rate["value_inc_vat"] | float - min_rate) / rate_diff) * octopus_energy_weighting) -%}
147+
141148
{%- set free_namespace = namespace(is_free=False) -%}
142149
{%- for free_session in free_electricity_rates -%}
143150
{%- set free_start = free_session["start"] | as_timestamp | timestamp_utc -%}
@@ -158,7 +165,7 @@ action:
158165
159166
{%- set metadata = { "rate": rate["value_inc_vat"], "is_capped": rate["is_capped"] } -%}
160167
{%- if carbon_intensity_namespace.rate -%}
161-
{%- set value = value * (carbon_intensity_namespace.rate["intensity_forecast"] | float) -%}
168+
{%- set value = value + (((carbon_intensity_namespace.rate["intensity_forecast"] | float - min_carbon) / carbon_diff) * carbon_intensity_weighting) -%}
162169
{%- set metadata = dict(metadata.items(), carbon_intensity=carbon_intensity_namespace.rate["intensity_forecast"] | float) -%}
163170
{%- endif -%}
164171

_docs/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Target timeframes was a feature that has been extracted out of the [Octopus Energy integration](https://github.com/BottlecapDave/HomeAssistant-OctopusEnergy). The idea is you can configure binary sensors that will find and turn on during the most optimal time periods based on external data sources, targeting either the lowest or highest values. What these values represent can be anything. In the original integration, the values represented cost of energy, and so the cheapest periods were discovered. But it could represent other things like
44

5-
* Temperature to turn on sprinklers during the hottest times of the day
5+
* Energy prices to turn on devices when cost is the cheapest
66
* Carbon emissions to turn on devices when renewables on the grid are at their highest
77
* Solar generation to turn on devices when the most energy is being generated.
88

_docs/services.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ The following services are available if you have set up at least one [target tim
5454

5555
For updating a given [target timeframe's](./setup/target_timeframe.md) config. This allows you to change target timeframes sensors dynamically based on other outside criteria (e.g. you need to adjust the target hours to top up home batteries).
5656

57+
!!! warning
58+
59+
This will cause the sensor to re-evaluate the target times, which may result in different times being picked.
60+
5761
| Attribute | Optional | Description |
5862
| ------------------------ | -------- | --------------------------------------------------------------------------------------------------------------------- |
5963
| `target.entity_id` | `no` | The name of the target sensor whose configuration is to be updated. |
@@ -126,6 +130,10 @@ The following services are available if you have set up at least one [rolling ta
126130
127131
For updating a given [rolling target timeframe's](./setup/rolling_target_timeframe.md) config. This allows you to change rolling target timeframes sensors dynamically based on other outside criteria (e.g. you need to adjust the target hours to top up home batteries).
128132
133+
!!! warning
134+
135+
This will cause the sensor to re-evaluate the target times, which may result in different times being picked.
136+
129137
| Attribute | Optional | Description |
130138
| ------------------------ | -------- | --------------------------------------------------------------------------------------------------------------------- |
131139
| `target.entity_id` | `no` | The name of the target sensor whose configuration is to be updated. |

custom_components/target_timeframes/entities/rolling_target_timeframe.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ def __init__(self, hass: HomeAssistant, data_source_id: str, config_entry, confi
6868
self._attributes = self._config.copy()
6969
self._last_evaluated = None
7070
self._data_source_id = data_source_id
71+
self._attributes["data_source_id"] = self._data_source_id
7172

7273
is_rolling_target = True
7374
if CONFIG_TARGET_ROLLING_TARGET in self._config:
@@ -205,6 +206,7 @@ async def async_update(self):
205206
self._attributes["next_average_value"] = active_result["next_average_value"]
206207
self._attributes["next_min_value"] = active_result["next_min_value"]
207208
self._attributes["next_max_value"] = active_result["next_max_value"]
209+
self._attributes["data_source_id"] = self._data_source_id
208210

209211
self._state = active_result["is_active"]
210212

@@ -295,6 +297,7 @@ async def async_update_rolling_target_timeframe_config(self, target_hours=None,
295297
self._config = config
296298
self._attributes = self._config.copy()
297299
self._target_timeframes = []
300+
await self.async_update()
298301
self.async_write_ha_state()
299302

300303
if persist_changes:

custom_components/target_timeframes/entities/target_timeframe.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ def __init__(self, hass: HomeAssistant, data_source_id: str, config_entry, confi
7373
self._attributes = self._config.copy()
7474
self._last_evaluated = None
7575
self._data_source_id = data_source_id
76+
self._attributes["data_source_id"] = self._data_source_id
7677

7778
is_rolling_target = True
7879
if CONFIG_TARGET_ROLLING_TARGET in self._config:
@@ -86,6 +87,7 @@ def __init__(self, hass: HomeAssistant, data_source_id: str, config_entry, confi
8687

8788
self._data_source_data = initial_data if initial_data is not None else []
8889
self._target_timeframes = []
90+
8991

9092
self._hass = hass
9193
self.entity_id = generate_entity_id("binary_sensor.{}", self.unique_id, hass=hass)
@@ -230,6 +232,7 @@ async def async_update(self):
230232
self._attributes["next_average_value"] = active_result["next_average_value"]
231233
self._attributes["next_min_value"] = active_result["next_min_value"]
232234
self._attributes["next_max_value"] = active_result["next_max_value"]
235+
self._attributes["data_source_id"] = self._data_source_id
233236

234237
self._state = active_result["is_active"]
235238

@@ -326,6 +329,7 @@ async def async_update_target_timeframe_config(self, target_start_time=None, tar
326329
self._config = config
327330
self._attributes = self._config.copy()
328331
self._target_timeframes = []
332+
await self.async_update()
329333
self.async_write_ha_state()
330334

331335
if persist_changes:

0 commit comments

Comments
 (0)