Rynkowe ceny energii elektrycznej

Cześć,

Od lipca 2024 energia sprzedawana do sieci ma być rozliczana na bazie cen godzinowych z rynku dnia następnego (Rynkowa cena energii elektrycznej (RCE) - PSE)

Zapewne część z was (podobnie jak ja) będzie chciało zoptymalizować sprzedawaną / wykorzystywaną energię więc podzielę się swoją templatką do codziennego pobierania stawek w danych godzinach.

Jako że to moja pierwsza templatka tworzona od zera to chętnie przyjmę propozycje usprawnień.

  1. Zaczynamy od edycji configuration.yaml. Dodajemy:
homeassistant:
  allowlist_external_dirs:
    - "/config/downloads"
    - "/config/downloads/energy_prices"

downloader:
  download_dir: downloads

# jeżeli nie mieliśmy do tej pory to także:
automation: !include automations.yaml
script: !include scripts.yaml
command_line: !include command_line.yaml
template: !include templates.yaml
  1. Dalej tworzymy skrypt (scripts.yaml), który zapisuje plik CSV pobrany z PSE do folderu config/download/energy_prices z nazwą taką jak w PSE. Wykorzystuje w tym celu standardową integrację Downloader.
download_pse_market_energy_prices:
  alias: Download PSE Market Energy Prices
  sequence:
    - data:
        filename: "{{ (now() + timedelta(days=1)).timestamp() | timestamp_custom('%Y%m%d') }}.csv"
        overwrite: true
        subdir: energy_prices
        url: "https://www.pse.pl/getcsv/-/export/csv/PL_CENY_RYN_EN/data/{{ (now() + timedelta(days=1)).timestamp() | timestamp_custom('%Y%m%d') }}"
      service: downloader.download_file
  icon: mdi:cash
  1. Następnie tworzymy automatyzację (automations.yaml) która raz dziennie odpala powyższy skrypt:
- id: 'xxxxxxxxxxxxxxxx'
  alias: Daily PSE Market Energy Price Download
  description: ''
  trigger:
  - platform: time
    at: 23:32:23
  action:
  - service: script.download_pse_market_energy_prices
  mode: single
  1. Na koniec command_line sensor (command_line.yaml) który przy każdej zmianie godziny pobiera nam ze ściągniętego pliku CSV linijkę odpowiadającą aktualnej godzinie:
sensor:
  name: pse_market_energy_price_current_hour
  unique_id: pse_market_energy_price_current_hour
  command: "cat -n /config/downloads/energy_prices/{{ now().timestamp() | timestamp_custom('%Y%m%d') }}.csv | sed '{{now().strftime('%H') | int + 2}}!d'"
  value_template: '{{value.split(";")[2] | regex_replace(find=",", replace=".") | float(0) }}'
  unit_of_measurement: "PLN/MWh"

Otrzymujemy encję, która podaje nam aktualną cenę w PLN/MWh:

Możemy wykorzystać ją jako warunek do automatyzacji lub po prostu podpiąć do dashboardu energii i zliczać całkowitą cenę oddanej energii (na screenshocie niska, bo dziś pochmurny dzień i magazyn dopiero się w pełni naładował):
image

Docelowo można pomyśleć o modyfikacji, żeby plik był pobierany dzień wcześniej wieczorem (dane są publikowane popołudniu), ale obecnie to jest poniżej minuty opóźnienia w odświeżaniu danych w dodatku w środku nocy.

3 polubienia

Widziałem też coś takiego, można dodać repo w HACS

Rewelacyjny skrypt!

Osobiscie dokonalbym dwoch drobnych zmian - w sensorze zmienilbym

state: "{{ now().timestamp() | timestamp_custom('%Y%m%d') }}"

na

state: "{{ (now() + timedelta(days=1)).timestamp() | timestamp_custom('%Y%m%d') }}"

to daje jutrzejsza date i wtedy odpalalbym automatyzacje o jakiejs dziwnej godzinie, np 23:07 poniewaz odpalania skryptow o polnocy jest kiepskie, masa automatyki na serwerach odpala sie wtedy i masa ludzi wtedy bedzie powbierac te dane wiec serwer sie moze nie wyrobic, a tak trafiamy na spokojniejszy moment dla serwera i nie tracimy minuty rozliczen :slight_smile:

2 polubienia

czyli po każdym przeładowaniu HA sensor będzie w stanie unavailable do czasu aż znów o pełnej godzinie pobierze wartość z pliku i będzie miał state? Zapewne wtedy panel energii się odezwie (jeśli zostanie użyty do określenia ceny) , że encja jest nienumeryczna.

Edit. Sprawdziłem z ciekawości bo temat mnie bardzo ciekawi i sam szukam jakiegoś rozwiązania. A więc rzeczywiście po restarcie HA encja jest unavailable , ponieważ nie ustawiono w konfiguracji sensora scan_interval więc powinien domyślnie wykonać update po 60s ale tego nie zrobił, dalej pozostawał unavailable, nawet zmiana godziny go nie wybudziła, dopiero wykonanie service: command_line.reload obudziło go to życia i dalej aktualizował się zgodnie. @kubaa czy u siebie też to obserwujesz ?

Zaktualizowałem dzisiaj HA do najnowszej wersji i sensor był rzeczywiście unavailable, log wyrzucił błąd:
ValueError: Template error: float got invalid input '' when rendering template '{{value.split(";")[2] | regex_replace(find=",", replace=".") | float }}' but no default was specified

Błąd niby sugerowałby niewłaściwą zawartość pliku, więc może wynika to z chwilowego braku dostępu do pliku podczas uruchomienia?
Po ponownym przeładowaniu tak jak u Ciebie wszystko zadziałało.

Tak to wygląda, ale zastanawia mnie dlaczego sensor nie wstaje “sam” po czasie scan_interval tylko trzeba wykonać command_line.reload ? Nie mam większego doświadczenia z tą integracją, mam raptem kilka czujników temperatury mojego della i one nie potrzebują “przeładowania” same wstają.


potem działa poprawnie.

Udało mi się to rozwiązać. Otóż okazuje się, że występuje jakaś dziwna kolejność ładowania sensorów i użyty sensor daty (i nazwy pliku) ładował się sporo później niż próbował załadować się sensor z ceną który z niego korzystał.

Tak więc pozbyłem się encji z datą i użyłem templatki w skrypcie oraz encji ceny. Szczególnie po wdrożeniu zmiany:

Dzięki, miałem to w planach ale skoro wkleiłeś kod to użyłem od razu u siebie.

Zaktualizowałem pierwszy post o obie zmiany.

3 polubienia

hej, pogrzebalem jeszcze troche w kodzie i zrobilem dwie zmiany ktre sie moga przydac wszystkim

pierwsza:

  value_template: '{{value.split(";")[2] | regex_replace(find=",", replace=".") | float(0) }}'

dopisanie po float “(0)” daje nam zabezpiecznie jak np plik sie zle wczyta albo watosc sie nie bierze, zamiast bledu dostaniemy “0”

u siebie tak ustawilem i dzieki temu znalazlem blad w skrypcie

 command: "cat -n /config/downloads/energy_prices/{{ now().timestamp() | timestamp_custom('%Y%m%d') }}.csv | sed '{{now().strftime('%H') | int + 1}}!d'"

w tym poleceniu polecenie sed odczytuje numer linii dodajac do biezacej godziny 1, ale plik CSV ma naglowek, wiec musimy dodac nie 1 a 2 poniewaz plik tekstowy zaczyna sie od linii 1 a nie 0 ; )

inaczej mowiac majac godzine 00:00:00 tostaniemy “00” castowane na int’a + 1 czyli da nam linie numer jeden a w niej jest naglowek pliku csv z opisem kolumn, jak zrobimy + 2 wtedy odczyt sie zgadza.

zatem uprzejmie prosze abys @kubaa skorygowal pierwszy post zeby sobie ktos wersji z bledem nie wkleil w swoja konfiguracje.

poprawna wersja to:

 command: "cat -n /config/downloads/energy_prices/{{ now().timestamp() | timestamp_custom('%Y%m%d') }}.csv | sed '{{now().strftime('%H') | int + 2}}!d'"

swoja droga te pliki z odczytami sie zbieraja w tym katalogu downloads/energy_prices, jak ktos chce to moge podrzucic sposob automatycznego kasowania starych plikow

1 polubienie

hm … u mnie z “1” wydaje się być ok ? według Ciebie powinien mi wskazywac cenę z godziny 17 … ?


edit. właśnie kolejna zmiana i jest ok …

wg mnie kod jest poprawny z “1”.

Można jak proponujesz ale jak nie chcesz aby sie zbierały to chyba wystarczy zmienić atrybut … z true na …

overwrite: false

zaczne od konca, overwrite nadpisuje plik jesli ma te sama nazwe, tu kazdy ma inna wiec i tak sie beda zbierac, zeby overwrite mialo sens bys musial ustalic jedna nazwe pliku np ceny.csv i wtedy przy overwrite: yes bedzie go codziennie nadpisywac :wink:

A co do godzin to juz tlumacze, ponizej mamy przykladowy plik csv

obraz

jak mamy polecenie now().strftime('%H') | int to o polnocy danego dnia to nam zwroci wartosc “0” - jak dodamy 1 do wychodzi 1, czyli odczyta pierwsza linie z pliku, a pierwsza linia to naglowek “Data;Godzina;RCE”, zwroc uwage ze w pliku godziny sa od 1 do 24 a nie od 0 do 23, dlatego dla godziny 00:00 musisz odczytac wartosc z linii 2 dla godzyny “1”, a dla godziny 19 jak z Twojego przykladu powyzej musisz odczytac wartosc z linii 21 dla godziny “20”. wszystko jest przesuniete o jeden :wink:

Wiem ze to troche pokretne i mam nadzieje ze uda ci sie zrozumiec moje wytlumaczenie. Chwile nad tym siedzialem i analizowalem, zdecydowanie tak musi byc zeby sie zgadzalo, nie mniej sprawdz sobie sam dla pewnosci. mysle ze dojdziesz do tej samej konkluzji.

Dzięki, rzeczywiście trzeba dodać 2 a nie 1, bo indeksowanie jest od 1 a nie od 0.
Zaktualizowałem skrypty w pierwszym poście.

1 polubienie

Staram się jak mogę, ale chyba w tej kwestii to “beton”.

o 1:05 zwróci nam 1 co po dodaniu 2 da nam 3 wiersz a w nim …

Data;Godzina;RCE
20240412;1;347,08
20240412;2;342,44

cena dla energii pobieranej w godzinach 2-3 ? a my tymnczasem jesteśmy w godzinie 1+ :thinking:
… no chyba, że pobór od 00 - 01 to cena 1 a 01-02 to cena 2 …?

dokladnie o to chodzi

od 00 - 01 to cena 1 (z linii 2 w pliku)
od 01 - 02 to cena 2 (z linii 3 w pliku)

i tak dalej az do

od 23 - 00 to cena 24 (z linii 25 w pliku)

na tym polega ten “zakrecony” problem - tez chwile nad tym siedzialem
i dlatego tam musi byc to “+2” a nie “+1”

1 polubienie

Super sprawa, dzięki!

szybkie zmiany w HA, w najnowszej odsłonie downloader wylatuje z configuration.yaml do własnej integracji:
image

Nowa zmiana dla tych co śledzą wątek - w związku z tym, że zdarzają się ceny ujemne trzeba wprowadzić modyfikację.
Z tego co wiem dla osób fizycznych przy cenie ujemnej cena rzeczywista będzie wynosić zero.

Sensor wydaje mi się, że można zmienić w ten sposób:

sensor:
  name: pse_market_energy_price_current_hour
  unique_id: pse_market_energy_price_current_hour
  command: "cat -n /config/downloads/energy_prices/{{ now().timestamp() | timestamp_custom('%Y%m%d') }}.csv | sed '{{now().strftime('%H') | int + 2}}!d'"
  value_template: '{{[value.split(";")[2] | regex_replace(find=",", replace=".") | float(0) , 0] | max}}'
  unit_of_measurement: "PLN/MWh"

Zweryfikowałem ręcznie zmieniając wartość w pobranym pliku CSV i wskazuje poprawnie 0 przy ujemnych wartościach.

2 polubienia

Wygląda dobrze. Wykorzystując max zwraca z dwóch wartości (pliku csv i 0) większą wartość więc w przypadku ujemnej zwróci 0. Dobra robota, dziękuję.

Świetna integracja.

Mam jednak pytanie / prośbę o pomoc/wskazówki. Jak zrobić z tego coś na styl forecast, tj. ceny pojawić się powinny dla całego dnia od razu a nie aktualizowane w trakcie trwania dnia.

Chciałem sam to zrobić, ale, że jestem cienki z HAS, to piszę o tym tutaj :slight_smile:

Wykorzystaj do tego. GitHub - JaccoR/hass-entso-e: Integration for Home Assistant to fetch day ahead energy prices from European countries via ENTSO-e Transparency Platform. Następnie przekonwertuj EURO na PLN. I masz wszystko na dziś i na jutro codziennie po 14.
Możesz też skorzystać z Electricity price right now - Home Assistant REST integration.

1 polubienie

Może ktoś podać jakieś realne zastosowanie informacji o cenach przy automatyzacjach? U siebie nie widzę sensownego zastosowania, które realnie przełożyłoby się na zauważalne oszczędności.

Mam fotowoltaikę na starych zasadach, więc mnie to nie dotyczy, ale wydaje mi się, że oczywiste zastosowanie jest takie, żeby urządzenia o dużej mocy pracowały wtedy, gdy panele produkują energię, a cena jest najniższa. Najprostsze zastosowanie to grzanie wody użytkowej (jeśli mamy zbiornik oczywiście). Stosunkowo proste jest też ładowanie auta elektrycznego, ale to już zależy od tego, jak kto używa. Podejrzewam, że dobrze może się też sprawdzić sterowanie klimatyzacją, no bo w końcu najbardziej jej potrzebujemy, gdy świeci słońce - ale nie mam, więc nie wiem jak to jest w praktyce. Inne urządzenia mogą być trochę bardziej skomplikowane, zmywarka czy pralka muszą być załadowane i w ogóle trzeba je móc jakoś zdalnie włączyć.

Nie wiem, czy to obecnie ma jeszcze sens, ale kiedyś w grę wchodziło jeszcze kopanie bitcoinów itd. Przy zerowych lub ujemnych cenach zawsze to coś.

A spodziewam się, że w godzinach największej produkcji te ceny będą bardzo często bardzo niskie.

Poza tym wszystkim jest jeszcze kwestia magazynu energii, jeśli ktoś ma, to dane o cenach energii mogą być bardzo istotne. Typowo zwymiarowana instalacja (czyli de facto przewymiarowana) produkuje w lecie w ciągu doby o wiele więcej niż się wykorzystuje przez całą dobę, więc można zoptymalizować baterie ładując je tylko wtedy, gdy cena jest najniższa.

3 polubienia