Skip to content

Instantly share code, notes, and snippets.

@luuuis
Last active February 18, 2023 18:36
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save luuuis/25a1030327a6ff9713a5a6747ebb6154 to your computer and use it in GitHub Desktop.
Save luuuis/25a1030327a6ff9713a5a6747ebb6154 to your computer and use it in GitHub Desktop.
Preços do mercado diário e do mecanismo de ajuste MIBEL
##
## Example usage:
##
sensor:
- platform: command_line
name: omie_daily_spot_avg_pt
command: "python3 /config/omie.py spot"
value_template: "{{ value_json.spot_prices_pt.avg / 1000 }}"
json_attributes:
- time
- header
- source
- spot_prices_pt
unit_of_measurement: 'EUR'
- platform: command_line
name: omie_daily_ajuste_avg_pt
command: "python3 /config/omie.py ajuste"
value_template: "{{ value_json.ajuste_prices_pt.avg / 1000 }}"
json_attributes:
- time
- header
- source
- ajuste_prices_pt
unit_of_measurement: 'EUR'
template:
sensor:
- unique_id: omie_daily_spot_hourly_pt
device_class: monetary
unit_of_measurement: 'EUR'
state_class: measurement
state: "{{ state_attr('sensor.omie_daily_spot_avg_pt', 'spot_prices_pt').hourly[now().hour]|float / 1000 }}"
attributes:
friendly_name: "OMIE preço horário do mercado diário (€/kWh)"
#!/usr/bin/env python3
import csv
import json
import statistics
import sys
from datetime import date, datetime
import requests
# Example usage:
#
# sensor:
# - platform: command_line
# name: omie_daily_spot_avg_pt
# command: "python3 /config/omie.py spot"
# value_template: "{{ value_json.spot_prices_pt.avg / 1000 }}"
# json_attributes:
# - time
# - header
# - source
# - spot_prices_pt
# unit_of_measurement: 'EUR'
# - platform: command_line
# name: omie_daily_ajuste_avg_pt
# command: "python3 /config/omie.py ajuste"
# value_template: "{{ value_json.ajuste_prices_pt.avg / 1000 }}"
# json_attributes:
# - time
# - header
# - source
# - ajuste_prices_pt
# unit_of_measurement: 'EUR'
def to_json(source, short_names):
with requests.get(source) as resp:
lines = resp.text.splitlines()
header = lines[0]
data = lines[2:]
reader = csv.reader(data, delimiter=';', skipinitialspace=True)
hourly = {row[0]: [float(row[i + 1].replace(',', '.')) for i in list(range(24))] for row in reader if row[0] != ''}
spot = {
'time': datetime.now().isoformat(),
'header': header,
'source': source,
}
spot.update({short_names[k] if k in short_names else k: {
'row': k,
'avg': round(statistics.mean(hourly[k]), 2),
'sum': round(sum(hourly[k]), 1),
'hourly': hourly[k]}
for k in hourly}
)
return spot
def spot_url(yy, MM, dd):
dd_MM_yy = f'{dd}_{MM}_{yy}'
return f'https://www.omie.es/sites/default/files/dados/AGNO_{yy}/MES_{MM}/TXT/INT_PBC_EV_H_1_{dd_MM_yy}_{dd_MM_yy}.TXT'
def ajuste_url(yy, MM, dd):
dd_MM_yy = f'{dd}_{MM}_{yy}'
return f'https://www.omie.es/sites/default/files/dados/AGNO_{yy}/MES_{MM}/TXT/INT_MAJ_EV_H_{dd_MM_yy}_{dd_MM_yy}.TXT'
def spot_price(fetch_date):
source = spot_url(fetch_date.year, str.zfill(str(fetch_date.month), 2), str.zfill(str(fetch_date.day), 2))
return to_json(source, {
"Energía total con bilaterales del mercado Ibérico (MWh)": 'energy_total_with_bilaterals',
"Energía total de compra sistema español (MWh)": 'energy_total_purchases_es',
"Energía total de compra sistema portugués (MWh)": 'energy_total_purchases_pt',
"Energía total de venta sistema español (MWh)": 'energy_total_sales_es',
"Energía total de venta sistema portugués (MWh)": 'energy_total_sales_pt',
"Energía total del mercado Ibérico (MWh)": 'energy_total',
"Exportación de España a Portugal (MWh)": 'energy_export_es_to_pt',
"Importación de España desde Portugal (MWh)": 'energy_import_es_from_pt',
"Precio marginal en el sistema español (EUR/MWh)": 'spot_prices_es',
"Precio marginal en el sistema portugués (EUR/MWh)": 'spot_prices_pt',
})
def ajuste_price(fetch_date):
source = ajuste_url(fetch_date.year, str.zfill(str(fetch_date.month), 2), str.zfill(str(fetch_date.day), 2))
return to_json(source, {
"Precio de ajuste en el sistema español (EUR/MWh)": 'ajuste_prices_es',
"Precio de ajuste en el sistema portugués (EUR/MWh)": 'ajuste_prices_pt',
"Energía horaria sujeta al MAJ a los consumidores MIBEL (MWh)": 'ajuste_energy',
"Cuantía unitaria del ajuste (EUR/MWh)": 'ajuste_quantity',
})
if __name__ == '__main__':
if len(sys.argv) not in [2, 3] or not sys.argv[1] in ['spot', 'ajuste']:
print('usage: omie.py <spot|ajuste> [ISO date]', file=sys.stderr)
sys.exit(1)
fetch_date = date.today() if len(sys.argv) == 2 else date.fromisoformat(sys.argv[2])
if sys.argv[1] == 'spot':
print(json.dumps(spot_price(fetch_date)))
if sys.argv[1] == 'ajuste':
print(json.dumps(ajuste_price(fetch_date)))
% omie.py ajuste 2022-09-15 | jq .
{
"time": "2023-02-09T13:36:36.662158",
"header": "OMIE - Mercado de electricidad;Fecha Emisión :15/09/2022 - 22:21;;15/09/2022;Precio definitivo horario del mecanismo de ajuste a los consumidores en el mercado (EUR/MWh);;;;",
"source": "https://www.omie.es/sites/default/files/dados/AGNO_2022/MES_09/TXT/INT_MAJ_EV_H_15_09_2022_15_09_2022.TXT",
"ajuste_prices_es": {
"row": "Precio de ajuste en el sistema español (EUR/MWh)",
"avg": 151,
"sum": 3623.9,
"hourly": [
180.07,
191.25,
194.86,
200.56,
203.62,
201.85,
189.74,
170.89,
156.3,
139.08,
128.4,
123.12,
117.35,
114.83,
116.48,
118.56,
118.91,
120.42,
128.35,
133.51,
132.79,
133.77,
146.61,
162.59
]
},
"ajuste_prices_pt": {
"row": "Precio de ajuste en el sistema portugués (EUR/MWh)",
"avg": 151,
"sum": 3623.9,
"hourly": [
180.07,
191.25,
194.86,
200.56,
203.62,
201.85,
189.74,
170.89,
156.3,
139.08,
128.4,
123.12,
117.35,
114.83,
116.48,
118.56,
118.91,
120.42,
128.35,
133.51,
132.79,
133.77,
146.61,
162.59
]
},
"Energía horaria sujeta al mecanismo de ajuste a los consumidores MIBEL (MWh)": {
"row": "Energía horaria sujeta al mecanismo de ajuste a los consumidores MIBEL (MWh)",
"avg": 20433.37,
"sum": 490400.9,
"hourly": [
16704.6,
15349,
14234.7,
13570.3,
13384.9,
13735.4,
15692.5,
18171.8,
19839.4,
22113.7,
23345.2,
24304.9,
25162.9,
25554.3,
25119.1,
24386.6,
23953.7,
23730.2,
23173.4,
22831.8,
23342.5,
23362.9,
20945,
18392.1
]
},
"ajuste_quantity": {
"row": "Cuantía unitaria del ajuste (EUR/MWh)",
"avg": 179.22,
"sum": 4301.3,
"hourly": [
179.22,
179.22,
179.22,
179.22,
179.22,
179.22,
179.22,
179.22,
179.22,
179.22,
179.22,
179.22,
179.22,
179.22,
179.22,
179.22,
179.22,
179.22,
179.22,
179.22,
179.22,
179.22,
179.22,
179.22
]
}
}
% omie.py spot 2022-03-15 | jq .
{
"time": "2023-02-09T13:35:58.258011",
"header": "OMIE - Mercado de electricidad;Fecha Emisión :14/03/2022 - 13:43;;15/03/2022;Precio del mercado diario (EUR/MWh);;;;",
"source": "https://www.omie.es/sites/default/files/dados/AGNO_2022/MES_03/TXT/INT_PBC_EV_H_1_15_03_2022_15_03_2022.TXT",
"spot_prices_es": {
"row": "Precio marginal en el sistema español (EUR/MWh)",
"avg": 249.66,
"sum": 5991.9,
"hourly": [
215.54,
211.15,
209.8,
209.79,
209.8,
210,
212.79,
242.73,
259.22,
259.22,
255,
255,
248.12,
247.63,
247.14,
253.67,
253.67,
253.67,
277.8,
297.01,
311.71,
304.19,
283.17,
264.11
]
},
"spot_prices_pt": {
"row": "Precio marginal en el sistema portugués (EUR/MWh)",
"avg": 249.66,
"sum": 5991.9,
"hourly": [
215.54,
211.15,
209.8,
209.79,
209.8,
210,
212.79,
242.73,
259.22,
259.22,
255,
255,
248.12,
247.63,
247.14,
253.67,
253.67,
253.67,
277.8,
297.01,
311.71,
304.19,
283.17,
264.11
]
},
"energy_total_purchases_es": {
"row": "Energía total de compra sistema español (MWh)",
"avg": 17050.49,
"sum": 409211.7,
"hourly": [
14439.4,
13883,
13958.5,
13775.3,
13713.6,
13709.2,
15339.1,
17439.5,
18619.9,
18851.8,
19255.2,
19089.1,
19301,
19687.9,
19122.5,
18430.6,
18032.8,
16822.4,
16423.7,
17761.6,
19588.4,
18912.9,
17633.7,
15420.6
]
},
"energy_total_sales_es": {
"row": "Energía total de venta sistema español (MWh)",
"avg": 21506.5,
"sum": 516156.1,
"hourly": [
19271.3,
19112.8,
19217,
19096.2,
18868.2,
18609.5,
18854.9,
20273,
21767.8,
22916,
23826.2,
23555.5,
24144,
24459.9,
24044.3,
24176.8,
23848.2,
22417.8,
21750,
21234.4,
23077.9,
22031.7,
20159,
19443.7
]
},
"energy_total_purchases_pt": {
"row": "Energía total de compra sistema portugués (MWh)",
"avg": 6151.96,
"sum": 147647,
"hourly": [
5508.7,
5811.4,
5710.9,
5639,
5446.9,
5414.9,
5067.2,
4778.4,
5392.4,
6280.5,
6626,
6734.2,
6896.7,
6684.2,
6479.1,
6588.4,
6428.4,
6378.4,
6349.7,
6600.9,
7267,
7064.7,
6557.5,
5941.5
]
},
"energy_total_sales_pt": {
"row": "Energía total de venta sistema portugués (MWh)",
"avg": 4125.21,
"sum": 99005,
"hourly": [
3913.8,
3818.6,
3689.4,
3555.1,
3575.3,
3797.6,
4048.4,
4441.9,
4741.5,
4713.3,
4552,
4317.8,
4103.7,
3962.2,
3607.3,
3385.2,
3156,
3183,
3423.4,
5528.1,
6177.5,
5932.3,
4322,
3059.6
]
},
"energy_total": {
"row": "Energía total del mercado Ibérico (MWh)",
"avg": 23202.45,
"sum": 556858.7,
"hourly": [
19948.1,
19694.4,
19669.4,
19414.3,
19160.5,
19124.1,
20406.3,
22217.9,
24012.3,
25132.3,
25881.2,
25823.3,
26197.7,
26372.1,
25601.6,
25019,
24461.2,
23200.8,
22773.4,
24362.5,
26855.4,
25977.6,
24191.2,
21362.1
]
},
"energy_total_with_bilaterals": {
"row": "Energía total con bilaterales del mercado Ibérico (MWh)",
"avg": 34719.51,
"sum": 833268.3,
"hourly": [
30567.4,
29568.3,
29186.9,
28742.5,
28441.7,
28632.7,
30704,
33901.7,
36316.5,
38045.3,
38478.2,
38406.4,
38772.9,
38307.3,
37602.5,
36803.1,
36044.7,
35697.5,
35495.2,
37809.4,
39606.5,
38575.4,
35480.2,
32082
]
},
"energy_import_es_from_pt": {
"row": "Importación de España desde Portugal (MWh)",
"avg": 0,
"sum": 0,
"hourly": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
]
},
"energy_export_es_to_pt": {
"row": "Exportación de España a Portugal (MWh)",
"avg": 2026.75,
"sum": 48642,
"hourly": [
1594.9,
1992.8,
2021.5,
2083.9,
1871.6,
1617.3,
1018.8,
336.5,
650.9,
1567.2,
2074,
2416.4,
2793,
2722,
2871.8,
3203.2,
3272.4,
3195.4,
2926.3,
1072.8,
1089.5,
1132.4,
2235.5,
2881.9
]
}
}
@jonferreira
Copy link

Boas!
Visto que os valores são atualizados uma vez por dia, há necessidade de o HA estar a atualizar o sensor a cada 60s?
Não sou muito de python mas pelo que entendo o que fazes é ler o TXT mas processar só a linha do dia e hora atual?

@luuuis
Copy link
Author

luuuis commented Feb 10, 2023

@jonferreira não é necessário, no entanto também não descobri maneira de (com o Command Line Sensor) actualizar só às 00:00. Por outro lado parece-me inofensivo que actualize com mais ou menos frequência, os valores não mudam ao longo do dia e o ficheiro parece-me estar "cached".

pelo que entendo o que fazes é ler o TXT mas processar só a linha do dia e hora atual?

Se reparares no value_template do sensor este está configurado para assumir o valor da média do dia. No entanto, os dados restantes do dia estão lá nos atributos. Exemplo para um sensor do preço horário:

template:
  sensor:
    - unique_id: omie_daily_spot_hourly_pt
      device_class: monetary
      unit_of_measurement: 'EUR'
      state_class: measurement
      state: "{{ state_attr('sensor.omie_daily_spot_avg_pt', 'spot_prices_pt').hourly[now().hour]|float / 1000 }}"
      attributes:
        friendly_name: "OMIE preço horário do mercado diário (€/kWh)"

https://gist.github.com/luuuis/25a1030327a6ff9713a5a6747ebb6154/88816e2a91b02c6015b97c5e9bbdcadb286562ce#file-configuration-yml-L25-L33

@jonferreira
Copy link

@luuuis pelo que entendo podes usar o scan_interval - https://www.home-assistant.io/integrations/sensor.command_line/#scan_interval

podes meter 3600 para ser de hora a hora por exemplo. desta forma reduzes drasticamente o trafego desnecessário a ir buscar dados estáticos todos os minutos.

deixo tambem a pergunta: faria sentido atualizar o sensor com os valores horários "reais" e depois ter um outro sensor com a média? - https://www.home-assistant.io/integrations/min_max/

desta forma ficamos com um grafico horario e um diario, por assim dizer?

@luuuis
Copy link
Author

luuuis commented Feb 10, 2023

Pode-se fazer isso @jonferreira, o problema é que não há forma de garantir que ele actualiza atempadamente à meia noite. Como podes ver aqui em casa actualizou às 00:00:59, com esse scan_interval abres a possibilidade de ele actualizar à 1 da manhã.

Home – Home Assistant 2023-02-10 16-30-16

Pode ser que no futuro eu dedique uns tempos a fazer disto uma integração que só actualiza uma vez por dia mas para já não me importo de gastar uns bytes uma vez por minuto e estes ficheiros estão com certeza "cached" no OMIE.

faria sentido atualizar o sensor com os valores horários "reais" e depois ter um outro sensor com a média?

Pode fazer sentido consoante a necessidade de cada um. Se reparares já actualizei os exemplos hoje de manhã e estão lá os sensores da média diária omie_daily_spot_avg_pt e o horário omie_daily_spot_hourly_pt. Com o https://github.com/RomRider/apexcharts-card por exemplo já consegue fazer gráficos com o valor horário até ao fim do dia usando somente os atributos do omie_daily_spot_avg_pt porque tem os valores futuros também.

Home Assistant - Home – Home Assistant 2023-02-10 16-35-31

Já para o HA gravar os dados no histórico e estatísticas necessitamos do sensor omie_daily_spot_hourly_pt com o valor horário . 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment