rnovacek / homeassistant_cz_energy_spot_prices

Home Assistant integration that provides current Czech electricity spot prices based on OTE.
Apache License 2.0
75 stars 17 forks source link

Vzorové řešení reálných nákupních cen u dvoutarifních sazeb #49

Open martin-klima opened 3 months ago

martin-klima commented 3 months ago

Nabízím řešení výpočtu reálných nákupních cen u dvoutarifních sazeb. Výsledkem je graf pro celé známé období spotových cen zohledňující regulovanou část ceny, DPH a další případné poplatky.

Jedná se téměř o klon senzoru current_spot_electricity_price, avšak s přepočítanými cenami. To znamená, že ceny pro jednotlivé hodiny jsou dostupné jako atributy. Na rozdíl od originálního senzoru jsou všechny ceny sloučeny pod jeden atribut prices, takže se nemíchají s ostatními atributy, jako je např. friendly_name. Jako stav senzoru se zobrazuje aktuální cena.

image Porovnání grafu reálných cen (nahoře) a originálního grafu (dole)

Co si každý musí nastavit podle sebe:

  1. hodiny vysokého tarifu vt_hours. Kdo má FVE, ten má hodiny stabilní během celého roku, kdo ne, ten bude muset updatovat podle změn na straně distributora. Zadává se jako pole, kde každé číslo představuje hodinu, kdy je vysoký tarif.
  2. regulovanou složku ceny pro oba tarify price_vt a price_nt bez DPH. V mém případě používám ceny v Kč za kWh. Regulované ceny lze najít ve vyúčtování, a protože je část poplatků fixní za měsíc a část se váže na MWh, je třeba si to spočítat podle vaší modelové spotřeby a ceny za jistič. Mně to pro sazbu D57 a jistič 3x 20A vychází price_vt = 1.38 pro vysoký tarif a price_nt = 1.186 pro nízký tarif.
  3. sazbu DPH. V mém případě je to vat = 21, tedy 21 %.

Template sensor

  - name: "Spot Electricity Buy Prices"
    unique_id: spot_electricity_buy_prices
    unit_of_measurement: "Kč/kWh"
    attributes:
      prices: >
        {%- set vt_hours = [9, 12, 16, 20] %}
        {%- set price_vt = 1.38 %}
        {%- set price_nt = 1.186 %}
        {%- set vat = 21 %}
        {%- set ns = namespace(buy_prices=[]) %}
        {%- for key, value in states.sensor.current_spot_electricity_price.attributes.items() %}
          {%- if key[:4].isnumeric() %}
            {%- set hour = strptime(key, '%Y-%m-%dT%H:%M:%S%z').hour %}
            {%- if hour not in vt_hours %}
              {%- set addPrice = price_nt %}
            {%- else %}
              {%- set addPrice = price_vt %}
            {%- endif %}
            {%- set value = ((value + addPrice) * (1 + vat / 100)) | round(2) %}
            {%- set ns.buy_prices = ns.buy_prices + [{key: value}] %}
          {%- endif %}
        {%- endfor %}
        {{ns.buy_prices}}
    state: >
      {%- set vt_hours = [9, 12, 16, 20] %}
      {%- set price_vt = 1.38 %}
      {%- set price_nt = 1.186 %}
      {%- set vat = 21 %}

      {%- set hour_now = now().hour %}
      {%- set day_now = now().day %}
      {%- for key, value in states.sensor.current_spot_electricity_price.attributes.items() %}
        {%- if key[:4].isnumeric() %}
          {%- set hour = strptime(key, '%Y-%m-%dT%H:%M:%S%z').hour %}
          {%- set day = strptime(key, '%Y-%m-%dT%H:%M:%S%z').day %}
          {%- if hour == hour_now and day == day_now %}
          {%- if hour not in vt_hours %}
            {%- set addPrice = price_nt %}
          {%- else %}
            {%- set addPrice = price_vt %}
          {%- endif -%}
          {{ ((value + addPrice) * (1 + vat / 100)) | round(2) }}
        {%- endif %}
        {%- endif %}
      {%- endfor %}

Jsou dva způsoby, jak template senzor vytvořit

1) v souboru configuration.yaml, jak je popsáno zde: https://www.home-assistant.io/integrations/template

template:
  - sensor:
    - name: "Spot Electricity Buy Prices"
    (atd...)

2) strukturovaně, jak je popsáno zde: https://www.home-assistant.io/docs/configuration/splitting_configuration Soubor configuration.yaml pak obsahuje:

template: !include_dir_merge_named template/

V adresáři template je pak soubor sensor.yaml a v něm je uvedený kód.

sensor:
  - name: "Spot Electricity Buy Prices"
  (atd...)

Konfigurace grafu

type: custom:apexcharts-card
header:
  show: true
  show_states: true
  colorize_states: true
graph_span: 2d
span:
  start: day
now:
  show: true
  label: Now
series:
  - entity: sensor.spot_electricity_buy_prices
    float_precision: 2
    type: column
    color: '#090'
    show:
      in_header: raw
    data_generator: |
      return Object.entries(entity.attributes.prices).map(([idx, row]) => {
        var date = Object.keys(row)[0];
        var price = Object.values(row)[0];

        return [new Date(date).getTime(), price];
      });
jirkaholy commented 3 months ago

Děkuji na řešení, na které asi hodně lidí čekalo. Bohužel se mi to nepodařilo ani po delší době zprovoznit. Pokud vytvořím helper/teplate/sensor a vložím do něj kód, hlásí to : Invalid state with length 1939. State max length is 255 characters. Nějakým způsobem to ovlivňuje ns.buy_prices. Když vymažu, hláška zmizí, ale sensor nefunguje. Chybí mi něco v nastavení? Děkuji za pomoc

martin-klima commented 3 months ago

@jirkaholy Děkuji za report. Tento sensor nelze vytvořit jako helper, jelikož template helper sensor podporuje pouze state, nikoliv atributy.

Uvedený kód je třeba použít k vytvoření plnohodnotného template sensoru v yaml souboru. Zítra dodám podrobnosti.

martin-klima commented 2 months ago

@jirkaholy Rozšířil jsem svůj příspěvek o sekci "Jsou dva způsoby, jak template senzor vytvořit", snad ti to pomůže. Kdyžtak dej vědět.

Otestoval jsem, že senzor lze vytvořit i přes helper, jak jsi to udělal ty, ale jak jsem už napsal včera, podporuje pouze 'state', tedy aktuální hodnotu, nikoliv atributy. V takovém případě je třeba vložit pouze tu část kódu, pod state: >.

jirkaholy commented 2 months ago

Perfektní, funguje. Díky

jirimissbach commented 1 month ago

@martin-klima - funguje výborně - díky. Jde udělat sort který najde nejnižší cenu v konkrítním čase? Například senzory 2, 3, 4 cheapes hodin v NT? Pro nabíjení auta ideální.