Rynkowe ceny energii elektrycznej

Na takie objawy najlepiej zacząć od wyczyszczenia pamięci podręcznej przeglądarki.

To raczej nie to. W innych “świeżych” przeglądarkach jest ten sam efekt

U mnie wygląda tak:

image

type: custom:apexcharts-card
graph_span: 24h
span:
  start: day
update_interval: 15min
experimental:
  color_threshold: true
series:
  - entity: sensor.rce_prices_today
    attribute: value
    data_generator: |
      const startOfDay = new Date();
      startOfDay.setHours(0, 0, 0, 0);
      return entity.attributes.value.map(item => {
        const timeRange = item.udtczas_oreb.split(" - ")[0];
        const [hours, minutes] = timeRange.split(":");
        const timestamp = new Date(startOfDay);
        timestamp.setHours(hours, minutes);
        return [timestamp.getTime(), item.rce_pln];
      });
    type: line
    name: Cena energii (jutro)
    curve: smooth
    stroke_width: 4
    color_threshold:
      - value: 0
        color: red
      - value: 300
        color: orange
      - value: 500
        color: yellow
      - value: 700
        color: green
header:
  show: true
  title: Ceny energii (PLN)
  show_states: false
  colorize_states: true
now:
  show: true
  label: Teraz
  color: red

No coś u mnie jest nie tak z tym widokiem. Zmieniłem stroke_with: 4 ale bez zmian. Jak mam wykres w osobnej zakłace i jest jedynym objektem to jest ok, ale z innymi kafelkami to sie psuje i ucina.

Inny temat to jak patrzę na taryfy dynamiczne od PGE i ceny to one sie sporo różnią od tych danych i wykresów powyżej. Chodzi o to że oni biorą ceny z TGE, nie z PSE.
TGE udostępnia w ogóle api z tymi cenami?

https://www.tge.pl/energia-elektryczna-rdb
i cena wg PGE:
https://www.gkpge.pl/dla-domu/oferta/dynamiczna-energia-z-pge

jak powinienem przerobić

resource_template: "https://api.raporty.pse.pl/api/rce-pln?$select=rce_pln,udtczas_oreb&$filter=doba eq '{{ now().strftime('%Y-%m-%d') }}'"

tak aby czytać ten plik:
https://energy-instrat-api.azurewebsites.net/api/prices/energy_price_rdn_hourly?date_from=10-10-2024T00:00:00Z&date_to=10-10-2024T23:59:59Z

oczywiście interesuje nas fixing_i

Edit moderator: nie dodawaj posta pod swoim postem tylko edytuj treść ostatniego posta.

Kwestia widoku wydaje się wyjaśniona.

Taryfy dynamiczne często mieszane są przez niedouczonych dziennikarzy z odkupem energii po cenach dynamicznych, a to dwie różne sprawy oparte na innych cenach.
Odkup który wszedł dla wszystkich którzy uruchomili PV po 1 lipca oparty jest na cenach RCE (rynkowa cena energii). Ceny te publikowane są od 14 czerwca w API PSE.
Taryfy dynamiczne opierają się na notowaniach TGE, rynku dnia następnego, fixing I. No i tu jest granda bo nie ma do nich publicznego dostępu poprzez API jak w PSE, a TGE każe sobie za te dane słono płacić.

Na szczęście dane te publikuje w postaci API Fundacja Instrat.

Opisałem to dokłądnie dla wszystkich zagubionych w tych zawiłościach.

Co do Twojego pytania, pracuję nad tym w wolnej chwili żeby te ceny wyłuskać z API Instrat, ale na razie coś mi nie zadziałało. Opublikuję rozwiązanie jak tylko się z nim uporam.

Trzeba jeszcze pamiętać, że do “gołej” ceny z notowania każdy operator dolicza jeszcze marże i dla PGE jest to 0,0999 zł/kWh. Czyli tamplate sensor powinien pobierać aktualną cenę i doliczać do niej ten wskaźnik. Inną sprawą jest miesięczna opłata stała dla PGE 49,90.
Można poczytać o tym tu, choć przesłanie artykułu jest bzdurne i oparte o złe założenia:
https://globenergia.pl/taryfy-dynamicznie-zupelnie-nieoplacalne-u-ktorego-sprzedawcy-najbardziej/

Ja pracuję obecnie nad sterowaniem falownikiem Deye z magazynem tak żeby oddawać energię w najwyższych cenach (np. oddawać rano zamiast ładować magazyn) i kupować energię do ładowania magazynu kiedy nie ma słońca po najniższych cenach dynamicznych. Brzmi jak plan ale życie zweryfikuje :slight_smile:

1 polubienie

To znaczy, że albo w tym widoku albo w innym masz jakieś błędy w konfiguracji.

:thinking: a nie po cenach rynkowych RCE?

Nie można kupować energii po cenach RCE. Ja obecnie oddaje po cenach RCE, a kupuje zgodnie z taryfą G11. Rozważam zmianę na G12W i ładowanie magazynu w tańszej strefie albo zmianę na taryfę dynamiczną i ładowanie w dołkach cenowych.

@mstepuch dzieki za wyjaśnienie :slight_smile:

Masz do analizy dużo zmiennych w obu wariantach aby “zarobić na prądzie” uwzględniając dodatkowo możliwości pozyskiwania prądu z PV (dużo zmiennych, na które nie masz wpływu, możesz tylko szacować lub opierać sie na danym statystycznych). Zakładam, że na początek nie uwzględniacz wcale kosztów instalacji PV, magazynów energii itd tylko czy posiadając już takie rozwiązanie, chcesz je maksymalnie i efektywnie wykorzystać. Trzymam kciuki za analizę :crossed_fingers: a potem efekt końcowy.

Dokładnie tak. Skoro mam już instalację, zbudowałem ją sam jak najtaniej ale na porządnym sprzęcie to staram się z niej jak najwięcej wycisnąć.
Moja analiza przed decyzją zakupu instalacji zakładała, że jeśli moja samowystarczalność roczna będzie wynosiła 70% to instalacja zwróci się do 5 lat, a jeśli otrzymam dotację to wcześniej. Inaczej to wszystko nie było by nic warte.

Na prądzie zarobić w net-billingu się nie da, można tylko zminimalizować koszty.
Już po kilku miesiącach widzę że nadwyżki finansowe ze sprzedaży latem nie pokryją mi zakupu zimą więc drążę dalej :slight_smile:

Ten skrypt w pliku sensors.yaml mi zadziałał:

# Pobierania aktualnej ceny RDE 
- platform: rest
  name: Energy Prices Fixing I
  unique_id: 62bb581f-a4db-4316-88eb-7f6f78b9c753
  resource_template: >
    https://energy-instrat-api.azurewebsites.net/api/prices/energy_price_rdn_hourly?date_from={{ now().strftime('%d-%m-%YT00:00:00Z') }}&date_to={{ now().strftime('%d-%m-%YT23:59:59Z') }}
  method: GET
  scan_interval: 3600
  value_template: >
      {% set now = now().strftime('%Y-%m-%dT%H:00:00Z') %}
      {% for item in value_json if item.date == now %}
        {{ item.fixing_i.price }}
      {% endfor %}
  unit_of_measurement: "PLN/MWh"

pobiera pojedyńcza wartość. Nie umiem jeszcze z tego stworzyć wykresu w apex charts. Ktoś pomoże?

Powyższa cena odwierciedla ceny dynamiczne dla PGE wg tego co sugerują na:
https://www.gkpge.pl/dla-domu/oferta/dynamiczna-energia-z-pge

Kilka postów wyżej masz kod karty apex.

witam wszystkich i oddaje troche wiedzy którą od Was wziąłem :slight_smile:
home assistanta włączyłem pod koniec sierpnia i we wrześniu trafiłem tu szukając cen TGE RDN. Dowiedziałem sie co i jak ugryźć i dalej poszło. Michał, walczyłem z json z energy instrat z tydzień żeby format całości pasował do RCE z PSE. Po tygodniu doczytałem sie ze REST nie “obsluguje” /nie wiem jak to określić/ jsona bez atrybutu, poddałem się i na szybko zrobiłem coś takiego, z automatu pobierane co 1h. Niestety wykresu przyszłości w apexcharts z tego nie da sie zrobić, wiec kombinowałem dalej. Tu możecie zobaczyć czym różnią się PSE i Instrat https://jsonpathfinder.com/

 rest:
   - resource_template: "https://energy-instrat-api.azurewebsites.net/api/prices/energy_price_rdn_hourly?{{ now().strftime('date_from=%d-%m-%YT%H:00:00Z')}}{{now().strftime('&date_to=%d-%m-%YT%H:59:59Z') }}"
     method: GET
     headers:
       accept: "application/json"
     sensor:
     - name: TGE Prices Today
       unique_id: 20240901000003
       unit_of_measurement: "PLN/MWh"
       value_template: "{{ value_json[0].fixing_i.price }}"

Co do Energy Instrat to miejcie świadomość że potrafi nie działać. Najwieksza przerwa jaką ostatnio widziałem to był weekend powodzi. Nie działało od niedzieli do wtorku, ale w zapasie miałem RCE :slight_smile: . Teraz robie pobieranie danych bezpośrednio ze strony TGE i konwert na json w tym samym formacie jak z instrat. Na razie działa jednodniowo i jak skończe to wrzuce tutaj. HA bedzie mógł sam się przełączyć. Dopiero kilka dni temu poznałem potężne narzędzie ‘jq’ i jeszcze nie zdążyłem przemyśleć co i jak.
Na koniec przydługiego wstepu chciałbym Was prosić o dane jakie macie na rachunkach z taurona i energi. Encje poniżej obliczają ceny energii z dodatkowymi opłatami z PGE a nie wiem jakie mają tauron i energa. Tylko akcyza i opł. kogeneracyjna bedzia taka sama. Myślę o przejściu do energi z powodu opłaty handlowej, ale najpierw chciałbym zrobić symulację i pewnie nie tylko ja. To co wiem: opłata handlowa energa 0, pge 49,90 (netto), wsp kosztowy energa 121,9 PLN/MWh, pge 81,20 PLN/MWh (brutto) (energa rozlicza ceny ujemne)
Poniżej wszystko zadziała na zasadzie kopiuj/wklej, wiec do sedna:
Energy Instrat publikuje dane po 16, u mnie download jest o 17 na wszelki wypadek. Pobieramy downloaderem plik json (automations.yaml)

- id: '2024101100001'
  alias: TGE EnergyInstrat json
  description: ''
  triggers:
  - hours: '17'
    minutes: '0'
    seconds: '10'
    trigger: time_pattern
  actions:
  - action: downloader.download_file
    data:
      overwrite: true
      url: https://energy-instrat-api.azurewebsites.net/api/prices/energy_price_rdn_hourly?{{(now()
        - timedelta(days=6)).timestamp() | timestamp_custom('&date_from=%d-%m-%YT00:00:00Z')}}{{(now()
        + timedelta(days=1)).timestamp() | timestamp_custom('&date_to=%d-%m-%YT23:59:59Z')}}
      subdir: energy_prices
      filename: energy_instrat.json
  - delay:
      hours: 0
      minutes: 0
      seconds: 5
      milliseconds: 0
    enabled: true
  - action: homeassistant.update_entity
    data:
      entity_id:
      - sensor.tge_prices_today
      - sensor.current_tge_price
    enabled: true
  mode: single

dalej w integracji command_line polecenie jq kasuje fixing_ii, dalej odczytuje tylko dane daty i ceny fixing_i a na koncu dodaje brakujacy atrybut ‘tge_rdn’, potem już klasyka i template HA (configuration.yaml)

command_line:
  - sensor:
      unique_id: 20241010000001
      name: TGE Prices Today
      command: "jq 'del (..|objects|.fixing_ii, .volume) | (.[] | {date: (.date),price: (.fixing_i.price)})' /config/downloader/energy_prices/energy_instrat.json | jq -sc '{\"tge_rdn\": .}'"
      value_template: "{{ value_json.value[0]['date']['price'] }}"
      unit_of_measurement: "PLN/MWh"
      json_attributes:
        - tge_rdn
      icon: mdi:cash-100
template:
  - sensor:
    - name: "Current TGE Price"
      unique_id: 20241001000010
      unit_of_measurement: "PLN/MWh"
      state: >
        {% set current_time = now().strftime('%Y-%m-%dT%H:00:00Z') %}
        {% set dates = state_attr('sensor.tge_prices_today', 'tge_rdn') %}
        {% for date in dates %}
          {% set start_time = date.date %}
          {% if start_time == current_time %}
            {{ date.price }}
          {% endif %}
        {% endfor %}
      icon: mdi:cash-100
  - sensor:
    - name: "Current PGE Price"
      unique_id: 20240912000002
      unit_of_measurement: "PLN/kWh"
      state: >
        {% set current_price = [ states('sensor.current_tge_price') | float(0), 0] | max %}
        {% set k      = 81.2  | float %}
        {% set akcyza = 5.0   | float %}
        {% set kogen  = 6.18  | float %}
        {% set jakosc = 31.4  | float %}
        {% set siec   = 350.0 | float %}
        {{(current_price + k + akcyza + kogen + jakosc + siec) | multiply(0.00123) | float(0)}}
      icon: mdi:cash

dodatki: (chwilowe ceny energii), przydatne do obserwacji cen i różnic na bieżąco

template:
  - sensor:
    - name: "PGE Static Price"
      unique_id: 20240912000003
      unit_of_measurement: "PLN/kWh"
      state: >
        {% set current_price = 500.0 | float %}
        {% set akcyza = 5.0   | float %}
        {% set kogen  = 6.18  | float %}
        {% set jakosc = 31.4  | float %}
        {% set siec   = 350.0 | float %}
        {{ (current_price + akcyza + kogen + jakosc + siec) | multiply(0.00123) | float(0) }}
      icon: mdi:cash
#------------------------------------------------------------------------------
  - sensor:
    - name: "PGE Dynamic Price Fixed"
      unique_id: 20240912000006
      unit_of_measurement: "PLN/kWh"
      state: >
        {% set total_kwh = (states('sensor.monthly_total_kwh') | float(0)) | multiply(0.001) | float(0) %}
        {% set current_price = [ states('sensor.current_tge_price') | float(0), 0] | max %}
        {% set k      = 81.2  | float %}
        {% set akcyza = 5.0   | float %}
        {% set kogen  = 6.18  | float %}
        {% set jakosc = 31.4  | float %}
        {% set siec   = 350.0 | float %}
        {% set stale  = ((9.99 + 0.75 + 0.33 + 40.58) | float / total_kwh) | float(0) %}
        {{ ( (current_price + k + akcyza + kogen + jakosc + siec + stale) | multiply(0.00123) | float(0) ) }}
      icon: mdi:cash
  - sensor:
    - name: "PGE Static Price Fixed"
      unique_id: 20240912000007
      unit_of_measurement: "PLN/kWh"
      state: >
        {% set total_kwh = (states('sensor.monthly_total_kwh') | float(0)) | multiply(0.001) | float(0) %}
        {% set current_price = 500.0 | float %}
        {% set akcyza = 5.0   | float %}
        {% set kogen  = 6.18  | float %}
        {% set jakosc = 31.4  | float %}
        {% set siec   = 350.0 | float %}
        {% set stale  = ((9.99 + 0.75 + 0.33 + 10.48) | float(0) / total_kwh) | float(0) %}
        {{ ( (current_price + akcyza + kogen + jakosc + siec + stale) | multiply(0.00123) | float(0) ) }}
      icon: mdi:cash
#------------------------------------------------------------------------------
  - sensor:
    - name: "Diff"
      unique_id: 20240912000008
      unit_of_measurement: "PLN/kWh"
      state: >
        {% set current_price = states('sensor.current_pge_price') | float(0) %}
        {% set static_price = states('sensor.pge_static_price') | float(0) %}
        {{ ((static_price - current_price) | float) }}
      icon: mdi:cash
  - sensor:
    - name: "Diff Fixed"
      unique_id: 20240912000010
      unit_of_measurement: "PLN/kWh"
      state: >
        {% set current_price = states('sensor.pge_dynamic_price_fixed') | float(0) %}
        {% set static_price = states('sensor.pge_static_price_fixed') | float(0) %}
        {% if static_price > 0 and current_price > 0 %}
          {{ ((static_price - current_price) | float(0)) }}
        {% endif %}
      icon: mdi:cash

srednie ceny zakupu w taryfie dynamicznej (encje total na pewno dawno już macie (utility_meter):

template:
  - sensor:
    - name: "Daily AVG PGE Price"
      unique_id: 20240923000101
      unit_of_measurement: "PLN/kWh"
      state: >
        {% set cost = states('sensor.daily_total_cost') | float(0) %}
        {% set kwh  = states('sensor.daily_total_kwh')  | float(0) %}
        {% if kwh > 0 and cost > 0 %}
          {{ (cost/kwh) | float(0) }}
        {% endif %}
      icon: mdi:cash
  - sensor:
    - name: "Weekly AVG PGE Price"
      unique_id: 20240923000102
      unit_of_measurement: "PLN/kWh"
      state: >
        {% set cost = states('sensor.weekly_total_cost') | float(0) %}
        {% set kwh  = states('sensor.weekly_total_kwh')  | float(0) %}
        {% if kwh > 0 and cost > 0 %}
          {{ (cost/kwh) | float(0) }}
        {% endif %}
      icon: mdi:cash
  - sensor:
    - name: "Monthly AVG PGE Price"
      unique_id: 20240923000103
      unit_of_measurement: "PLN/kWh"
      state: >
        {% set cost = states('sensor.monthly_total_cost') | float(0) %}
        {% set kwh  = states('sensor.monthly_total_kwh')  | float(0) %}
        {% if kwh > 0 and cost > 0 %}
          {{ (cost/kwh) | float(0) }}
        {% endif %}
      icon: mdi:cash

i na koniec 2xapexcharts. pierwszy z cenami TGE drugi przeliczony na PGE
uwaga: formatter w sekcji tooltip nie pozwala odczytac cen z wykresu po linii now
uwaga2: formatter do wywalenia, w przypadku gdy znacznik jest na wykresie TGE/PGE cena w tooltip jest ok, jesli na innym pokazuje cene z przed -1d (roznica span i offet), raczej nie da sie poprawić

type: custom:apexcharts-card
card_mod:
  style: |
    ha-card {
      box-shadow: none;
      margin: 0px;
      font-size: 15px;
      font-family: Arial Narrow;
    }
    div#header {
      padding-left: 400px;
      padding-right: 400px;
    }
graph_span: 7d
span:
  start: day
  offset: "-6d"
update_interval: 10min
cache: true
experimental:
  color_threshold: true
all_series_config:
  fill_raw: last
  show:
    extremas: true
    legend_value: false
series:
  - entity: sensor.tge_prices_today
    attribute: tge_rdn
    name: Current TGE Price
    yaxis_id: TGE
    type: area
    opacity: 0.2
    curve: stepline
    stroke_width: 1
    float_precision: 2
    color: "#ffc338"
    color_threshold:
      - value: 800
        color: red
      - value: 600
        color: orange
      - value: 400
        color: yellow
      - value: 200
        color: green
      - value: 0
        color: blue
    show:
      in_header: before_now
    data_generator: |
      return entity.attributes.tge_rdn.map((hour) => {
      const priced = hour.price;
      const UTC_offset = Math.abs(new Date(hour.date).getTimezoneOffset())*60*1000;
        return [new Date(hour.date)-UTC_offset, priced];
      });
  - entity: sensor.daily_avg_pge_price
    name: Daily AVG Price
    yaxis_id: AVG
    type: line
    curve: smooth
    stroke_width: 2
    float_precision: 5
    extend_to: now
    group_by:
      func: last
      duration: 1h
  - entity: sensor.weekly_avg_pge_price
    name: Weekly AVG Price
    yaxis_id: AVG
    type: line
    curve: smooth
    stroke_width: 2
    float_precision: 5
    extend_to: now
    group_by:
      func: last
      duration: 1h
  - entity: sensor.monthly_avg_pge_price
    name: Monthly AVG Price
    yaxis_id: AVG
    type: line
    curve: smooth
    stroke_width: 2
    float_precision: 5
    extend_to: now
    group_by:
      func: last
      duration: 1h
header:
  show: true
  show_states: true
  colorize_states: true
now:
  show: true
  label: Now
  color: red
apex_config:
  annotations:
    position: back
    yAxisIndex: 0
    yaxis:
      - "y": 418.8
        strokeDashArray: 3
        borderColor: red
        borderWidth: 1
        label:
          text: PGE (418.8)
          borderColor: "#ff0000"
          position: left
          offsetX: 15
          style:
            color: "#ffff00"
            background: "#707070"
  chart:
    height: 600px
    dropShadow:
      enabled: true
      enabledOnSeries:
        - 1
        - 2
        - 3
      top: 10
      left: 10
      blur: 3
      color: "#000000"
      opacity: 0.7
zoom:
      type: x
      enabled: true
      autoScaleYaxis: true
    toolbar:
      show: true
      floating: true
      offsetX: -70
      offsetY: -20
      tools:
        download: true
        selection: true
        zoom: true
        zoomin: true
        zoomout: true
        pan: true
        reset: true
      autoSelected: reset
  tooltip:
    shared: true
    intersect: false
    x:
      format: dd MMM (HH:00 - HH:59)
      show: true
    "y":
      formatter: |
        EVAL: function(val1, { series, seriesIndex, dataPointIndex }) {
          return `TGE: ${series[0][dataPointIndex].toFixed(2)} PLN/MWh<br>` +
                 `Daily: ${series[1][dataPointIndex].toFixed(3)} PLN/kWh<br>` +
                 `Weekly: ${series[2][dataPointIndex].toFixed(3)} PLN/kWh<br>` +
                 `Monthly: ${series[3][dataPointIndex].toFixed(3)} PLN/kWh<br>`;
        }
      title:
        formatter: |
          EVAL: function(seriesName) {
            return ""
          }
  grid:
    borderColor: rgb(50, 50, 50)
    position: back
    padding:
      top: -30
      left: -50
      right: -50
    row:
      colors:
        - rgb(55, 55, 55)
        - transparent
      opacity: 0.3
    xaxis:
      lines:
        show: true
    yaxis:
      lines:
        show: true
  legend:
    show: true
  xaxis:
    axisBorder:
      color: "#505050"
    axisTicks:
      show: true
      width: 4
      color: "#909090"
    crosshairs:
      show: true
      position: back
      stroke:
        color: "#505050"
        width: 1
        dashArray: 10
    labels:
      datetimeUTC: false
      style:
        colors: "#bebebe"
        fontSize: 12px
        fontFamily: Arial Narrow
yaxis:
  - id: TGE
    min: -100
    max: 1500
    apex_config:
      forceNiceScale: true
      tickAmount: 16
      decimalsInFloat: 0
      opposite: false
      tooltip:
        enabled: true
      axisTicks:
        show: true
        width: 4
        color: "#909090"
      axisBorder:
        show: true
        color: "#505050"
      crosshairs:
        show: true
        position: back
        stroke:
          color: "#505050"
          width: 1
          dashArray: 10
      title:
        text: "[ TGE ]"
        rotate: 0
        offsetX: 35
        offsetY: -285
        style:
          fontWeight: 600
          color: "#ffc338"
          fontSize: 12px
      labels:
        offsetX: -63
        style:
          colors: "#bebebe"
          fontSize: 12px
          fontFamily: Arial Narrow
  - id: AVG
    min: 0.5
    max: 1.5
    apex_config:
      forceNiceScale: true
      tickAmount: 8
      decimalsInFloat: 3
      opposite: true
      tooltip:
        enabled: true
      axisTicks:
        show: true
        width: 4
        color: "#909090"
      axisBorder:
        show: true
        color: "#505050"
      title:
        text: "[ PGE ]"
        rotate: 0
        offsetX: -30
        offsetY: -285
        style:
          fontWeight: 600
          color: "#bf66ff"
          fontSize: 12px
      labels:
        offsetX: -60
        style:
          colors: "#bebebe"
          fontSize: 12px
          fontFamily: Arial Narrow
type: custom:apexcharts-card
card_mod:
  style: |
    ha-card {
      box-shadow: none;
      margin: 0px;
      font-size: 15px;
      font-family: Arial Narrow;
    }
    div#header {
      padding-left: 400px;
      padding-right: 400px;
    }
graph_span: 7d
span:
  start: day
  offset: "-6d"
update_interval: 10min
cache: true
experimental:
  color_threshold: true
all_series_config:
  fill_raw: last
  show:
    extremas: true
series:
  - entity: sensor.tge_prices_today
    attribute: tge_rdn
    name: Current PGE Price
    unit: PLN/kWh
    yaxis_id: PGE
    type: area
    opacity: 0.2
    curve: stepline
    stroke_width: 1
    float_precision: 5
    color: "#ffc338"
    color_threshold:
      - value: 1.6
        color: red
      - value: 1.4
        color: orange
      - value: 1.2
        color: yellow
      - value: 1
        color: green
      - value: 0.5
        color: blue
    show:
      in_header: before_now
    data_generator: >
      return entity.attributes.tge_rdn.map((hour) => {
      const priced = (hour.price+81.2+5+6.18+31.4+350);
      const UTC_offset = Math.abs(new Date(hour.date).getTimezoneOffset())*60*1000;
        return [new Date(hour.date)-UTC_offset, priced*0.00123];
      });
  - entity: sensor.daily_avg_pge_price
    name: Daily AVG Price
    yaxis_id: PGE
    type: line
    curve: smooth
    stroke_width: 2
    float_precision: 5
    extend_to: now
    group_by:
      func: last
      duration: 1h
  - entity: sensor.weekly_avg_pge_price
    name: Weekly AVG Price
    yaxis_id: PGE
    type: line
    curve: smooth
    stroke_width: 2
    float_precision: 5
    extend_to: now
    group_by:
      func: last
      duration: 1h
  - entity: sensor.monthly_avg_pge_price
    name: Monthly AVG Price
    yaxis_id: PGE
    type: line
    curve: smooth
    stroke_width: 2
    float_precision: 5
    extend_to: now
    group_by:
      func: last
      duration: 1h
header:
  show: true
  show_states: true
  colorize_states: true
now:
  show: true
  label: Now
  color: red
apex_config:
  annotations:
    position: back
    yaxis:
      - "y": 1.09787
        strokeDashArray: 3
        borderColor: red
        borderWidth: 1
        label:
          text: PGE static
          borderColor: "#ff0000"
          position: left
          offsetX: 15
          style:
            color: "#ffff00"
            background: "#707070"
  chart:
    height: 600px
    dropShadow:
      enabled: true
      enabledOnSeries:
        - 1
        - 2
        - 3
      top: 10
      left: 10
      blur: 3
      color: "#000000"
      opacity: 0.7
    zoom:
      type: x
      enabled: true
      autoScaleYaxis: true
    toolbar:
      show: true
      floating: true
      offsetX: -20
      offsetY: -20
      tools:
        download: true
        selection: true
        zoom: true
        zoomin: true
        zoomout: true
        pan: true
        reset: true
      autoSelected: reset
  tooltip:
    shared: true
    intersect: false
    x:
      format: dd MMM (HH:00 - HH:59)
      show: true
    "y":
      formatter: |
        EVAL: function(val1, { series, seriesIndex, dataPointIndex }) {
          return `PGE: ${series[0][dataPointIndex].toFixed(5)} PLN/kWh<br>` +
                 `Daily: ${series[1][dataPointIndex].toFixed(5)} PLN/kWh<br>` +
                 `Weekly: ${series[2][dataPointIndex].toFixed(5)} PLN/kWh<br>` +
                 `Monthly: ${series[3][dataPointIndex].toFixed(5)} PLN/kWh<br>`;
        }
      title:
        formatter: |
          EVAL: function(seriesName) {
            return ""
          }
  grid:
    borderColor: rgb(50, 50, 50)
    position: back
    padding:
      top: -30
      left: -30
    row:
      colors:
        - rgb(55, 55, 55)
        - transparent
      opacity: 0.3
    xaxis:
      lines:
        show: true
    yaxis:
      lines:
        show: true
  legend:
    show: true
  xaxis:
    axisBorder:
      color: "#505050"
    axisTicks:
      show: true
      width: 4
      color: "#909090"
    crosshairs:
      show: true
      position: back
      stroke:
        color: "#505050"
        width: 1
        dashArray: 10
    labels:
      datetimeUTC: false
      style:
        colors: "#bebebe"
        fontSize: 12px
        fontFamily: Arial Narrow
  yaxis:
    - id: PGE
      min: 0.5
      forceNiceScale: true
      decimalsInFloat: 3
      opposite: false
      axisTicks:
        show: true
        width: 4
        color: "#909090"
      axisBorder:
        show: true
        color: "#505050"
      tooltip:
        enabled: true
      crosshairs:
        show: true
        position: back
        stroke:
          color: "#505050"
          width: 1
          dashArray: 10
      title:
        text: "[ PGE ]"
        rotate: 0
        offsetX: 25
        offsetY: -285
        style:
          fontWeight: 600
          color: "#ffc338"
          fontSize: 12px
      labels:
        offsetX: -43
        style:
          colors: "#bebebe"
          fontSize: 12px
          fontFamily: Arial Narrow

i na deser pączek, dla mnie ocena progu opłacalności taryfy dynamicznej :slight_smile:

type: custom:apexcharts-card
chart_type: donut
update_interval: 10min
header:
  show: true
  show_states: false
  colorize_states: true
  title: Monthly total [kWH]
series:
  - entity: sensor.monthly_salon_kwh
    name: Salon
  - entity: sensor.monthly_kuchnia_kwh
    name: Kuchnia
  - entity: sensor.monthly_lodowka_kwh
    name: Lodowka
all_series_config:
  float_precision: 2
apex_config:
  chart:
    height: 400px
  dataLabels:
    style:
      fontSize: 15px
    formatter: |
      EVAL:function(value) {
        return value.toFixed(2) + " %";
      }
  plotOptions:
    pie:
      customScale: 1
      dataLabels:
        minAngleToShowLabel: 4
      donut:
        size: 50%
        background: transparent
        labels:
          show: true
          name:
            show: false
          total:
            show: true
            label: Total kWh
            formatter: |
              EVAL:function(w) {
                return w.globals.seriesTotals.reduce((a, b) => {return (a + b)} , 0).toFixed(2) + " kWh"
                }

na koniec kilka screenow




uprzedzając pytania o okno czasowe highest lowest to na razie nie wiem nawet jak zacząć, ale mam to w planach. pythona nie znam wogóle i pewnie pojdę drogą bash i jq (funkcje max_by i min_by), ale szybko nie będzie (jq poznałem kilka dni temu)
PZDR i miłego dłubania

4 polubienia

@bialy WOW! Kawał roboty.

Przykleiłem kod i czekam do 17 na efekt pobrania JASONA z Instrat.

Czyli dodatkowo zrobiłeś scrappera pobierającego z TGE?

Jeszcze nie rozmieniłem za co odpowiada u Ciebie każdy z template sensorów.
Widzę w ich kodzie poszczególne składowe cen za MWh i fajnie to jest przejrzyście zrobione. Może byś w 2 słowach opisał za co odpowiada każdy z sensorów. Przeczytałem opis 3 razy ale nie wyłuskałem wszystkiego bo sporo tego :slight_smile:

Może by jednak w ramach rozwoju przenieść te wartości do imput_number z przypisaną domyślną, np.

input_number:
  adjustable_kogen:
    name: "Cogeneration Value"
    min: 0
    max: 100
    step: 0.01
    unit_of_measurement: "PLN"
    icon: mdi:cash
    initial: 6.18

Co ty na to?. Mogę pomóc.

Musiałem pozmieniać bo mam oddzielnie sensors.yaml, command_line.yaml,
dla template sensorów jest wtedy inna składnia.

No i na koniec, taryfa dynamiczna jako średnia jej cen w porównaniu do ceny G11 to raczej na pewno się nie opłaci ale jak wysterujesz jakieś urządzenia (pompę ciepła, ładowanie magazynu energii) w dołkach cenowych, to już jak najbardziej.

I podał w prawidłowym formacie czyli kompletny kod, tak się robi, takie kompletne przyklady są zawsze w dokumentacji. Każdy z nas ma swój sposób na organizacje plików konfiguracyjnych i tylko podawanie kompletnego kodu gwarantuje, że kazdy może z niego skorzystać.

@bialy tak trzymaj, brawo TY :exclamation: zawsze podawaj kompletny kod HA.

1 polubienie

sprawdziłem o co chodzi z input_number (nigdy nie używałem) i wszystkie dodawane wartości są stałe dla każdego z operatorów, wiec raczej nie widzę sensu. jest przejrzyście i każdy może zmienić cyfry pod swojego. tym bardziej że użwane są tylko dla jednej encji.
co do składni. chciałem uniknąć komplikacji, wiec wrzuciłem wszystko do configuration.yaml. normalnie mam w innych plikach bo zacząłem sie gubić:
(configuration.yaml)

template: !include_dir_merge_list custom_components/yaml_templates/

a w katalogu custom_components/yaml_templates/ dwa pliki tge_pge.yaml i avg_pge.yaml
nie bede wrzucał ponownie zawartości żeby nie duplikować. w plikach jest juz bez “template:”

kolejne 5 sensorow jest tylko do obserwacji i nie są Wam raczej potrzebne. ja uczyłem się HA i te były pierwsze. jestem wzrokowcem, wiec chciałem po prostu widzieć cyfry.

  • “PGE Static Price” - stała cena dla PGE potrzebna tylko żeby policzyć różnice z dynamiczną. dlaczego tak? żeby składnia obu sensorów była identyczna, odjąć jeden od drugiego i zobaczyć wykres.
  • “PGE Dynamic Price Fixed” i “PGE Static Price Fixed” to samo co static i current z płatami stałymi, w tym przypadku dla PGE: (handlowa,abonamentowa,przejściowa, stała sieciowa). obie spadają z każdą zużytą kWh z tym że poniżej ceny 418.8 na TGE Dynamic Fixed spada szybciej (500 - opłata kosztowa). utrzymujące się przecięcie “będzie oznaczało” próg opłacalności i bedzie to pewnie powyżej 160kWh
  • “Diff” i “Diff_fixed” po prostu różnica do wizualizacji (wartość dodatnia mam taniej, ujemna drożej)

sensory AVG (daily,weekly,monthly) wiadomo ile konkretnie kosztuje mnie energia. na dzisiaj srednią miesięczną mam 1,026 pln/kWh (dzisiaj było drogo) więc jestem do przodu 0,07 na kWh * moje 150kWh = 10,50pln i nie pokrywa opłaty handlowej. i to jest nieważne, przeszedłem na taryfę dynamiczną żeby mieć motywację i cel do poznania HA, a wiedza którą zdobyłem jest bezcenna, myślę że warta tych 20-30pln miesięcznie :slight_smile: nawet jesli o tyle bedzie drożej (próg opłacalności oceniam na 160kWh przy świadomym używaniu kuchenki, ale ocenie to na wykresie pączka na koniec miesiąca)
nie mam pompy ciepła ani nic większego niż kuchenka elektryczna, mieszkam w bloku ale z pompą ciepła i jakimkolwiek magazynem ciepła czy energii byłaby bajka (dla koputerów,routera i monitorów mam ups)
i teraz prośba. mogłbyś zmodyfikować fragment data_generator z apexcharts żeby rozpoznawał czas letni i zimowy? obecnie jest przesunięcie wykresu o 2h zapisem -(2*3600*1000)
a zaraz bedzie zmiana czasu i bedzie -1 a nie wiem jak to zrobić:

data_generator: |
      return entity.attributes.tge_rdn.map((hour) => {
      const priced = hour.price
        return [new Date(hour.date)-(2*3600*1000), priced];
      });

co do przesunięcia. za przesunięcie osi odpowiada ten zapis:

apex_config:
  xaxis:
    labels:
      datetimeUTC: false

poniżej screen z cyframi sensorów o które pytałeś

OK. Super to wykminiłeś już mi się udało wdrożyć :slight_smile:

Jutro przyjże się w praktyce działaniu twoich sensorów.

Pomyślę co z tym Apexem zrobić.

Po dzisiejszym dniu mam już wszystkie elementy żeby lepiej sterować pracą falownika Deye i magazynu, bo udało mi się podłączyć go do HA tak żeby nim sterować z systemu.
Dzięki sensorom cen RCE mam zamiar sterować sprzedażą energii w najdroższych okresach, a dzięki Twoim cenom TGE/PGE ładowaniem magazynu z sieci kiedy nie ma słońca. Będzie co robić w zimie :slight_smile:

W Urządzenia oraz usługi można dodać sensor season

poprawiłem data_generator z apexcharts (zmiany już naniesione w pierwszym poście)

    data_generator: |
      return entity.attributes.tge_rdn.map((hour) => {
      const priced = hour.price;
      return [new Date(hour.date)-(2*3600*1000), priced];
      });
zmienić na
    data_generator: >
      return entity.attributes.tge_rdn.map((hour) => {
      const priced = hour.price;
      const UTC_offset = Math.abs(new Date(hour.date).getTimezoneOffset())*60*1000;
        return [new Date(hour.date)-UTC_offset, priced];
      });
lub na
    data_generator: >
      return entity.attributes.tge_rdn.map((hour) => {
      const priced = (hour.price+81.2+5+6.18+31.4+350);
      const UTC_offset = Math.abs(new Date(hour.date).getTimezoneOffset())*60*1000;
        return [new Date(hour.date)-UTC_offset, priced*0.00123];
      });

dodatkowo poprawiłem mój błąd z multiyaxis. przeoczyłem bo częściej zaglądałem do oryginalnej dokumentacji. teraz jest w/g tego GitHub - RomRider/apexcharts-card: 📈 A Lovelace card to display advanced graphs and charts based on ApexChartsJS for Home Assistant, niestety przestaje wtedy działać ‘forceNiceScale’. (zmiany już naniesione w pierwszym poście)
zmiana polega na:

apex_config:
...
...
  yaxis:
    - id: TGE
    ...
    - id: AVG
    ...
zmiana na
yaxis:
  - id: TGE
    min: -100
    max: 1500
    apex_config:
      ...
      ...
  - id: AVG
    min: 0.5
    max: 1.5
    apex_config:
      ...
      ...

+inne kosmetyczne
edit:
właśnie znalazłem coś dla fanów wyglądu 3d :slight_smile:

apex_config:
  chart:
    dropShadow:
      enabled: true
      enabledOnSeries:
        - 1
        - 2
        - 3
      top: 10
      left: 10
      blur: 3
      color: "#000000"
      opacity: 0.7

edit:
znaleziony błąd w formatter w sekcji tooltip. formatter do wywalenia, w przypadku gdy znacznik jest na wykresie TGE/PGE cena w tooltip jest ok, jeśli na innym pokazuje cene -1d (roznica span i offet), raczej nie da się poprawić. znalazłem to w necie, ale takiej sytuacji autor nie przewidział.

można dodać 24h ale zepsuje wyświetlanie w drugą stronę
TGE: ${series[0][dataPointIndex+24].toFixed(2)} PLN/MWh

"y":
      formatter: |
        EVAL: function(val1, { series, seriesIndex, dataPointIndex }) {
          return `TGE: ${series[0][dataPointIndex].toFixed(2)} PLN/MWh<br>` +
                 `Daily: ${series[1][dataPointIndex].toFixed(5)} PLN/kWh<br>` +
                 `Weekly: ${series[2][dataPointIndex].toFixed(5)} PLN/kWh<br>` +
                 `Monthly: ${series[3][dataPointIndex].toFixed(5)} PLN/kWh<br>`;
        }

Dzięki za aktualizację, ja też pracuję nad optymalizatorem kosztów ale jeszcze chwilę …

Mam pytanie do twoich sensorów:
pge_static_price_fixed:
pge_dynamic_price_fixed

Uwzględniają one dodatkowo zmienną “stale” (9.99 + 0.75 + 0.33 + 10.48)
i dzielą przez miesięczne zużycie energii.

Co to za stałe? Czy to opłaty stałe z rachunku?
Jeśli tak to powinny być mnożone przez ilość miesięcy a nie dzielone prze ilość energii? Chyba się pogubiłem