-
-
Save luuuis/25a1030327a6ff9713a5a6747ebb6154 to your computer and use it in GitHub Desktop.
## | |
## 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 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)"
@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?
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ã.
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.
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 . 👍
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?