-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathspot-price.yaml
315 lines (306 loc) · 13.2 KB
/
spot-price.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
# Start pack for Spot Price control.
# Version 0.2.3
#
# This is a copy-paste approach in order to get Finnish Electricity Spot Prices to Home Assistant.
# Initial implementation by Temez but feel free to further develop this.
# Special thanks to Mikki who has created the API where data is fetched. For more information see https://spot-hinta.fi/
# This is just a loader for the data which is stored in sensor attributes. Template sensors present actual data.
sensor:
- platform: rest
resource: https://api.spot-hinta.fi/TodayAndDayForward?HomeAssistant=true
name: SHF Electricity price
unique_id: shf_electricity_price
scan_interval: 604800 # 7 days, update logic is in the automation
value_template: 'OK' # static value as sensor is not updated regularly
json_attributes:
- "data"
- platform: statistics
name: "SHF Average Price 7 Days"
entity_id: sensor.shf_electricity_price_now
state_characteristic: mean
unique_id: shf_average_7days
precision: 4
max_age:
days: 7
template:
- sensor:
- name: SHF data # Helper for other sensors to get correct price/rank from array
unique_id: shf_data
state: 'DATA'
availability: '{{ has_value("sensor.shf_electricity_price") }}'
attributes:
raw: '{{ state_attr("sensor.shf_electricity_price", "data") if state_attr("sensor.shf_electricity_price", "data") else state_attr("sensor.shf_data", "raw") }}'
data: >
{% set output = namespace(value=[]) %}
{% for value in state_attr("sensor.shf_data","raw") | default([], true) %}
{% set t = value.DateTime | as_datetime | as_local %}
{% if t.hour >= state_attr("input_datetime.shf_price2_start", "hour") and t.hour < state_attr("input_datetime.shf_price2_stop", "hour")%}
{% set x = states("input_number.shf_price2_slider") %}
{% else %}
{% set x = states("input_number.shf_price1_slider") %}
{% endif %}
{% set price = value.PriceWithTax + x | float %}
{% set new_data = dict(value, **{"Timestamp": t | as_timestamp, "TotalPrice": price}) %}
{% set output.value = output.value + [new_data] %}
{% endfor %}
{{ output.value }}
- sensor:
- name: SHF Rank now
unique_id: shf_electricity_rank_now
unit_of_measurement: Rank
availability: '{{ state_attr("sensor.shf_data", "data") | selectattr("Timestamp", "lt", now() | as_timestamp) | list | length > 0 }}'
state: >
{% set today = state_attr('sensor.shf_data', 'data') | selectattr("Timestamp", "lt", today_at("23:59") | as_timestamp) | selectattr("Timestamp", "ge", today_at("0:00") | as_timestamp) %}
{% set n = state_attr('sensor.shf_data', 'data') | selectattr("Timestamp", "eq", now().replace(minute=0, second=0, microsecond=0) | as_timestamp) | first %}
{{ (today | sort(attribute="TotalPrice")).index(n) + 1 }}
- sensor:
- name: SHF Electricity price now
unique_id: shf_electricity_price_now
unit_of_measurement: "€/kWh"
device_class: monetary
state: '{{ (state_attr("sensor.shf_data", "data") | selectattr("Timestamp", "lt", now() | as_timestamp) | list)[-1]["TotalPrice"] | round(4) }}'
availability: '{{ state_attr("sensor.shf_data", "data") | selectattr("Timestamp", "ge", now() | as_timestamp ) | list | length > 0 }}'
attributes:
data: '{{ state_attr("sensor.shf_data", "data") }}'
all_prices: '{{ state_attr("sensor.shf_data", "data") | selectattr("Timestamp", "ge", today_at("0:00") | as_timestamp) | map(attribute="TotalPrice") |list }}'
today_prices: '{{ state_attr("sensor.shf_data", "data") | selectattr("Timestamp", "ge", today_at("0:00") | as_timestamp) | selectattr("Timestamp", "lt", today_at("23:59") | as_timestamp) | map(attribute="TotalPrice") |list }}'
tomorrow_prices: '{{ state_attr("sensor.shf_data", "data") | selectattr("Timestamp", "ge", today_at("23:59") | as_timestamp) | map(attribute="TotalPrice") |list }}'
today_min: '{{ this.attributes.today_prices | default([0]) | min }}'
today_avg: '{{ this.attributes.today_prices | default([0]) | average | round(4) }}'
today_max: '{{ this.attributes.today_prices | default([0]) | max }}'
tomorrow_min: '{{ this.attributes.tomorrow_prices | default([0], true) | min }}'
tomorrow_avg: '{{ this.attributes.tomorrow_prices | default([0], true) | average | round(4) }}'
tomorrow_max: '{{ this.attributes.tomorrow_prices | default([0], true) | max }}'
- sensor:
- name: SHF Average price today
unique_id: shf_average_electricity_price
unit_of_measurement: "€/kWh"
device_class: monetary
state: '{{ state_attr("sensor.shf_electricity_price_now", "today_avg") }}'
- sensor:
- name: SHF Average price next hours
unique_id: shf_average_electricity_price_next_hours
unit_of_measurement: "€/kWh"
device_class: monetary
availability: '{{ has_value("sensor.shf_electricity_price_now") }}'
state: >
{% set stop = (now() + timedelta(hours=states("input_number.shf_price_avg_slider")|int)) | as_timestamp %}
{{ state_attr("sensor.shf_data", "data") | selectattr("Timestamp", "ge", now() | as_timestamp) | selectattr("Timestamp", "lt", stop) | map(attribute="TotalPrice") | average | round(3) }}
- sensor:
- name: SHF Control Factor 0-1
unique_id: shf_control_factor_0-1
unit_of_measurement: factor
icon: mdi:gauge
state: '{{ (states("sensor.shf_control_factor_1") | float(1) /2 + 0.5) }}'
availability: '{{ state_attr("sensor.shf_control_factor_1", "today_values") is iterable }}'
attributes:
today_values: >
{% set output = namespace(value=[]) %}
{% for value in state_attr("sensor.shf_control_factor_1", "today_values") %}
{% set output.value = output.value + [ value | float /2 + 0.5 ] %}
{% endfor %}
{{ output.value }}
- sensor:
- name: SHF Control Factor +-1
unique_id: shf_control_factor_+-1
unit_of_measurement: factor
icon: mdi:gauge
state: '{{ state_attr("sensor.shf_control_factor_1", "today_values")[now().hour] | default(1) }}'
availability: '{{ state_attr("sensor.shf_electricity_price_now", "today_prices") is iterable and state_attr("sensor.shf_electricity_price_now", "today_min") | is_number and state_attr("sensor.shf_electricity_price_now", "today_max") | is_number }}'
attributes:
today_values: >
{% set output = namespace(value=[]) %}
{% for pnow in state_attr("sensor.shf_electricity_price_now", "today_prices") %}
{% set pmin = state_attr("sensor.shf_electricity_price_now", "today_min") | float %}
{% set pmax = state_attr("sensor.shf_electricity_price_now", "today_max") | float %}
{% set value = max(min((2*(pmax - pnow) / (pmax - pmin)-1) * states('input_number.shf_control_function_factor') | float,1),-1) %}
{% if states("input_select.shf_control_function" ) == "Linear" %}
{% set output.value = output.value + [value | round(2)] %}
{% else %}
{% set output.value = output.value + [sin(value*pi/2) | round(2)] %}
{% endif %}
{% endfor %}
{{ output.value }}
- binary_sensor:
- name: "SHF Rank acceptable"
unique_id: shf_rank_acceptable
device_class: power
availability: '{{ has_value("sensor.shf_rank_now") }}'
state: '{{ states("sensor.shf_rank_now")| int <= states("input_number.shf_rank_slider") | int }}'
- binary_sensor:
- name: "SHF Price acceptable"
unique_id: shf_price_acceptable
device_class: power
availability: '{{ has_value("sensor.shf_electricity_price_now") }}'
state: '{{ states("sensor.shf_electricity_price_now") | float <= states("input_number.shf_price_slider") | float }}'
- binary_sensor:
- name: "SHF Price or Rank acceptable"
unique_id: shf_price_or_rank_acceptable
device_class: power
state: '{{ is_state("binary_sensor.shf_rank_acceptable", "on") or is_state("binary_sensor.shf_price_acceptable", "on") }}'
input_select:
shf_control_function:
name: SHF Control Function
options:
- Linear
- Sinusoidal
icon: mdi:gauge
input_number:
shf_control_function_factor:
name: SHF Control Function Factor
min: 1
max: 3
step: 0.01
icon: mdi:gauge
mode: box
shf_rank_slider:
name: SHF Max Rank allowed
min: 1
max: 24
step: 1
shf_price_slider:
name: SHF Max Price allowed
min: 0
max: 4
step: 0.01
unit_of_measurement: €/kWh
icon: mdi:cash-lock
mode: box
shf_price_avg_slider:
name: SHF Average price hours
min: 1
max: 24
step: 1
unit_of_measurement: h
icon: mdi:cash-clock
shf_control_factor:
name: SHF Control Factor
min: 0
max: 1000
mode: box
shf_price1_slider:
name: SHF Price1
min: 0
max: 1000
step: 0.0001
unit_of_measurement: €
icon: mdi:cash-lock
mode: box
shf_price2_slider:
name: SHF Price2
min: 0
max: 1000
step: 0.0001
unit_of_measurement: €
icon: mdi:cash-lock
mode: box
input_datetime:
shf_price2_start:
name: SHF Price2 start
has_date: false
has_time: true
shf_price2_stop:
name: SHF Price2 stop
has_date: false
has_time: true
# Automation for automatic updating of the sensor. Tries to reduce API load.
automation:
- id: '1669453089221'
alias: Intelligent update of electricity price sensor
description: 'Tries to fetch new data every 15mins after 14 oclock local time. Condition stops unnecessary requests. Random delay disperses API calls.'
trigger:
- platform: time_pattern
minutes: /15
alias: Trigger every 15mins
condition:
- condition: template
value_template: '{{ state_attr("sensor.shf_data", "data") | selectattr("Timestamp", "ge", (now() + timedelta(hours=9) )| as_timestamp ) | list | length <= 0 }}'
alias: Check if there isn't data for tomorrow and time is after 14 o'clock
action:
- delay: '{{ range(60, 600)|random }}'
alias: Random delay in order to reduce API congestion
- service: homeassistant.update_entity
alias: Trigger the update of the sensor
target:
entity_id: sensor.shf_electricity_price
mode: single
- id: '1671178061951'
alias: 'SHF: Validate Price modifiers'
description: ''
trigger:
- platform: state
entity_id:
- input_datetime.shf_price2_start
- input_datetime.shf_price2_stop
condition: []
action:
- service: input_datetime.set_datetime
data:
time: '{{ state_attr(''input_datetime.shf_price2_stop'', ''hour'') }}:00'
target:
entity_id: input_datetime.shf_price2_stop
- service: input_datetime.set_datetime
data:
time: '{{ state_attr(''input_datetime.shf_price2_start'', ''hour'') }}:00'
target:
entity_id: input_datetime.shf_price2_start
- if:
- condition: template
value_template: '{{states(''input_datetime.shf_price2_start'') > states(''input_datetime.shf_price2_stop'')}}'
then:
- service: input_datetime.set_datetime
data:
time: '{{ states(''input_datetime.shf_price2_stop'') }}'
target:
entity_id: input_datetime.shf_price2_start
mode: single
# Scripts
script:
cheapest_hours:
alias: Cheapest hours
description: "Returns starting time of cheapest period."
fields:
start:
name: "Start time"
description: "Defines the start time for search. Use template."
required: true
example: "{{ now() }}"
selector:
datetime:
stop:
name: "Stop time"
description: "Defines the stop time for search. Use template."
required: true
example: '{{ now() + timedelta(hours=12) }} or {{ today_at("23:00") }}'
selector:
datetime:
hours:
name: "Hours"
description: "Defines the duration of the desired period."
example: "5"
required: true
selector:
number:
min: 1
max: 48
sequence:
- variables:
start_time: >
{% set output = namespace(value=[], tmp = []) %}
{% set data = state_attr("sensor.shf_data", "data") | selectattr("Timestamp", "ge", start | as_timestamp) | selectattr("Timestamp", "lt", stop | as_timestamp) | list %}
{% set hours = hours if hours is number else hours["hours"] %}
{% set hours = min(hours | int, data | length) %}
{% for inval in data %}
{% set output.tmp = data | selectattr("Timestamp", "ge", inval["Timestamp"]) | selectattr("Timestamp", "lt", inval["Timestamp"] + hours*3600) | list%}
{% if output.tmp | length >= hours %}
{% set d = dict(inval, **{"PriceTmp": output.tmp | sum(attribute="TotalPrice") }) %}
{% set output.value = output.value + [d] %}
{% endif %}
{%- endfor -%}
{% set starttime = (output.value | sort(attribute="PriceTmp"))[0]["Timestamp"] %}
{{ { "start" : starttime } }}
- stop: Return variable
response_variable: start_time
enabled: true
mode: parallel
max: 100