-
-
Save luuuis/25a1030327a6ff9713a5a6747ebb6154 to your computer and use it in GitHub Desktop.
homeassistant: | |
customize: | |
sensor.omie_daily_spot_pt: | |
device_class: monetary | |
state_class: measurement | |
sensor.omie_daily_ajuste_pt: | |
device_class: monetary | |
state_class: measurement | |
sensor: | |
- platform: command_line | |
unique_id: omie_daily_spot_pt | |
name: omie_daily_spot_pt | |
command: "python3 /config/omie.py spot" | |
value_template: "{{ value_json.spot_price_pt_hourly[now().hour] }}" | |
unit_of_measurement: 'EUR/MWh' | |
json_attributes: | |
- row | |
- header | |
- source | |
- spot_price_pt_day_average | |
- spot_price_pt_hourly | |
- platform: command_line | |
name: omie_daily_ajuste_pt | |
unique_id: omie_daily_ajuste_pt | |
command: "python3 /config/omie.py ajuste" | |
value_template: "{{ value_json.ajuste_price_pt_hourly[now().hour] }}" | |
unit_of_measurement: 'EUR/MWh' | |
json_attributes: | |
- row | |
- header | |
- source | |
- ajuste_price_pt_day_average | |
- ajuste_price_pt_hourly | |
- platform: command_line | |
unique_id: omie_tomorrow_spot_pt | |
name: omie_tomorrow_spot_pt | |
command: "python3 /config/omie.py spot {{ (today_at()+timedelta(days=1)).date().isoformat() }}" | |
scan_interval: 3600 | |
value_template: > | |
{% if value != '' %} | |
{{ value_json.spot_price_pt_hourly[now().hour] }} | |
{% else %} | |
{{ 'unavailable' }} | |
{% endif %} | |
unit_of_measurement: 'EUR/MWh' | |
json_attributes: | |
- row | |
- header | |
- source | |
- spot_price_pt_day_average | |
- spot_price_pt_hourly | |
- platform: command_line | |
name: omie_tomorrow_ajuste_pt | |
unique_id: omie_tomorrow_ajuste_pt | |
command: "python3 /config/omie.py ajuste {{ (today_at()+timedelta(days=1)).date().isoformat() }}" | |
scan_interval: 3600 | |
value_template: "{{ value_json.ajuste_price_pt_hourly[now().hour] }}" | |
unit_of_measurement: 'EUR/MWh' | |
json_attributes: | |
- row | |
- header | |
- source | |
- ajuste_price_pt_day_average | |
- ajuste_price_pt_hourly |
#!/usr/bin/env python3 | |
import csv | |
import json | |
import statistics | |
import sys | |
from datetime import date, datetime | |
import requests | |
def to_dict(source, fetch_date, short_names): | |
with requests.get(source) as resp: | |
if resp.status_code == 404: | |
return None | |
lines = resp.text.splitlines() | |
header = lines[0] | |
data = lines[2:] | |
reader = csv.reader(data, delimiter=';', skipinitialspace=True) | |
rows = {row[0]: [float(row[i + 1].replace(',', '.')) for i in list(range(24))] for row in reader if row[0] != ''} | |
file_data = { | |
'header': header, | |
'fetched': datetime.now().isoformat(), | |
'market_date': fetch_date.isoformat(), | |
'source': source, | |
} | |
for k in rows: | |
hourly = rows[k] | |
if k in short_names: | |
# hourly & daily avg/sum | |
key = short_names[k] | |
suffix, daily = ['average', round(statistics.mean(hourly), 2)] if "(EUR/MWh)" in k else ['total', round(sum(hourly), 1)] | |
file_data.update({ | |
f'{key}_day_{suffix}': daily, | |
f'{key}_hourly': hourly, | |
}) | |
else: | |
# unprocessed: | |
file_data.update({k: hourly}) | |
return file_data | |
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' | |
# _daily_total | |
# _daily_average | |
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_dict(source, fetch_date, { | |
"Energía total con bilaterales del mercado Ibérico (MWh)": 'energy_with_bilaterals_es_pt', | |
"Energía total de compra sistema español (MWh)": 'energy_purchases_es', | |
"Energía total de compra sistema portugués (MWh)": 'energy_purchases_pt', | |
"Energía total de venta sistema español (MWh)": 'energy_sales_es', | |
"Energía total de venta sistema portugués (MWh)": 'energy_sales_pt', | |
"Energía total del mercado Ibérico (MWh)": 'energy_es_pt', | |
"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_price_es', | |
"Precio marginal en el sistema portugués (EUR/MWh)": 'spot_price_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_dict(source, fetch_date, { | |
"Precio de ajuste en el sistema español (EUR/MWh)": 'ajuste_price_es', | |
"Precio de ajuste en el sistema portugués (EUR/MWh)": 'ajuste_price_pt', | |
"Energía horaria sujeta al MAJ a los consumidores MIBEL (MWh)": 'ajuste_energy', | |
"Energía horaria sujeta al mecanismo de ajuste 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': | |
spot = spot_price(fetch_date) | |
if spot is not None: | |
print(json.dumps(spot)) | |
if sys.argv[1] == 'ajuste': | |
ajuste = ajuste_price(fetch_date) | |
if ajuste is not None: | |
print(json.dumps(ajuste)) |
@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?