HomeAssistant ja sähköpörssiohjaus

-Teme-

Vakionaama
Itse siirryin splitattuun konffikseen kun configuration yaml kasvoi yli 2000 rivin - siitä taitaa olla noin 3 vuotta ja sen jälkeen tullut paljon yaml rivejä lisää.
Oikeasti hankala löytää ja tiettyjä asioita ja välillä huomaa että on tekemässä jotain sellaista mikä löytyy jo
 

Nautilus

Jäsen
Aivan joo. Luuin, että Rankki muokkautuu siirtohintojen jälkeen.
Riippuu rankista :)

Ainakin tuossa omassa SHF-paketissa oli suoraan myös SHF Rank now -sensori joka tekee rankin shf_data:n TotalPrice-attribuutista eli se kertoo mikä on kuluvan tunnin rank siirtoineen jos ne on lisännyt. Itse käytän tuota on kun on yö/päivähinnoittelu siirrossa.
 

jupet

Jäsen
15min resoluution testiversio löytyy nyt täältä branchista: https://github.com/T3m3z/spotprices2ha/tree/15min_prices

Rohkeat kokeilkoot ja rokan syökööt :)

Elisiltapäivällä otin tämän ajoon ja tulee tämmöistä herjaa:

We have generated statistics for 'SHF Average price today' (sensor.shf_average_price_today) in the past, but it no longer has a state class, therefore, we cannot track long term statistics for it anymore.
Toisessa HA-instanssissa joku suht tuoreeltaan tämän branchin julkaisun jälkeen napattu ei ole moista herjaa. Ei kyllä silmällä erota mitään eroa ko. sensorin määrittelyissä eli jokin muu asia tässä takana jotenkin...

Edit: asiaa pohtiessa hämäriä muistikuvia että olen saattanut tuohon käydä joskus muinoin itse lisäämässä state_class: measure jotta menee pitkäaikaissäilöön. Eli varmaan ihan oman säädön lopputulos.


Rank näytti tyhjää uudelleenkäynnistelystä huolimatta, vaihdoin rank sensorin heebo1974 edellä postaamaan versioon ja nyt toimii.

Tein samalla +15min ja +30min rank sensorit niin voi pistää ehdoksi PILP kompuran ja poistoilmapuhaltimen käynnistykselle että kaikki nämä on alle määritetyn rank-rajan (tällä siis rajoitetaan esim 10 kalleinta varttia pois per päivä)
- sensor:
- name: "SHF Rank now+30min"
unique_id: shf_electricity_rank_now+30
availability: >
{{ state_attr("sensor.shf_data", "raw") is not none }}
state: >
{% set data = state_attr("sensor.shf_data", "raw") %}
{% set current = data | default([])
| selectattr("DateTime", "le", (now()+timedelta(minutes=30)).isoformat())
| list
| last %}

{% if current and 'Rank' in current %}
{{ current.Rank | int(default=none) }}
{% else %}
none
{% endif %}
 
Viimeksi muokattu:

grendy

Vakionaama
Itsekin päivitin eilen 60->15min automaation ja meni kyllä mystisen helposti. Copypastesi vaan uuden yamlin vanhan tilalle ja muutti SFH max rank allowedin 17->72. Eli oma automaatio toimii siis niin että hinta on oma asetuksena (ei tarvinnut muuttaa tietenkään) ja sitten toisena tää max rank allowed. Jos SHF rank allowed ja SHF price acceptable molemmat on OFF niin sitten VILP menee kahvitauolle. Ja kahvitaukoa on 25% päivästä maksimissaan.
 

Temez

Aktiivinen jäsen
15min resoluution testiversio löytyy nyt täältä branchista: https://github.com/T3m3z/spotprices2ha/tree/15min_prices
Uusi versio 0.2.5.1 löytyy nyt tuolta. Korjattu Rank Now -sensori.
Riippuu rankista :)

Ainakin tuossa omassa SHF-paketissa oli suoraan myös SHF Rank now -sensori joka tekee rankin shf_data:n TotalPrice-attribuutista eli se kertoo mikä on kuluvan tunnin rank siirtoineen jos ne on lisännyt. Itse käytän tuota on kun on yö/päivähinnoittelu siirrossa.
Paketin mukana tuleva Rank Now -sensori tosiaan ottaa myös asetetun siirtohinnan huomioon. Eli rajapinnasta tulee Rank-arvo, mutta se lasketaan sitten vielä HA:n päässä uusiksi mahdollisen yösiirtohinnan vaikuttaessa.

Ketjun koodiesimerkeissä on näemmä otettu "rajapinnan raakadata" käyttöön eli siinä pelkän energiahinnan Rank.
 

Temez

Aktiivinen jäsen
Edit: asiaa pohtiessa hämäriä muistikuvia että olen saattanut tuohon käydä joskus muinoin itse lisäämässä state_class: measure jotta menee pitkäaikaissäilöön. Eli varmaan ihan oman säädön lopputulos.
Tästä taitanee olla kiinni. Voisin lisätä ne myös pakettiinkin.
 

Temez

Aktiivinen jäsen
Tätä virhettä näyttää nyt tulevan logiin. Ilmeisesti datamäärä nyt hieman paisunut, en tiedä onko jotain tehtävissä tai onko tästä ylipäätään haittaa?

  • State attributes for sensor.shf_electricity_price_now exceed maximum size of 16384 bytes. This can cause database performance issues; Attributes will not be stored
  • State attributes for sensor.shf_data exceed maximum size of 16384 bytes. This can cause database performance issues; Attributes will not be stored
Tätä joo tulee logille. En ole itse havainnut ongelmia, mutta olisihan nuo kiva saada pois. Vaikeaa vaan muokata enää niitä hiiteen, kun pitäisi räjäyttää nuo sensorit useammaksi palaseksi tai poistaa sensorin attribuuteista kenttiä. Molemmilla varmaankin ikäviä vaikutuksia käyttäjille, kun saattaa olla koodia/logiikkaa kiinni niissä.
 

Duudson

Jäsen
Paketin mukana tuleva Rank Now -sensori tosiaan ottaa myös asetetun siirtohinnan huomioon. Eli rajapinnasta tulee Rank-arvo, mutta se lasketaan sitten vielä HA:n päässä uusiksi mahdollisen yösiirtohinnan vaikuttaessa.
Noin se on muistini mukaan aiemmin toiminutkin, mutta nyt jostain syystä ainakin itselläni se ei ota siirtohintoja huomioon 15 minuutin siirtymän jälkeen. Otin uusimman version kokonaisuudessaan ja täällä mainitun rank korjauksen. Ehkä meni siinä rikki
 

Duudson

Jäsen
Otin nyt myös uusimman Temezin version, mutta sama homma on siinäkin. Rankki näyttää vain sähkön hinnan rankkia vaikka siirtohinnat on konffattu

Itse en tuota nyt enää tarvitse kun tein oman klo 18:00-17:45 rankkauksen siirtohintoineen, mutta en mielestäni koskenut näihin alkuperäisiin. Jos muilla toimii niin sitten varmaan räpelsin tuon itse rikki
 

MarjoC

Jäsen
Mä päivitin koodin ja silti minulla antaa näin: korjasi kyllä tuon 15 min heiton, mutta itse sensori ei päivity millään. Missasinko mä jonkun päivityksen tuohon scriptiin?


1759855563932.png
 

hemaris

Aktiivinen jäsen
Mä päivitin koodin ja silti minulla antaa näin: korjasi kyllä tuon 15 min heiton, mutta itse sensori ei päivity millään. Missasinko mä jonkun päivityksen tuohon scriptiin?


katso liitettä 109060
Minä ihmettelin samaa toisen sensorin (helpperi) kanssa. Googlaamalla löytyi tieto että tuohon määrittelyyn pitää lisätä suure ("units_of_measurement") jotta ymmärtää että on numeerinen arvo. Siihen voisi vaan yrittää laittaa "Rank", tosin en ole ihan varma että onko tuossa joku sallittujen lista. Itselläni kyse oli helpperistä ja siinä puimin suoraan listalta oikean suureen.

Templaten alta löytyy ohjeet:

Edit. Voi olla että ymmärsin väärin ongelman, eli vastaus oli tuohon graafiseen ulkoasuun ei ehkä varsinaiseen ongelmaan. Itsellä tuo päivitys kyllä toimii.
 

MarjoC

Jäsen
Mites muut näyttää hintoja minulla tällainen taulukko: olen siis rakentanut noille Heat, DHW omat rank or price muuttujat ja sitten Yield ok on vain että on >0:n euroissa ja Sell jos on yli tietyn arvon.
1759856791756.png
 

MarjoC

Jäsen
Minä ihmettelin samaa toisen sensorin (helpperi) kanssa. Googlaamalla löytyi tieto että tuohon määrittelyyn pitää lisätä suure ("units_of_measurement") jotta ymmärtää että on numeerinen arvo. Siihen voisi vaan yrittää laittaa "Rank", tosin en ole ihan varma että onko tuossa joku sallittujen lista. Itselläni kyse oli helpperistä ja siinä puimin suoraan listalta oikean suureen.

Templaten alta löytyy ohjeet:

Edit. Voi olla että ymmärsin väärin ongelman, eli vastaus oli tuohon graafiseen ulkoasuun ei ehkä varsinaiseen ongelmaan. Itsellä tuo päivitys kyllä toimii.
lähti toimimaan minullakin. :)
 

MarjoC

Jäsen
Ei varmaan ole mitään valmista ihan suoraan käytettävää, mutta tässä mun pohja, josta voi editoida omaan tarpeeseen:

Koodi:
type: custom:html-template-card
title: Electricity prices
ignore_line_breaks: true
content: |
  <style>
    table {
      width: 100%;
      border-collapse: collapse;
    }
    th, td {
      padding: 8px;
      text-align: center;
      border: 1px solid #ddd;
    }
    th {
      background-color: #f2f2f2;
    }
    .ok-true {
      background-color: #d4edda;
    }
    .ok-false {
      background-color: #f8d7da;
    }
    .rank-ok {
      background-color: #d4edda;
    }
    .rank-not-ok {
      background-color: #f8d7da;
    }
  </style>
  <table style="border: 1px solid">
    <tr>
      <td><b>Time</b></td>
      <td><b>SPOT</b></td>
      <td><b>Total</b></td>
      <td class="blue-text"><b>Rank</b></td>
      <td><b>Yield</b></td>
      <td><b>Heat OK?</b></td>
      <td><b>DHW OK?</b></td>
      <td><b>Yield OK?</b></td>
      <td><b>Sell?</b></td>
    </tr>
    
    {% for value in state_attr('sensor.shf_electricity_price_now', 'data') %}
      
      {% set spot_price_no_tax = value['PriceNoTax'] * 100 %}
      {% set spot_price_with_tax = value['PriceWithTax'] * 100 %}
      {% set total_price_with_tax = value['TotalPrice'] * 100 %}
      {% set yield_margin = states('input_number.yield_margin') | float %}
      {% set selling_price = (value['PriceNoTax'] * 100) - yield_margin %}
      {% set price_time_slot = strptime(value['DateTime'][:-6], '%Y-%m-%dT%H:%M:%S') | as_timestamp | timestamp_custom('%d.%m. %H:%M', true) %}
      
      {% set now_ts = now() | as_timestamp %}
      {% set slot_start = strptime(value['DateTime'][:-6], '%Y-%m-%dT%H:%M:%S') | as_timestamp %}
      {% set slot_end = slot_start + 900 %}  {# 15 min = 900 sekuntia #}

      {% if now_ts >= slot_start and now_ts < slot_end or slot_start > now_ts %}

        <tr>       
          <td>{{ (price_time_slot) }}</td>
          <td>{{ (spot_price_with_tax) | round(2) }} c/kWh</td>
          <td>{{ (total_price_with_tax) | round(2) }} c/kWh</td>
          <td class="blue-text">{{ value['Rank'] }}</td>
          <td>{{ (selling_price ) | round(2) }} c/kWh</td>
          <td class="{% if value['Rank'] | int <= states('input_number.shf_rank_slider') | int or total_price_with_tax <= (states('input_number.shf_price_slider') | float * 100) %}ok-true{% else %}ok-false{% endif %}">
            {% if value['Rank'] | int <= states('input_number.shf_rank_slider') | int or total_price_with_tax <= (states('input_number.shf_price_slider') | float * 100) %}
              ✅
            {% else %}
              ❌
            {% endif %}
          </td>
          <td class="{% if value['Rank'] | int <= states('input_number.shf_rank_slider_dhw') | int or total_price_with_tax <= (states('input_number.shf_price_slider_dhw') | float * 100) %}ok-true{% else %}ok-false{% endif %}">
            {% if value['Rank'] | int <= states('input_number.shf_rank_slider_dhw') | int or total_price_with_tax <= (states('input_number.shf_price_slider_dhw') | float * 100) %}
              ✅
            {% else %}
              ❌
            {% endif %}
          </td>
            <td class="{% if selling_price < 0 %}ok-false{% else %}ok-true{% endif %}">
            {% if selling_price < 0 %}
              ❌
            {% else %}
              ✅
            {% endif %}
          </td>
          <td class="{% if selling_price <= states('input_number.shf_max_yield_price') | int %}ok-false{% else %}ok-true{% endif %}">
            {% if selling_price <= states('input_number.shf_max_yield_price') | int %}
              ❌
            {% else %}
              ✅
            {% endif %}
          </td>
          </td>
        </tr>
      {% endif %}
    {% endfor %}
  </table>
 

Nautilus

Jäsen
Uusi versio 0.2.5.1 löytyy nyt tuolta. Korjattu Rank Now -sensori.

Paketin mukana tuleva Rank Now -sensori tosiaan ottaa myös asetetun siirtohinnan huomioon. Eli rajapinnasta tulee Rank-arvo, mutta se lasketaan sitten vielä HA:n päässä uusiksi mahdollisen yösiirtohinnan vaikuttaessa.

Ketjun koodiesimerkeissä on näemmä otettu "rajapinnan raakadata" käyttöön eli siinä pelkän energiahinnan Rank.
Aloin katseleen näitä uusia 15min-versioita niin eikös tässä nyt katoa se "TotalPrice"-logiikka rankista, oliko siihen joku erityinen syy?

Edellinen:
Koodi:
       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 }}
Uusi:
Koodi:
      state: >
      {{ (state_attr("sensor.shf_data", "data") | selectattr("Timestamp", "le", now() | as_timestamp) | list | last | default(none))["Rank"] | default(none) }}
 

Temez

Aktiivinen jäsen
Aloin katseleen näitä uusia 15min-versioita niin eikös tässä nyt katoa se "TotalPrice"-logiikka rankista, oliko siihen joku erityinen syy?
Ainoastaan koodarin tyhmyys. Ja vireystila mahdollisesti vaikuttavana osatekijä. Pitääpä palautella se toiminnallisuus.
 

Ponde

Tulokas
Itselläni tällainen virhe edellisen tuntikohtaisen skriptin osalta. Lienee joku virhe alustassa kun itse spot-price.yaml skriptiin ei ole tullut muutoksia pitkään aikaan? Meille tulee vartti mittaus/laskutus joskus keväällä

sensor.shf_electricity_price
"This entity is no longer being provided by the rest integration"
 

TouhoA

Tulokas
Onko muilla vastaavaa käyttötapausta jonkin laitteen osalta. Oon tähän ratkaisua koittanut itse pähkäillä, mutta selkeesti ei oma osaaminen riitä.

Makkareiden lämmityksessä perinteiset Enston Taso patterit, joiden päälläoloa ohjataan Shelly 1PM:llä. Näille rakennettu automaatio, joka käynnistää tarvittaessa patterin 15-30 minuutiksi kunkin tunnin aikana, mikäli SHF:n kautta asetettu pörssisähkön suurin sallittu hinta alittuu ja huoneen lämpötila on alle makuuhuoneen raja-arvon. Tämä on toiminut hyvin pari talvea, kun ILP ja leivinuuni kuitenkin tuottaa lämpöä niin hyvin, että kakkareissa ei juurikaan tarvitse lämmittää.

Nyt kun ensi kuun alusta oma sähkömyyjä siirtyy myös varttihinnoitteluun, pitäisi opitmoida lämmityksiä niin, että saisin valittua aina ko. tunnin halvimman vartin (tai kaksi) tuota lämmitystä varten, mutta ongelmia tuottaa juuri tuon tunnin halvimman vartin tunnistaminen ja käyttäminen automaation triggerinä. Eli sen sijaan, että käynnistettäisiin patterit aina tasalta (tai muuna ennalta määrättynä aikana), pitäisi löytää jokaiselle tunnille optimaalinen aika käynnistää automaatio, joka päättelee sitten muiden arvojen perusteella käynnistetäänkö patterit.
 

kenzy

Jäsen
Aloin katseleen näitä uusia 15min-versioita niin eikös tässä nyt katoa se "TotalPrice"-logiikka rankista, oliko siihen joku erityinen syy?

Edellinen:
Koodi:
       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 }}
Uusi:
Koodi:
      state: >
      {{ (state_attr("sensor.shf_data", "data") | selectattr("Timestamp", "le", now() | as_timestamp) | list | last | default(none))["Rank"] | default(none) }}

Tällä lähtenee pelittelemään:

Koodi:
  - sensor:
      - name: "SHF Rank now"
        unique_id: shf_rank_now
        unit_of_measurement: Rank
        availability: >
          {{ state_attr('sensor.shf_electricity_price_now', 'data') is not none }}
        state: >
          {% set data_all = state_attr('sensor.shf_electricity_price_now', 'data') | default([], true) %}
          {% if data_all | length > 0 %}
            {# Rajataan vain tämän päivän data #}
            {% set start = today_at('00:00') | as_timestamp %}
            {% set end = today_at('23:59:59') | as_timestamp %}
            {% set data = data_all
              | selectattr('Timestamp', 'ge', start)
              | selectattr('Timestamp', 'le', end)
              | list %}
            {% set now_ts = now() | as_timestamp %}
            {% set current = data | selectattr('Timestamp', 'le', now_ts) | list | last %}
            {% if current %}
              {% set current_price = current['TotalPrice'] | float(0) %}
              {% set prices = data | map(attribute='TotalPrice') | map('float') | list %}
              {% set sorted = prices | sort %}
              {% set rank = sorted.index(current_price) + 1 %}
              {{ rank }}
            {% else %}
              unknown
            {% endif %}
          {% else %}
            unknown
          {% endif %}
 
Viimeksi muokattu:

jupet

Jäsen
Meillä tiskikone ajastuu tämmöisellä automaatiolla, hyödyntää SHF-setin cheapest_hours skriptiä joka tosin nykyään hakee halvimpia vartteja, "hours: 5" = 1:15 siis. Korjaus: en tiedä oliko vain sokeus vai päivittyikö tämä vasta viimeisimmässä versiossa, mutta nyt kun katson uudestaan niin tässä tunnit on tunteja, ja 1:15 saadaan siis pyytämällä 1.25 tuntia.

Koodi:
alias: Kitchen dish washer set next cheapest start time
description: >-
  Automatic cheapes starting time for dish washer
triggers:
  - at: "20:00:00"
    trigger: time
actions:
  - data:
      start: "{{ now() }}"
      stop: "{{ now() + timedelta(hours=12)}}"
      hours: 5
    response_variable: result
    action: script.cheapest_hours
  - data:
      timestamp: "{{ result['start']}}"
    target:
      entity_id: input_datetime.dish_washer_timer
    action: input_datetime.set_datetime
mode: single

Saat siis tähän malliin nykyhetkestä tunnin eteenpän halvimman vartin alkamisajan kun laitat timedelta hours=1 loppuaikaan ja hours: 0.25 pyynnön. Automaation voi triggeröidä input_datetime mätsilläja katsoo sitten aina patteria sammuttaessa vartin päästä seuraavan halvimman vartin jollekin aikavälille...
 
Viimeksi muokattu:

jupet

Jäsen
"hours: 5" = 1:15 siis. Korjaus: en tiedä oliko vain sokeus vai päivittyikö tämä vasta viimeisimmässä versiossa, mutta nyt kun katson uudestaan niin tässä tunnit on tunteja, ja 1:15 saadaan siis pyytämällä 1.25 tuntia.
Virheellinen väittämäni korjattu edelle.
 

janti

Moderaattori
Ylläpidon jäsen

Nordpool Predict FI – Home Assistant Integration​

Nordpool Predict FI is a Home Assistant integration that displays the forecasts published by vividfog/nordpool-predict-fi. It reads the hourly price feed (prediction.json) and the wind forecast (windpower.json), then exposes the data as sensors.

The integration shows all available data from today (Helsinki time) onwards. Price data combines Sähkötin realized prices with forecast data, transitioning from actual to predicted values. Wind power data is shown similarly. Cheapest windows work across the entire data timeline, using both realized and forecast data to find the most economical future price windows throughout the week.
 

-Teme-

Vakionaama
Tuli otettua tuo nordpool-predict integraatio heti käyttöön.
Dashboard sai tuulivoima- ja hintaennusteen, pinaisessa viirusta alkaa ennuste ja samalla tarkkuus muuttuu 15m -> 1h.
Alemmassa sitten on peräpeili tsekkaus hinta vs kulutus ja tämänhetkinen kulutus
1760803644784.png

Seuraavaksi pitääkin alkaa rakentamaan tulevan parin päivän jaksolle erinlaisia hinta-arvio sensoreita
 

kenzy

Jäsen
Minä joskus pari vuotta sitten hain Fingridin apin kautta suoraan noi kaikkien sähköntuotantomenetelmien datat + tuulivoimaennusteet, enkä voi sanoa, että olisi pystynyt niiden perusteella mitenkään kovin luotettavasti tekemään mitään toimenpiteitä sähkön hinnan säästön osalta. Mielenkiintoista kuitenkin seurata saako joku kyhättyä tuosta jotakin oikeasti säästön arvoista aikaiseksi.
 

maanma

Vakionaama
Kävi tänään ilmi että Nordpool integraationi current price taitaa päivittyä 60 min välein.

Niinpä
{% set ihq = (now().hour-1)*4 |int %}
{% if now().minute <15 %}
{% set ihq = ihq+ 1 |int %}
{% elif now().minute <30 %}
{% set ihq = ihq+ 2 |int %}
{% elif now().minute <45 %}
{% set ihq = ihq+ 3 |int %}
{% else %}
{% set ihq = ihq+ 4 |int %}
{% endif %}
{% set ihq=ihq -1 | int %}
{% if [] != state_attr('sensor.nordpool_kwh_fi_eur_3_10_0255','raw_today') %}
{{ (state_attr('sensor.nordpool_kwh_fi_eur_3_10_0255','raw_today')[ihq].value ) | float }}
{% endif %}
 

Jamo70

Aktiivinen jäsen
On tullut käytettyä tätä SHF tosi monessa ja nyt ehkä vähän tyhmä kysymys, kun mietin pientä automaatiota keskelle päivää.
Toimiiko start ja stop aikana myös ”tomorrow”?
Muissa on ollut ehtona aina now tai today.
 

Liitteet

  • IMG_7665.jpeg
    IMG_7665.jpeg
    124,4 KB · Katsottu: 31

Temez

Aktiivinen jäsen
On tullut käytettyä tätä SHF tosi monessa ja nyt ehkä vähän tyhmä kysymys, kun mietin pientä automaatiota keskelle päivää.
Toimiiko start ja stop aikana myös ”tomorrow”?
Muissa on ollut ehtona aina now tai today.
Ei taida tuollaista olla. Mutt tänään kello x + 24h tekee saman.

Koodi:
 {{ today_at('12:00') + timedelta(hours=24) }}
 

Jassu

Tulokas
Mulla on yli kymmneniätuhansia rivejä YAMlia nojaamassa tuohon vanhaan 1h välein olevaan SHF:ään ja samalle 24 portaiseen rankkaukseen. Kiva että muutoksessa se jatkoi toimintaansa ilman käpistelyä.

Jos nyt päivitän uuteen versioon, niin käsittääkseni siinä suoraan on vain ja ainoastaan tuettu varttihinnoittelu (ja ranking muuttuu 24 -> 96), jos en käsin tee esim tunneille keskiarvolasketaa ja säädä erikseen sille rankingia (max 24).

Haluaisin alkaa vähitelleen siirtämään osaa toiminnoista varttipuolelle, niin että osa tulee kuitenkin pysyvästi nojaamaan tuntien keskiarvoon, kuten nytkin. Mieluusti niin että seuraavat eivät hajoa päivityksessä vaan toimisivat "as is" antaen vieläkin tunnin keskiarvoa ja varteille tulisi uusilla nimillä sensorit:

sensor.shf_electricity_price_now
sensor.shf_average_price_today
sensor.shf_rank_now

Onko ajatus ihan mahdoton?
 

kenzy

Jäsen
On tullut käytettyä tätä SHF tosi monessa ja nyt ehkä vähän tyhmä kysymys, kun mietin pientä automaatiota keskelle päivää.
Toimiiko start ja stop aikana myös ”tomorrow”?
Muissa on ollut ehtona aina now tai today.
Stop-muuttujalle voi määrittää esim näin kun oon itse tehnyt:

{% set now_time = now() %}
{% set lahtoaika_str = states('input_datetime.lahtoaika_kotilataus') %}
{% set lahtoaika = as_datetime(now_time.date() ~ ' ' ~ lahtoaika_str) %}
{% if as_timestamp(now_time) > as_timestamp(lahtoaika) %}
{% set lahtoaika = lahtoaika + timedelta(days=1) %}
{% endif %}
{{ lahtoaika }}

Mulla on määritettynä input_datetime.lahtoaika_kotilataus- helperiin vain kellonaika, jolloin auton lataus täytyy olla valmiina ja tuo hakee tämän ajankohdan ja seuraavan tuohon helperiin määritetyn kellonajan väliseltä ajalta halvimmat tunnit. Tuo siis palauttaa esimerkiksi tämän vuorokauden klo 7 siihen saakka, kun nykyinen kellonaika on vähemmän kuin klo 7 saman vuorokauden aikana ja huomisen klo 7 sen jälkeen, kun nykyinen aika on ohittanut klo 7.
 

kenzy

Jäsen
Mulla on yli kymmneniätuhansia rivejä YAMlia nojaamassa tuohon vanhaan 1h välein olevaan SHF:ään ja samalle 24 portaiseen rankkaukseen. Kiva että muutoksessa se jatkoi toimintaansa ilman käpistelyä.

Jos nyt päivitän uuteen versioon, niin käsittääkseni siinä suoraan on vain ja ainoastaan tuettu varttihinnoittelu (ja ranking muuttuu 24 -> 96), jos en käsin tee esim tunneille keskiarvolasketaa ja säädä erikseen sille rankingia (max 24).

Haluaisin alkaa vähitelleen siirtämään osaa toiminnoista varttipuolelle, niin että osa tulee kuitenkin pysyvästi nojaamaan tuntien keskiarvoon, kuten nytkin. Mieluusti niin että seuraavat eivät hajoa päivityksessä vaan toimisivat "as is" antaen vieläkin tunnin keskiarvoa ja varteille tulisi uusilla nimillä sensorit:

sensor.shf_electricity_price_now
sensor.shf_average_price_today
sensor.shf_rank_now

Onko ajatus ihan mahdoton?
Itselläni on shf_electricity_price_now- sensorin koodin perässä tällainen rimpsu:

Koodi:
          current_30min_avg: >
            {% set now_ts = now() | as_timestamp %}
            {% set data_30 = state_attr("sensor.shf_data", "data") | selectattr("Timestamp", "ge", now_ts) | selectattr("Timestamp", "lt", now_ts + 30*60) | list %}
            {% if data_30 | length > 0 %}
              {{ (data_30 | map(attribute="TotalPrice") | map("float") | sum / data_30 | length) | round(5) }}
            {% else %}
              0
            {% endif %}
          current_60min_avg: >
            {% set now_ts = now() | as_timestamp %}
            {% set data_60 = state_attr("sensor.shf_data", "data") | selectattr("Timestamp", "ge", now_ts) | selectattr("Timestamp", "lt", now_ts + 60*60) | list %}
            {% if data_60 | length > 0 %}
              {{ (data_60 | map(attribute="TotalPrice") | map("float") | sum / data_60 | length) | round(5) }}
            {% else %}
              0
            {% endif %}
          current_120min_avg: >
            {% set now_ts = now() | as_timestamp %}
            {% set data_120 = state_attr("sensor.shf_data", "data") | selectattr("Timestamp", "ge", now_ts) | selectattr("Timestamp", "lt", now_ts + 60*120) | list %}
            {% if data_120 | length > 0 %}
              {{ (data_120 | map(attribute="TotalPrice") | map("float") | sum / data_120 | length) | round(5) }}
            {% else %}
              0
            {% endif %}
          current_180min_avg: >
            {% set now_ts = now() | as_timestamp %}
            {% set data_180 = state_attr("sensor.shf_data", "data") | selectattr("Timestamp", "ge", now_ts) | selectattr("Timestamp", "lt", now_ts + 60*180) | list %}
            {% if data_180 | length > 0 %}
              {{ (data_180 | map(attribute="TotalPrice") | map("float") | sum / data_180 | length) | round(5) }}
            {% else %}
              0
            {% endif %}

Jolla saan current_30min_avg, current_60, current_120 ja current_180 muuttujat shf_electricity_price_now- sensoriin. Näitä voi kutsua tyyliin: state_attr('sensor.shf_electricity_price_now', 'current_60') ja edelleen tämänhetkinen varttihinta löytyy states('sensor.shf_electricity_price_now')- rimpsulla. Ei tarvi siis useita sensoreita keskiarvoja varten, vaan voit käyttää samaa sensoria ja siihen liittyviä muuttujia.
 

Jamo70

Aktiivinen jäsen
Tänään tein sellaisen huomion, että tämä automaatio ajoittaa virheellisesti aloitusajaksi klo 00 ja näin ollen haluttu 22-07 välinen aika ei toteudu. Kuinka tämä olis järkevintä korjata niin, ettei automaatio mene yli asetetun yösähköajan 22-07?

YAML:
alias: Lämmitys yösähkö
description: >-
  Hakee halvimmat 8h välillä 22-07 ja tekee Lämpökäyrän siirron noston 3+0 =>
  3+2. Palauttaa 8h jälkeen takaisin Lämpökäyrän 3+0.
use_blueprint:
  path: T3m3z/cheapest-period.yaml
  input:
    hours: 8
    start: "{{ today_at('22:00') }}"
    stop: "{{ today_at('22:00') + timedelta(hours=9) }}"
    trigger_type: Time Trigger
    trigger_time: "15:10:00"
    entity: sun.sun
    helper: input_datetime.shf_halvimmat_8h_lammitys
    action_on:
      - device_id: xxxxxx
        domain: number
        entity_id: xxxxx
        type: set_value
        value: 2
    action_off:
      - device_id: xxxxx
        domain: number
        entity_id: xxxxx
        type: set_value
        value: 0
IMG_7704.png
 

kenzy

Jäsen
Tänään tein sellaisen huomion, että tämä automaatio ajoittaa virheellisesti aloitusajaksi klo 00 ja näin ollen haluttu 22-07 välinen aika ei toteudu. Kuinka tämä olis järkevintä korjata niin, ettei automaatio mene yli asetetun yösähköajan 22-07?

YAML:
alias: Lämmitys yösähkö
description: >-
  Hakee halvimmat 8h välillä 22-07 ja tekee Lämpökäyrän siirron noston 3+0 =>
  3+2. Palauttaa 8h jälkeen takaisin Lämpökäyrän 3+0.
use_blueprint:
  path: T3m3z/cheapest-period.yaml
  input:
    hours: 8
    start: "{{ today_at('22:00') }}"
    stop: "{{ today_at('22:00') + timedelta(hours=9) }}"
    trigger_type: Time Trigger
    trigger_time: "15:10:00"
    entity: sun.sun
    helper: input_datetime.shf_halvimmat_8h_lammitys
    action_on:
      - device_id: xxxxxx
        domain: number
        entity_id: xxxxx
        type: set_value
        value: 2
    action_off:
      - device_id: xxxxx
        domain: number
        entity_id: xxxxx
        type: set_value
        value: 0
katso liitettä 109474
Tuolla spot-price.yamlissa on määritetty tuo cheapest_hours- skripti


Koodi:
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 in 0.25h increments."
        example: "5"
        required: true
        selector:
          number:
            min: 0.25
            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 steps = min((hours/0.25) | int, data | length) %}
            {% for inval in data %}
              {% set output.tmp = data | selectattr("Timestamp", "ge", inval["Timestamp"]) | selectattr("Timestamp", "lt", inval["Timestamp"] + steps*900) | list%}
              {% if output.tmp | length >= steps %}
                {% set d = dict(inval, **{"PriceTmp": output.tmp | sum(attribute="TotalPrice") / output.tmp | length }) %}
                {% set output.value = output.value + [d] %}
              {% endif %}
            {%- endfor -%}
            {% set obj = (output.value | sort(attribute="PriceTmp"))[0] %}
            {{ { "start" : obj["Timestamp"], "stop": obj["Timestamp"] + steps*900, "avgPrice": obj["PriceTmp"] } }}
      - stop: Return variable
        response_variable: start_time
        enabled: true
    mode: parallel
    max: 100

Itse käytän sitä esim. auton latausajan määritykseen. Mulla on laskennallinen sensori latausaika_h, johon lasken tarvittavan latausajan perustuen auton akun varaustilaan, asetettuun latausrajaan ja laturin syöttötehoon, mutta tuon tilalla voi olla vaikka se cheapest_hours- sliderin arvo. Lisäksi mulla on input_datetime- sensori, johon asetan kellonajan, jolloin latauksen pitää olla viimeistään valmis ja haen halvimman ajanjakson tämän hetken ja tuon asetetun kellonajan väliltä ja palautan sen input_datetime.latauksen_aloitus- sensoriin. Tossa automaatiossa mulla on myös tuota avg price- skriptiä käytetty tuon lasketun latausajan keskihinnan tarkasteluun.


Koodi:
alias: Lataus halvimmilla tunneilla, määritys
description: ""
triggers:
  - trigger: state
    entity_id:
      - input_boolean.lataus_halvimmilla_tunneilla
  - trigger: time_pattern
    minutes: /15
conditions:
  - condition: state
    entity_id: sensor.garo_garo
    state: ALWAYS_OFF
  - condition: time
    after: "15:00:00"
actions:
  - action: script.cheapest_hours
    data:
      start: "{{ now() }}"
      stop: |-
        {% set now_time = now() %}
        {% set lahtoaika_str = states('input_datetime.lahtoaika_kotilataus') %}
        {% set lahtoaika = as_datetime(now_time.date() ~ ' ' ~ lahtoaika_str) %}
        {% if as_timestamp(now_time) > as_timestamp(lahtoaika) %}
          {% set lahtoaika = lahtoaika + timedelta(days=1) %}
        {% endif %}
        {{ lahtoaika }}
      hours: "{{ states('sensor.latausaika_h')|int(0) }}"
    response_variable: result
  - data:
      timestamp: "{{ result['start'] }}"
    action: input_datetime.set_datetime
    target:
      entity_id: input_datetime.latauksen_aloitus
  - action: input_datetime.set_datetime
    target:
      entity_id: input_datetime.latauksen_lopetus
    metadata: {}
    data:
      timestamp: >-
        {{ as_timestamp(states('input_datetime.latauksen_aloitus')) + (3600 *
        states('sensor.latausaika_h')|float(0)) }}
  - action: script.average_price
    data:
      start: "{{ states('input_datetime.latauksen_aloitus') }}"
      stop: "{{ states('input_datetime.latauksen_lopetus') }}"
    response_variable: result2
  - action: input_number.set_value
    metadata: {}
    data:
      value: "{{ result2.avgPrice | float * 100 }}"
    target:
      entity_id: input_number.latausajan_keskihinta
mode: single
 

Jamo70

Aktiivinen jäsen
Tuolla spot-price.yamlissa on määritetty tuo cheapest_hours- skripti


Koodi:
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 in 0.25h increments."
        example: "5"
        required: true
        selector:
          number:
            min: 0.25
            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 steps = min((hours/0.25) | int, data | length) %}
            {% for inval in data %}
              {% set output.tmp = data | selectattr("Timestamp", "ge", inval["Timestamp"]) | selectattr("Timestamp", "lt", inval["Timestamp"] + steps*900) | list%}
              {% if output.tmp | length >= steps %}
                {% set d = dict(inval, **{"PriceTmp": output.tmp | sum(attribute="TotalPrice") / output.tmp | length }) %}
                {% set output.value = output.value + [d] %}
              {% endif %}
            {%- endfor -%}
            {% set obj = (output.value | sort(attribute="PriceTmp"))[0] %}
            {{ { "start" : obj["Timestamp"], "stop": obj["Timestamp"] + steps*900, "avgPrice": obj["PriceTmp"] } }}
      - stop: Return variable
        response_variable: start_time
        enabled: true
    mode: parallel
    max: 100

Itse käytän sitä esim. auton latausajan määritykseen. Mulla on laskennallinen sensori latausaika_h, johon lasken tarvittavan latausajan perustuen auton akun varaustilaan, asetettuun latausrajaan ja laturin syöttötehoon, mutta tuon tilalla voi olla vaikka se cheapest_hours- sliderin arvo. Lisäksi mulla on input_datetime- sensori, johon asetan kellonajan, jolloin latauksen pitää olla viimeistään valmis ja haen halvimman ajanjakson tämän hetken ja tuon asetetun kellonajan väliltä ja palautan sen input_datetime.latauksen_aloitus- sensoriin. Tossa automaatiossa mulla on myös tuota avg price- skriptiä käytetty tuon lasketun latausajan keskihinnan tarkasteluun.


Koodi:
alias: Lataus halvimmilla tunneilla, määritys
description: ""
triggers:
  - trigger: state
    entity_id:
      - input_boolean.lataus_halvimmilla_tunneilla
  - trigger: time_pattern
    minutes: /15
conditions:
  - condition: state
    entity_id: sensor.garo_garo
    state: ALWAYS_OFF
  - condition: time
    after: "15:00:00"
actions:
  - action: script.cheapest_hours
    data:
      start: "{{ now() }}"
      stop: |-
        {% set now_time = now() %}
        {% set lahtoaika_str = states('input_datetime.lahtoaika_kotilataus') %}
        {% set lahtoaika = as_datetime(now_time.date() ~ ' ' ~ lahtoaika_str) %}
        {% if as_timestamp(now_time) > as_timestamp(lahtoaika) %}
          {% set lahtoaika = lahtoaika + timedelta(days=1) %}
        {% endif %}
        {{ lahtoaika }}
      hours: "{{ states('sensor.latausaika_h')|int(0) }}"
    response_variable: result
  - data:
      timestamp: "{{ result['start'] }}"
    action: input_datetime.set_datetime
    target:
      entity_id: input_datetime.latauksen_aloitus
  - action: input_datetime.set_datetime
    target:
      entity_id: input_datetime.latauksen_lopetus
    metadata: {}
    data:
      timestamp: >-
        {{ as_timestamp(states('input_datetime.latauksen_aloitus')) + (3600 *
        states('sensor.latausaika_h')|float(0)) }}
  - action: script.average_price
    data:
      start: "{{ states('input_datetime.latauksen_aloitus') }}"
      stop: "{{ states('input_datetime.latauksen_lopetus') }}"
    response_variable: result2
  - action: input_number.set_value
    metadata: {}
    data:
      value: "{{ result2.avgPrice | float * 100 }}"
    target:
      entity_id: input_number.latausajan_keskihinta
mode: single

Niin mutta miten ja miksi tuo mun automaatio meni sekaisin vuorokauden vaihtuessa? Sille on annettu aikaväli hakea klo 22 ja siitä eteenpäin 9 tuntia väliseltä ajalta. Nyt tuo otti yli sallitun ja määritellyn.

Kyllä se aikaisemmin on osannut aloittaa ja ottaa ne halvimmat tunnit kuten pitääkin klo 22-07 väliltä.
 

Pretor

Aktiivinen jäsen
Niin mutta miten ja miksi tuo mun automaatio meni sekaisin vuorokauden vaihtuessa? Sille on annettu aikaväli hakea klo 22 ja siitä eteenpäin 9 tuntia väliseltä ajalta. Nyt tuo otti yli sallitun ja määritellyn.

Kyllä se aikaisemmin on osannut aloittaa ja ottaa ne halvimmat tunnit kuten pitääkin klo 22-07 väliltä.
Koska ne halvimmat kahdeksan tuntia on 00-07?
Yksi tunti kyseisellä aikavälillä tulee kaksi kertaa tänä yönä.
 

Mikki

Hyperaktiivi
Niin hullua kuin se onkin, niin 100 varttia tänään onkin. Kyllä kellojen kääntely on hulluakin hullumpaa hommaa. Aika käsittämätöntä on, ettei tuosta ole vielä luovuttu.
 
Back
Ylös Bottom