Closed c0mplex1 closed 9 months ago
What you want is surely possible, but the macro is not built for this
Some remarks:
hours
it will use the default of 1 hour.now()
as start will constantly move your starting point. With a fixed end, this will always make the last hour the cheapest one.I could probably build in support for this, but it's a rather simple only line template without the need for the macro.
For 8:00 - 20:00
{% set sensor = "sensor.electricity_price" %}
{% set within_time = today_at('08:00') < now() < today_at('20:00') %}
{% if sensor | has_value and within_time %}
{% set current_price = states(sensor) | float %}
{% set cheapest_price = state_attr(sensor, 'Prices')[8:19] | map(attribute='price') | min %}
{{ current_price == cheapest_price }}
{% else %}
{{ False }}
{% endif %}
20:00 - 08:00 is a lot more tricky though, I don't think that it is possible to do that 100% reliably in a template binary sensor only. The thing is that the lowest price can potentially be at 22:00 and you will lose that price after midnight. Unless your sensor also shows yesterday's prices (which will make the template above incorrect as well)
I've added a mode extreme_now
to do what you requested. However, you will still have issues when the day changes at midnight, and you lose the data of the previous day.
I'm waiting for some other things, but you can manually update to the version on the main branch.
At the moment I test the solution below, based on your replay a few days ago. Because my programming skills are not that high, I have to test it in real-time.
template:
# Get the lowest price between 8:00 - 20:00 (Day) and between 20:00 - 8:00 (Night).
- trigger:
- platform: time
at: "16:10"
sensor:
- unique_id: electricity_night_min_price
name: Electricity Night Min Price
state: >
{{ state_attr("sensor.electricity_price", "Prices")[20:32] | map(attribute="price") | min }}
- unique_id: electricity_day_min_price
name: Electricity Day Min Price
state: >
{{ state_attr("sensor.electricity_price", "Prices")[32:44] | map(attribute="price") | min }}
- binary_sensor:
- name: Test dag/nacht
unique_id: test_dag_nacht
state: >
{% set sensor = "sensor.electricity_price" %}
{% set is_day = today_at("08:00") <= now() < today_at("20:00") %}
{% if sensor | has_value %}
{% set current_price = states(sensor) | float(0) %}
{% if is_day %}
{% set cheapest_price = states("sensor.electricity_day_min_price") | float(0) %}
{% else %}
{% set cheapest_price = states("sensor.electricity_night_min_price") | float(0) %}
{% endif %}
{{ current_price == cheapest_price }}
{% else %}
False
{% endif %}
It looks like you also have the data of yesterday in your sensor (as you are taking 20:44 for 8:00 - 20:00 In that case you can work with the data the sensor provides.
With the setup above, you will be using yesterdays data until 16:10, because then the two trigger based sensors will refresh.
Can you show what is currently in the forecast of your electricity sensor?
This is what I currently have:
Prices:
- price: 0.07
readingDate: "2024-02-14T23:00:00Z"
- price: 0.07
readingDate: "2024-02-15T00:00:00Z"
- price: 0.07
readingDate: "2024-02-15T01:00:00Z"
- price: 0.07
readingDate: "2024-02-15T02:00:00Z"
- price: 0.07
readingDate: "2024-02-15T03:00:00Z"
- price: 0.07
readingDate: "2024-02-15T04:00:00Z"
- price: 0.08
readingDate: "2024-02-15T05:00:00Z"
- price: 0.1
readingDate: "2024-02-15T06:00:00Z"
- price: 0.1
readingDate: "2024-02-15T07:00:00Z"
- price: 0.1
readingDate: "2024-02-15T08:00:00Z"
- price: 0.08
readingDate: "2024-02-15T09:00:00Z"
- price: 0.08
readingDate: "2024-02-15T10:00:00Z"
- price: 0.07
readingDate: "2024-02-15T11:00:00Z"
- price: 0.07
readingDate: "2024-02-15T12:00:00Z"
- price: 0.08
readingDate: "2024-02-15T13:00:00Z"
- price: 0.08
readingDate: "2024-02-15T14:00:00Z"
- price: 0.08
readingDate: "2024-02-15T15:00:00Z"
- price: 0.1
readingDate: "2024-02-15T16:00:00Z"
- price: 0.1
readingDate: "2024-02-15T17:00:00Z"
- price: 0.1
readingDate: "2024-02-15T18:00:00Z"
- price: 0.08
readingDate: "2024-02-15T19:00:00Z"
- price: 0.07
readingDate: "2024-02-15T20:00:00Z"
- price: 0.07
readingDate: "2024-02-15T21:00:00Z"
- price: 0.07
readingDate: "2024-02-15T22:00:00Z"
average: 0.08
unit_of_measurement: EUR/kWh
friendly_name: Electricity price
Between 13:00 and 15:00 I get the prices of tomorrow.
Then I can use below, that's why I trigger at 16:10
{{ state_attr("sensor.electricity_price", "Prices")[32:44] | map(attribute="price") | min }}
Yes, but you refresh the sensors at 16:10 that means that as of then you are using the data for tomorrow for the day price, while you should still use the data for today until 20:00
That's correct. When I refresh the sensor at 16:10 then the data of tomorrow is saved, but will be used between 08:00 and 20:00 next day.
at 16:10 you will do this:
- unique_id: electricity_day_min_price
name: Electricity Day Min Price
state: >
{{ state_attr("sensor.electricity_price", "Prices")[32:44] | map(attribute="price") | min }}`
That will give you the prices from 8:00 - 20:00 tomorrow.
But at that time it is still before 20:00 today. So your binary sensor will check the current price against the cheapest day price tomorrow.
You should refresh the prices at 20:00
It's now 12:00 and the switch goes from false to true.
It will use today's prices until 16:10. After that it will use tomorrows prices. The binary sensor will be incorrect between 16:10 and 20:00
BTW: I do not use prices of the next day. I only want the lowest price between 08:00 and 20:00 and then use it next day. At 16:00 the prices of next are available.
Let's wait a week or so to see how it works.
Look, you have a trigger based template sensor, which triggers at 16:10. It will refresh the sensors defined under it at that time.
So at 16:10, these 2 sensors will get new values. This means, that this sensor will start showing the lowest price of 8:00 - 20:00 tomorrow.
But... Your binary sensor will compare the current price against that sensor, so from the period from 16:10 to 20:00 it will check if the current price is the same as the cheapest price between 8:00 and 20:00 tomorrow, not the cheapest price between 8:00 and 20:00 today.
That's why I'm saying you should use 20:00 for the trigger, not 16:10.
Aaaaaah, check. Now I see. I have changed the trigger time to 20:00.
If you want, you may close this topic.
I appreciate your help, and thank you very much for your explanation and patience.
Okay, I have an alternative approach for you, using the latest version of the macro (not released yet).
First, I noticed that the prices including VAT coming from EnergyZero are rounded to 2 decimals, while the prices excluding VAT are accurate up to 5 decimals. So if you would use the prices excluding VAT, it would not show the same values multiple times per day, and you could actually determine the real cheapest moment.
In the example below I have used prices including VAT, to replicate your current sensor. The price sensor will update every hour, and will display the current price as it's state and has the prices of yesterday, today and tomorrow (if available) in the prices
attribute. The advantage of also including yesterdays prices is, that you don't need to store the prices of the period between 20:00 and 8:00 in a separate template sensor, you can always access them.
template:
# get the prices using the service call provided by the core Energy Zero integration
- trigger:
- platform: time_pattern
hours: "/1"
- platform: homeassistant
event: start
action:
- service: energyzero.get_energy_prices
data:
incl_vat: true
config_entry: fe7bdc80dd3bc850138998d869f1f19d
start: "{{ today_at() - timedelta(days=1) }}"
end: "{{ today_at() + timedelta(days=2) }}"
response_variable: prices
sensor:
- unique_id: 79c470d8-4ccd-4f44-b3a2-e3d59d5dda8a
name: Energy Zero prices
state: "{{ prices.prices | selectattr('timestamp', '<=', utcnow().strftime('%Y-%m-%d %H:%M:%S+00:00')) | map(attribute='price') | list | last }}"
attributes:
prices: "{{ prices.prices }}"
# binary sensor which will be on during the periods with the lowest price
- binary_sensor:
- unique_id: 5f2706e7-ccd2-4b74-ab8b-4dbb77209c1f
name: Laagste prijs dag/nacht
state: >
{% from 'cheapest_energy_hours.jinja' import cheapest_energy_hours %}
{%- set start_time, end_time = '08:00', '20:00' -%}
{%- set day = today_at(start_time) <= now() < today_at(end_time) %}
{%- set after_mn = now() < today_at(start_time) -%}
{%- set start=today_at(start_time) if day else (today_at(end_time) - timedelta(days=1 if after_mn else 0)) -%}
{%- set end=today_at(end_time) if day else (today_at(start_time) + timedelta(days=0 if after_mn else 1)) -%}
{{ cheapest_energy_hours('sensor.energy_zero_prices', time_key='timestamp', start=start, end=end, mode='extreme_now') }}
Closing this, as you seem to have solved it yourself, and I provided another approach to tackle it as well.
I'm stuck. What I want is a binary sensor that turns on, and stays on for the next hour(s), when the electricity price is lowest. If the price goes up, the sensor must switch off, but if the price falls again, the switch must switch on again. I want this for 2 periods (day/night): from 08:00 to 20:00 and from 20:00 to 08:00. No matter what I try, I can't get it to work. I get the idea that what I want is not possible.
For example
The automations I tried are as follows: