Integração OMIE: preços horários, diários, mecanismo de ajuste

Aí infelizmente é um pouco mais complicado, é preciso actualizar o template sensor primeiro e depois os gráficos.

Já tenho isso feito localmente, vou tentar publicar mais logo.

1 Curtiu

De momento não tenho tempo para actualizar o Wiki de modo que partilho aqui os sensores que tenho no meu ambiente de testes, já actualizados para a v1.

Gists:

2 Curtiram

Ontem libertei a v1.0.0. O wiki também está actualizado, se derem por alguma coisa que está mal avisem.

3 Curtiram

Muito obrigado, @luuuis!
Consegui adaptar tudo com a ajuda dos links e ficou fantástico!

1 Curtiu

Está bonito, sim senhor. Isso é com apexcharts-card? Hás-de me dizer como é que colocas a unidade (€) ao lado dos valores no eixo vertical.

nao queres partilhar o codigo desses graficos? :slight_smile:

Não tenho mérito nenhum: é a proposta do André Leal Thy_Hunter, que está mais acima no fórum. Não sei especificamente o que faz colocar o €, mas deve estar no código do André. Eu adaptei aos sensores… Cá vai:

type: custom:apexcharts-card
card_mod:
  style: |
    ha-card {
      width: 450px;
      border: none;
      background: transparent
    }
header:
  show: true
  title: OMIE Horário - Hoje e Venda à Rede
update_interval: 10m
now:
  show: true
span:
  end: day
graph_span: 24h
series:
  - entity: sensor.omie_spot_price_pt
    name: Hourly price
    yaxis_id: price
    stroke_width: 1
    type: column
    color: '#FA7000'
    group_by:
      func: last
      duration: 1h
    show:
      extremas: true
      legend_value: true
    data_generator: >
      return ((hs) => Object.keys(hs).map((dt) => [ new Date(dt), hs[dt]
      ]))(entity.attributes.today_hours)
  - entity: sensor.venda_24h_rede
    name: Injeção
    yaxis_id: injeção
    type: line
    stroke_width: 3
    group_by:
      fill: zero
      func: diff
      duration: 1h
      start_with_last: false
    color: green
yaxis:
  - id: injeção
    max: 4
    opposite: true
    show: true
    decimals: 2
    apex_config:
      forceNiceScale: 'yes'
      labels:
        show: true
        style:
          colors: '#ffffff'
          fontSize: 10px
        offsetX: 0
        offsetY: 0
      axisBorder:
        show: false
        color: '#78909C'
  - id: price
    show: true
    decimals: 1
    apex_config:
      forceNiceScale: 'yes'
      labels:
        show: true
        formatter: |
          EVAL:function(value) {
          let text = parseFloat(value).toFixed(2);
          let result = "€" +text.replace(".", ",");
          return result;
          }
        style:
          colors: '#ffffff'
          fontSize: 10px
        offsetX: 0
        offsetY: 0
      axisBorder:
        show: false
        color: '#78909C'
apex_config:
  tooltip:
    enabled: true
    shared: true
    followCursor: false
    intersect: false
    inverseOrder: false
    fillSeriesColor: true
    theme: false
    onDatasetHover:
      highlightDataSeries: false
    x:
      show: false
  legend:
    show: false
    position: top
  annotations:
    position: back
  chart:
    height: 250
    type: bar
  grid:
    show: true
    strokeDashArray: '0'
    borderColor: '#666666'

type: custom:apexcharts-card
card_mod:
  style: |
    ha-card {
      width: 450px;
      border: none;
      background: transparent
    }
header:
  show: true
  title: OMIE Horário - Amanhã
update_interval: 10m
now:
  show: true
span:
  start: day
  offset: +24h
graph_span: 24h
series:
  - entity: sensor.omie_spot_price_pt
    name: Hourly price
    yaxis_id: price
    stroke_width: 1
    type: column
    color: '#FA7000'
    group_by:
      func: last
      duration: 1h
    show:
      extremas: true
      legend_value: true
    data_generator: >
      return ((hs) => Object.keys(hs).map((dt) => [ new Date(dt), hs[dt]
      ]))(entity.attributes.tomorrow_hours)
yaxis:
  - id: price
    show: true
    decimals: 1
    apex_config:
      forceNiceScale: 'yes'
      labels:
        show: true
        formatter: |
          EVAL:function(value) {
          let text = parseFloat(value).toFixed(2);
          let result = "€" +text.replace(".", ",");
          return result;
          }
        style:
          colors: '#ffffff'
          fontSize: 10px
        offsetX: 0
        offsetY: 0
      axisBorder:
        show: false
        color: '#78909C'
apex_config:
  tooltip:
    enabled: true
    shared: true
    followCursor: false
    intersect: false
    inverseOrder: false
    fillSeriesColor: true
    theme: false
    onDatasetHover:
      highlightDataSeries: false
    x:
      show: false
  legend:
    show: false
    position: top
  annotations:
    position: back
  chart:
    height: 250
    type: bar
  grid:
    show: true
    strokeDashArray: '0'
    borderColor: '#666666'

type: custom:apexcharts-card
card_mod:
  style: |
    ha-card {
      width: 450px;
      border: none;
      background: transparent
    }
header:
  show: true
  title: Coopérnico Spot Bi-horário - Hoje e Compra à Rede
update_interval: 10m
now:
  show: true
span:
  end: day
graph_span: 24h
series:
  - entity: sensor.template_coopernico_spot_price_bihorario
    name: Hourly price
    yaxis_id: price
    stroke_width: 1
    type: column
    color: '#FA7000'
    group_by:
      func: last
      duration: 1h
    show:
      extremas: true
      legend_value: true
    data_generator: >
      return ((hs) => Object.keys(hs).map((dt) => [ new Date(dt), hs[dt]
      ]))(entity.attributes.today_hours)
  - entity: sensor.consumo_24h_rede
    name: Consumo
    yaxis_id: consumo
    type: line
    stroke_width: 3
    group_by:
      fill: zero
      func: diff
      duration: 1h
      start_with_last: false
    color: green
yaxis:
  - id: consumo
    max: 5
    opposite: true
    show: true
    decimals: 2
    apex_config:
      forceNiceScale: 'yes'
      labels:
        show: true
        style:
          colors: '#ffffff'
          fontSize: 10px
        offsetX: 0
        offsetY: 0
      axisBorder:
        show: false
        color: '#78909C'
  - id: price
    show: true
    decimals: 1
    apex_config:
      forceNiceScale: 'yes'
      labels:
        show: true
        formatter: |
          EVAL:function(value) {
          let text = parseFloat(value).toFixed(2);
          let result = "€" +text.replace(".", ",");
          return result;
          }
        style:
          colors: '#ffffff'
          fontSize: 10px
        offsetX: 0
        offsetY: 0
      axisBorder:
        show: false
        color: '#78909C'
apex_config:
  tooltip:
    enabled: true
    shared: true
    followCursor: false
    intersect: false
    inverseOrder: false
    fillSeriesColor: true
    theme: false
    onDatasetHover:
      highlightDataSeries: false
    x:
      show: false
  legend:
    show: false
    position: top
  annotations:
    position: back
  chart:
    height: 250
    type: bar
  grid:
    show: true
    strokeDashArray: '0'
    borderColor: '#666666'

type: custom:apexcharts-card
card_mod:
  style: |
    ha-card {
      width: 450px;
      border: none;
      background: transparent
    }
header:
  show: true
  title: Coopérnico Spot Bi-horário - Amanhã
update_interval: 10m
span:
  start: day
  offset: +24h
graph_span: 24h
series:
  - entity: sensor.template_coopernico_spot_price_bihorario
    name: Hourly price
    yaxis_id: price
    stroke_width: 1
    type: column
    color: '#FA7000'
    group_by:
      func: last
      duration: 1h
    show:
      extremas: true
      legend_value: true
    data_generator: >
      return ((hs) => Object.keys(hs).map((dt) => [ new Date(dt), hs[dt]
      ]))(entity.attributes.tomorrow_hours)
yaxis:
  - id: price
    show: true
    decimals: 1
    apex_config:
      forceNiceScale: 'yes'
      labels:
        show: true
        formatter: |
          EVAL:function(value) {
          let text = parseFloat(value).toFixed(2);
          let result = "€" +text.replace(".", ",");
          return result;
          }
        style:
          colors: '#ffffff'
          fontSize: 10px
        offsetX: 0
        offsetY: 0
      axisBorder:
        show: false
        color: '#78909C'
apex_config:
  tooltip:
    enabled: true
    shared: true
    followCursor: false
    intersect: false
    inverseOrder: false
    fillSeriesColor: true
    theme: false
    onDatasetHover:
      highlightDataSeries: false
    x:
      show: false
  legend:
    show: false
    position: top
  annotations:
    position: back
  chart:
    height: 250
    type: bar
  grid:
    show: true
    strokeDashArray: '0'
    borderColor: '#666666'

É o formatter do yaxis. :+1:

O SQL da Wiki só é válido para SQLite. Eu não sou muito entendido, mas consegui adaptar um dos sensores SQL para MariaDB.

Deixo aqui caso seja util a alguém, e caso saibam de uma forma melhor de conseguir o mesmo, aceito sugestões.

name: OMIE PT Spot Price Month to Date Average
query: |-
  SELECT FROM_UNIXTIME(stats.start_billing_ts) AS window_start,
        FROM_UNIXTIME(stats.start_of_day_ts) AS window_end,
        FROM_UNIXTIME(MIN(start_ts)) AS oldest_measurement,
        FROM_UNIXTIME(MAX(start_ts)) AS newest_measurement,
        COUNT(*) AS measurement_count,
        ROUND(AVG(s.mean), 2) AS mean
  FROM statistics s 
  JOIN statistics_meta m ON s.metadata_id = m.id 
  CROSS JOIN (
      SELECT UNIX_TIMESTAMP(CASE 
                                WHEN DAY(NOW()) > billing_offset 
                                THEN CONCAT_WS('-', YEAR(NOW()), MONTH(NOW()), billing_offset) 
                                ELSE CONCAT_WS('-', YEAR(NOW() - INTERVAL 1 MONTH), MONTH(NOW() - INTERVAL 1 MONTH), billing_offset) 
                            END) AS start_billing_ts,
            UNIX_TIMESTAMP(CURDATE()) AS start_of_day_ts
      FROM (
          -- ⚠️ ADJUST HERE AS NECESSARY (e.g. 20 to start billing cycle at midnight on day 21):
          SELECT 20 AS billing_offset
          ) cfg
  ) AS stats
  WHERE statistic_id = 'sensor.omie_spot_price_pt' 
  AND start_ts >= stats.start_billing_ts 
  AND start_ts < stats.start_of_day_ts;
column: 'mean'
unit_of_measurement: 'EUR/MWh'
1 Curtiu

notei que tens uma entity chamada

sensor.venda_24h_rede

isto é baseado em quê exatamente, extrais do teu inverter ou algum custom que construiste?

acho estranho estar a ter problemas com todos os graficos que referem o valor do dia seguinte, quaisquer configuração que use (inclusive um simple copy & paste da wiki) mete-se o grafico sempre em Loading… e não sai dai.

Esse sensor resulta de uma integração do sensor do consumo. O inversor dá o consumo da casa e eu fiz uma integração (serviços → Auxiliar) para fazer o registo do consumo.

Se tens um sensor de consumo que te diga o consumo da casa, que uses no energy board do Home Assistant, por exemplo, altera o sensor 24h do código para esse teu.

Se não tiveres nenhum sensor de consumo da casa, elimina esse sensor e toda a informação referente a esse eixo… Também podes usar o gráfico 2 ou 4, mudando o data_generator: para o do gráfico 1 ou 3…

Mas em princípio se tens a integração OMIE do Luís e o apexcharts, o gráfico 2 deveria funcionar sem problemas… Para o gráfico 4, deverás ter o código da Coopérnico que o Luís fala na Wiki. Para o gráfico 1 e 3, deverás ter sensores de consumo e de venda de eletricidade à rede…

Também relembrar que estes testes convém que sejam feitos entre as 14h e as 24h, por causa dos horários do dia seguinte. Fora destas horas, há probabilidade de o gráfico estar sempre loading porque não há informação OMIE para o dia seguinte…

O inversor regista o Import e Export, aka o Consumo e o Excedente.
Olhando para a logica do teu grafico, visto que lhe chamas injeção, o sensor ligado a isto deveria ser o Export e não o Import/Consumo, nao faz mais sentido?
Posso estar a ver mal as coisas.

Sim, é isso: injeção na rede. Export…

Obrigado @beloso , vou partilhar no Wiki.

@tretabyte em primeiro lugar garantir que corres a versão 1.0.0 pois os gráficos que estão no Wiki trabalham os atributos novos nessa versão. Em segundo lugar verificar que o atributo tomorrow_hours contem de facto preenchido os valores futuros.

Alguém já criou os templates para compra de energia à Luzboa que queira “doar” ao Wiki?

1 Curtiu

sim estou a correr a versao 1.0.0 mas pelo que vejo os valores de Tomorrow não estão a ser puxados por algum estranho motivo.

Fui ver e também me aconteceu no ambiente de testes (mas não no outro). Vou investigar.

Hoje também me aconteceu ao final do dia, mas com as atualizações e o respetivo reinício, ficou novamente normal…

Templates Luzboa que uso:

Custo kWh/dia:

---
sensor:
  - name: Luzboa Daily Spot Cost
    unit_of_measurement: €/kWh
    state_class: measurement
    state: |-
      {% set PMD = state_attr(this.entity_id, 'PMD') | float(default=0) -%}
      {% set MIBEL = state_attr(this.entity_id, 'MIBEL') | float(default=0) -%}
      {% set Desvios = state_attr(this.entity_id, 'Desvios') | float(default=0) -%}
      {% set SAJ = state_attr(this.entity_id, 'SAJ') | float(default=0) -%}
      {% set PFC = ((PMD+MIBEL)/1000) + Desvios + SAJ -%}
      {% set FA = state_attr(this.entity_id, 'FA') | float(default=0) -%}
      {% set PT = state_attr(this.entity_id, 'PT') | float(default=0) -%}
      {% set CG = state_attr(this.entity_id, 'CG') | float(default=0) -%}
      {% set TEPAi = state_attr(this.entity_id, 'TEPAi') | float(default=0) -%}
      
      {{( (PFC*(1+PT))*FA+(CG)+(TEPAi) ) | round(4) }}
    attributes:
      friendly_name: "Luzboa €/kWh"
      formula: (ER*PFC*(1+PT)*FA)+(ER*CG)+(ER*TEPAi)
      PMD: "{{ state_attr('sensor.omie_spot_price_pt', 'today_average') | float(default=0) }}"
      MIBEL: "{{ state_attr('sensor.omie_adjustment_price_pt', 'today_average') | float(default=0) }}"
      Desvios: "{{ 0 | round(4) }}"
      SAJ: "{{ 0.004 | round(4) }}"
      FA: "{{ 1.02 | round(4) }}"
      PT: "{{ 0.1507 | round(4) }}"
      CG: "{{ 0.005 | round(4) }}"
      TEPAi: "{{ -0.09580 | round(4) }}"

Luzboa custo médio mensal, usa o SQL do month to date, o que partilhei acima, para tentar estimar o custo kWh total do mês.

---
sensor:
  - name: Luzboa Average Monthly Cost
    unit_of_measurement: €/kWh
    state_class: measurement
    state: |-
      {% set PMD = state_attr(this.entity_id, 'PMD') | float(default=0) -%}
      {% set MIBEL = state_attr(this.entity_id, 'MIBEL') | float(default=0) -%}
      {% set Desvios = state_attr(this.entity_id, 'Desvios') | float(default=0) -%}
      {% set SAJ = state_attr(this.entity_id, 'SAJ') | float(default=0) -%}
      {% set PFC = ((PMD+MIBEL)/1000) + Desvios + SAJ -%}
      {% set FA = state_attr(this.entity_id, 'FA') | float(default=0) -%}
      {% set PT = state_attr(this.entity_id, 'PT') | float(default=0) -%}
      {% set CG = state_attr(this.entity_id, 'CG') | float(default=0) -%}
      {% set TEPAi = state_attr(this.entity_id, 'TEPAi') | float(default=0) -%}
      
      {{( (PFC*(1+PT))*FA+(CG)+(TEPAi) ) | round(4) }}
    attributes:
      friendly_name: "Luzboa €/kWh"
      formula: (ER*PFC*(1+PT)*FA)+(ER*CG)+(ER*TEPAi)
      PMD: "{{ states('sensor.omie_pt_spot_price_month_to_date_average') | float(default=0) }}"
      MIBEL: "{{ state_attr('sensor.omie_adjustment_price_pt', 'today_average') | float(default=0) }}"
      Desvios: "{{ 0 | round(4) }}"
      SAJ: "{{ 0.004 | round(4) }}"
      FA: "{{ 1.02 | round(4) }}"
      PT: "{{ 0.1507 | round(4) }}"
      CG: "{{ 0.005 | round(4) }}"
      TEPAi: "{{ -0.09580 | round(4) }}"

Basei-me nuns templates partilhados acima, só adaptei para a versão 1.0.0 e o meu template SQL
(Acho que devia usar um SQL para o MIBEL, mas lá chegarei).

4 Curtiram

Copyright © 2017-2021. Todos os direitos reservados
CPHA.pt - info@cpha.pt


FAQ | Termos de Serviço/Regras | Política de Privacidade