Cheapest Energy Hours - Jinja macro for dynamic energy prices

Here you go!

Update

v3.4.1

:sparkles: IMPROVEMENTS

  • Add new parameter precision which sets the number of decimals all price values are rounded to. Defaults to 5 which was also the setting for rounding price values in the previous versions
1 Like

really, you are amazing …
Thanks

Update

v3.5.0

:sparkles: IMPROVEMENTS

  • Add new output mode cheap_now which returns "true" if the current time is within the start and end time the output of your selection. Returns “false” otherwise. Note: macros always return strings, if you want it to be a boolean, add the | bool filter to your template.
1 Like

Thanks for the new update. :+1:

Update

v3.6.0

:sparkles: IMPROVEMENTS

  • Add new parameter price_factor which will be applied to the prices provided by the source sensor.

:bug: BUG FIXES

  • Fixed a bug that would display an unexpected error if no valid sensor was provided
1 Like

While the forum was down, I’ve updated the macro twice :slight_smile:

UPDATE

v4.0.0 and 4.1.0

:rotating_light: BREAKING

  • HA 2023.11 or higher is required because the macro now uses jinja tests introduced in that version
  • cheap_now has been renamed to is_now. It was incorrect in combination with cheapest=false as it would indicate the most expensive prices then.

:sparkles: IMPROVEMENTS

  • the hours parameter now accepts decimals, before it would always calculate using whole numbers. As of this version the source data will be recalculated based on the hour input, and the hours will be split in parts based on that. It will calculate how to split based on the hour input, so if eg hours=3.5 is used, it will split in 2 parts, but if you use 2.8 it will split the hours in 5 parts. You can override this calculation by setting the no_weight_points parameter.
  • the start and end parameters now accept datetimes, datetime strings and timestamps (basically they accept anything on which the as_datetime filter/function can be used. You can still use a 24 hour time string though. If you use the datetime input it will ignore the include_today and include_tomorrow settings, and it will use the input from the datetime
  • The split mode now groups time fractions where possible, to create the optimal number of parts.

:bug: BUG FIXES

  • Fxed a bug introduces in 4.0.0 regarding automatically selecting include_tomorrow based on the end input.
2 Likes

Hi,

I can’t get the end parameter to work - probably a glitch in my head…
I’m on core 2023.11.1 and macro version [Edit]: 4.2

In the tempate tester I’ve got:

{% from "cheapest_energy_hours.jinja" import cheapest_energy_hours %}
{% print cheapest_energy_hours('sensor.energi_data_service', end='02:00', hours=2, look_ahead=true, include_tomorrow=true) %}

I would expect the start time to be returned to be midnight or earlier but I get 03:00 tomorrow:
2023-11-11T03:00:00+01:00

What am I doing wrong?

UPDATE

v4.2.0

:sparkles: IMPROVEMENTS

  • added an additional parameter look_ahead_minutes to determine how many minutes can be passed in the current hour to still take it into account. This defaults to 5. So eg at 13:04 the current hour will be still taken into account, but not anymore after 13:05. Set to 60 to have it the same as it currently was, set 0 to never take the current hour into account.
  • Added an additional parameter datapoints_per_hour. This is only needed when your source sensor provides more than one price per hour (eg prices per 30 minutes) and the input for hours is not a whole number (eg 2.4). If not set in such cases, it could be that the macro will give an error about a mismatch between the datapoints per hour and the weight points per hour.
  • Added some important notes to the README

:bug: BUG FIXES

  • Fxed a bug in how the hours were split when the input for hours wasn’t a whole number
  • Fixed a bug where the last datapoitn would not be taken into account when the input for hours was not a whole number.

Update

v4.2.1

:bug: BUG FIXES

  • Fixed a bug where an additional day would be added to the end time

should be fixed in v4.2.1

Wow! Brilliant!
It works :slight_smile:

Update

v4.2.2

:bug: BUG FIXES

  • Fix a bug where hours would be set to 1 in case a the program parameter was used

Hi TheFes,

I may have stumbled upon an issue crossing midnight.
My code:

{% from "cheapest_energy_hours.jinja" import cheapest_energy_hours %}
{% print cheapest_energy_hours('sensor.energi_data_service', hours=3, look_ahead=true, include_tomorrow=true) %}

I’ve been running it between the hours of 21:00 and 22:00.
If hours=2 I get the expected: 2023-11-10T22:00:00+01:00
If hours=3 I get: Error: Not enough data within current selection

… but it looks like, the data are there alright in the ‘sensor.energi_data_service’:

current_price: 234.33564436449998
unit: kWh
currency: DKK
region: East of the great belt
region_code: DK2
tomorrow_valid: true
next_data_update: 13:05:55
today: 173, 168, 166, 146, 141, 143, 178, 209, 226, 225, 224, 223, 215, 199, 192, 232, 263, 367, 367, 356, 325, 234, 234, 234
tomorrow: 201, 200, 200, 197, 197, 199, 231, 232, 236, 239, 235, 234, 232, 232, 235, 246, 258, 361, 368, 357, 347, 246, 236, 232
raw_today: 
- hour: '2023-11-10T00:00:00+01:00'
  price: 173
- hour: '2023-11-10T01:00:00+01:00'
  price: 168
- hour: '2023-11-10T02:00:00+01:00'
  price: 166
- hour: '2023-11-10T03:00:00+01:00'
  price: 146
- hour: '2023-11-10T04:00:00+01:00'
  price: 141
- hour: '2023-11-10T05:00:00+01:00'
  price: 143
- hour: '2023-11-10T06:00:00+01:00'
  price: 178
- hour: '2023-11-10T07:00:00+01:00'
  price: 209
- hour: '2023-11-10T08:00:00+01:00'
  price: 226
- hour: '2023-11-10T09:00:00+01:00'
  price: 225
- hour: '2023-11-10T10:00:00+01:00'
  price: 224
- hour: '2023-11-10T11:00:00+01:00'
  price: 223
- hour: '2023-11-10T12:00:00+01:00'
  price: 215
- hour: '2023-11-10T13:00:00+01:00'
  price: 199
- hour: '2023-11-10T14:00:00+01:00'
  price: 192
- hour: '2023-11-10T15:00:00+01:00'
  price: 232
- hour: '2023-11-10T16:00:00+01:00'
  price: 263
- hour: '2023-11-10T17:00:00+01:00'
  price: 367
- hour: '2023-11-10T18:00:00+01:00'
  price: 367
- hour: '2023-11-10T19:00:00+01:00'
  price: 356
- hour: '2023-11-10T20:00:00+01:00'
  price: 325
- hour: '2023-11-10T21:00:00+01:00'
  price: 234
- hour: '2023-11-10T22:00:00+01:00'
  price: 234
- hour: '2023-11-10T23:00:00+01:00'
  price: 234

raw_tomorrow: 
- hour: '2023-11-11T00:00:00+01:00'
  price: 201
- hour: '2023-11-11T01:00:00+01:00'
  price: 200
- hour: '2023-11-11T02:00:00+01:00'
  price: 200
- hour: '2023-11-11T03:00:00+01:00'
  price: 197
- hour: '2023-11-11T04:00:00+01:00'
  price: 197
- hour: '2023-11-11T05:00:00+01:00'
  price: 199
- hour: '2023-11-11T06:00:00+01:00'
  price: 231
- hour: '2023-11-11T07:00:00+01:00'
  price: 232
- hour: '2023-11-11T08:00:00+01:00'
  price: 236
- hour: '2023-11-11T09:00:00+01:00'
  price: 239
- hour: '2023-11-11T10:00:00+01:00'
  price: 235
- hour: '2023-11-11T11:00:00+01:00'
  price: 234
- hour: '2023-11-11T12:00:00+01:00'
  price: 232
- hour: '2023-11-11T13:00:00+01:00'
  price: 232
- hour: '2023-11-11T14:00:00+01:00'
  price: 235
- hour: '2023-11-11T15:00:00+01:00'
  price: 246
- hour: '2023-11-11T16:00:00+01:00'
  price: 258
- hour: '2023-11-11T17:00:00+01:00'
  price: 361
- hour: '2023-11-11T18:00:00+01:00'
  price: 368
- hour: '2023-11-11T19:00:00+01:00'
  price: 357
- hour: '2023-11-11T20:00:00+01:00'
  price: 347
- hour: '2023-11-11T21:00:00+01:00'
  price: 246
- hour: '2023-11-11T22:00:00+01:00'
  price: 236
- hour: '2023-11-11T23:00:00+01:00'
  price: 232

today_min: 
hour: '2023-11-10T04:00:00+01:00'
price: 141

today_max: 
hour: '2023-11-10T17:00:00+01:00'
price: 367

today_mean: 227
tomorrow_min: 
hour: '2023-11-11T04:00:00+01:00'
price: 197

tomorrow_max: 
hour: '2023-11-11T18:00:00+01:00'
price: 368

tomorrow_mean: 248
use_cent: true
attribution: Data sourced from Energi Data Service
net_operator: Radius
tariffs: 
additional_tariffs:
  transmissions_nettarif: 0
  systemtarif: 0
  elafgift: 1
tariffs:
  '0': 0
  '1': 0
  '2': 0
  '3': 0
  '4': 0
  '5': 0
  '6': 0
  '7': 0
  '8': 0
  '9': 0
  '10': 0
  '11': 0
  '12': 0
  '13': 0
  '14': 0
  '15': 0
  '16': 0
  '17': 1
  '18': 1
  '19': 1
  '20': 1
  '21': 0
  '22': 0
  '23': 0

unit_of_measurement: Øre/kWh
device_class: monetary
icon: mdi:flash
friendly_name: Energi Data Service

Regards, and thank you for your effort!

Ah I know what’s wrong, for now add end='23:59'

1 Like

Update

v4.2.3

:bug: BUG FIXES

  • Fix a bug where include_tomorrow was not working when input for end was 00:00 or when there was no input at all
  • Fix bug in look_ahead_minutes

Fixed in 4.2.3

1 Like

How do I change the output format to TRUE / FALSE (I have read the doc. but I dont get it :-/ )

{% from "cheapest_energy_hours.jinja" import cheapest_energy_hours %}
{{ cheapest_energy_hours("sensor.energi_data_service", hours=4, time_format="%H:%M:%S", start="6:00", end="17:00", look_ahead=true, look_ahead_minutes=5) }}

Use mode="is_now"

1 Like

Thanks ! so easy :slight_smile:

BETA RELEASE

Version 4.2 needed a lot of bug fixes, sorry about that. In the last days a made a lot of changes based on the feedback of users. So many thanks for that. Keep sending in issues and questions, it will help to improve the macro even more!

Initially I’ve created the macro with only full hours in mind. The price data I worked with (Nordpool) only had hourly data, and the macro only did not really take minutes into account for the setting for the start and end period of the prices to check. In v3.0.0 support for sensors with more than one price per hour was added, and in 4.0.0 support for decimals in the hour setting was added.
Version brings the same support to the start and end parameters. You always could enter data which wasn’t a whole hour, but now the data will be converted to actually use that input.

:rotating_light: BREAKING CHANGES

  • Refactor of look_ahead
    • The way look_ahead works has been reworked. look_ahead_minutes is no longer used, and therefor marked as depreciated in the macro. For now the parameter will be left in, so it will not break you current templates. In v5.0.0 the current time is checked, and converted to a start time shortly before it. To support this, the data in your source sensor is split into smaller parts (minimum of 5 minutes, so 12 parts per hour). So if you enable look_ahead and the current time is eg 11:06, the start time for the price selection will be 11:05 and there will be 12 data points per hour. If the current time is 12:18, the start time will be 12:15 and there will be 4 data points per hour.
    • One of the big advantages of this, is that it will correctly work with mode='is_now'. In previous version that would only be true in the minutes set in look_ahead_minutes (so by default in the first 5 minutes of the hour), after that the current hour would no longer be taken into account for the price data, so it would no longer be one of the cheapest hours.

:sparkles: IMPROVEMENTS

  • Both start and end will be used to split the data, and start and end will be adjusted accordingly. start will be set to the closed time before it, and end to the closed time after. In the end the data will be split according to the highest data points per hour value calculated for start, end and hours
  • Refactor of look_ahead as described above.
  • mode='split is now a parameter split which can be set to true or false. So you can now eg use mode='is_now', split=true to immediately see if the current time is in one of the cheapest blocks. Not all modes work the same as for split=false
    • all: the same data as in the previous version. This will also still be returned if you set mode='split'
    • start: the start time of the first block
    • end: the end time of the last block
    • min and max: the lowest and highest price in the prices found
    • time_min and time_max: the start time of the block with the lowest or highest price
    • average and weighted_average: both give the average of all prices found, as weights are not taken into account for the split setting, this will be the same for both modes
  • a debug parameter is aded, if set to true it will return a dictionary with a lot of data which can be helpful for debugging, including the output based on the other parameters.
  • if no input for the sensor is provided, the macro will try to find a sensor with the attributes as set for attr_today and attr_tomorrow. So basically if you use the Nordpool integration, or an integration with the same attributes it wil give the start time of the cheapest hour today if you only set use cheapes_energy_hours(). This can be helpful if for some reason the entity_id changes. Do note that it’s most resource friendly to set the sensor data yourself if it not matches the defaults, so the macro doesn’t have to search for it.

Again, if there are any bugs, questions, feature request, please let me know!

What’s Changed

Full Changelog: Comparing v4.2.3...v5.0.0b0 · TheFes/cheapest-energy-hours · GitHub