Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Afternoon rank #32

Open
trintafi opened this issue Jan 13, 2024 · 4 comments
Open

Afternoon rank #32

trintafi opened this issue Jan 13, 2024 · 4 comments

Comments

@trintafi
Copy link

The default features are great and I can do most what I want by using/copying price_or_rank binary sensor. However I would like to have a separate rank calculation for a specific time period, that might be useful for others as well.

Use case: I use price_or_rank to heat up the bathroom floor when price is lowest. The floor stays quite warm for few hours, but quite typically the heated hours are in the morning or late evening. For morning showers this is fine, but I would like to have a separate afternoon rank to find the cheapest hours from 2pm to 22pm for example. But would not like to keep the floor heated during the expensive hours of the day.

@T3m3z
Copy link
Owner

T3m3z commented Jan 15, 2024

Yes, your use case seems to reasonable.

Maybe something like below would suite your needs? That could be used as an automation condition to decide whether to turn on/off heating. You give start time, stop time and desired "rank" X. The code searches for Xth cheapest hour during the desired period and stores the price of that hour to variable "limit". And finally the code checks whether we are in currently in the desired time period and whether the current electricity price is lower than the limit found.

This way you don't need to calculate ranks for each hour and store the results of that. Maybe not the most elegant solution but this should give you needed tools to fulfill your use case. Please test this thoroughly as I just wrote the code quite quickly as an starting point for you.

{% set start = today_at("12:00") %}
{% set stop = start + timedelta(hours=6) %}
{% set rank = 3  %}

{% set limit = (state_attr('sensor.shf_data', 'data') | selectattr("Timestamp", "ge", start | as_timestamp) | selectattr("Timestamp", "lt", stop | as_timestamp) | sort(attribute="TotalPrice"))[rank]["TotalPrice"] %}

{{ now() > start and now() < stop and states('sensor.shf_electricity_price_now') | float < limit }}

image

@trintafi
Copy link
Author

trintafi commented Apr 8, 2024

Thanks for the comments and code example. I've used this feature now for few months and can confirm it works. Few observations:
-I've used a slider to set wanted hours (above example 3). Above code works if wanted hours is below time delta, but if they are same, it does not work. In practise this is ok, but you need to limit slider selection below max.

Also as I didn't want to heat every afternoon on cheapest hours (in case there's been cheap hours in afternoon anyway), I've added a check to see how many hours the floor has been heated during previous 6 hours. So the condition to heat based on afternoon rank is that afternoon rank is on AND floor is cold (has not been on for more than 3 hours (=value of the slider) during past 6 hours).

  • platform: history_stats
    name: "sauna on counter 6 hours"
    unique_id: sauna_on_counter_6_hours
    entity_id: switch.xxxx
    state: "on"
    type: time
    start: "{{ now().timestamp() - 21600 }}" # 6 hours ago
    end: "{{ now().timestamp() }}"

  • binary_sensor:

    • name: "Sauna floor cold"
      unique_id: sauna_floor_cold
      state: '{{states("sensor.sauna_on_counter_6_hours") | float < states("input_number.shf_afternoon_rank_slider") | int }} '
  • binary_sensor:

    • name: "Afternoon rank acceptable"
      unique_id: afternoon_rank_acceptable
      availability: '{{ has_value("sensor.shf_electricity_price_now") }}'
      state: >
      {% set start = today_at("16:00") %}
      {% set stop = start + timedelta(hours=6) %}
      {% set rank = states("input_number.shf_afternoon_rank_slider") | int %}
      {% set limit = (state_attr('sensor.shf_data', 'data') | selectattr("Timestamp", "ge", start | as_timestamp) | selectattr("Timestamp", "lt", stop | as_timestamp) | sort(attribute="TotalPrice"))[rank]["TotalPrice"] %}
      {{ now() > start and now() < stop and states('sensor.shf_electricity_price_now') | float < limit }}
  • binary_sensor:

    • name: "Afternoon_rank and cold floor"
      unique_id: shf_sauna_afternoon_rank_and_cold
      state: '{{ is_state("binary_sensor.sauna_floor_cold", "on") and is_state("binary_sensor.afternoon_rank_acceptable", "on") }}'

@trintafi
Copy link
Author

trintafi commented Apr 8, 2024

And sorry for violating your good naming principle, by adding shf in my own sensor names as well. I thought it would be handy to find all sensors related to spot prices easily (own or coming from the package), but didn't think of possible future conflicts at that point...

If anyone else uses code above, please don't make the same mistake.

@Hiekkaharju
Copy link

Hiekkaharju commented Apr 20, 2024

Thanks for the comments and code example. I've used this feature now for few months and can confirm it works

Sorry but I have trouble believing that this would work. To be clear: I have not tried it.
But states('sensor.shf_electricity_price_now') is actually one of the values in state_attr('sensor.shf_data', 'data') but rounded to 4 decimals, and "limit" will at a point be the same value without rounding i.e. with 5 decimals. Thus when comparing those, you will get a near random result, actually based on whether the rounding was up or down.
IMHO the best way to fix that, and many other similar cases people will run into, would be to not round sensor.shf_electricity_price_now in the first place i.e. line 64 spot_prize.yaml, as the Nordpool prizes are EUR/MWh with two decimals and thus converted to EUR/kWh they are with 5 decimals.

update: after recalling Finish governments recect "clever" decision to raise VAT to 25.5% I change my mind: best would be if all the EUR/kWh prices were actually rounded, but all to 5 decimals - this would keep the same resolution the original Nordpool prices have and would not add extra digits due to e.g. VAT calculation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants