Boas pessoas estou a tentar obter a media de valores do mercado OMIE no ciclo de faturação para depois usar em outros sensore para no fim calcular custo de energia no mercado indexado para depois tomar decições de manter ou mudar.
Antes de mais eu sei que existe a integração OMIE mas tem um pequeno snão recentemente tive aguns reboots a maquina e os sensores ficaram sem dados necessarios para obter o desejavel. Estava a usar query sql para obter a media de valores entre datas mas a ausencia de alguns valores gera dados errados.
Estou a utilizar AI para me facilitar a vida 
Neste momento estou a usar os ficheiros da OMIE para gerar a informação mais correta mas estou a obter um valor sobre o preço de ‘amanha’ errado, desconfio que seja pelo factor das 23h.

site: tiagofelicia.pt
21/02/2026 até 07/03/2026

site: tiagofelicia.pt
21/02/2026 até 08/03/2026

do mesmo flow se verificar o dia isolado para ‘amanha’ o valor esta certo:

flow:
[
{
"id": "inj_range_001",
"type": "inject",
"z": "fd173bdc0d418401",
"name": "run range",
"props": [
{
"p": "startDate",
"v": "2026-02-21",
"vt": "str"
},
{
"p": "endDate",
"v": "2026-03-07",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"x": 160,
"y": 1900,
"wires": [
[
"fn_build_range_001"
]
]
},
{
"id": "fn_build_range_001",
"type": "function",
"z": "fd173bdc0d418401",
"name": "build date range",
"func": "function buildUrl(d){\n const [y,m,dd] = d.split('-');\n const s = `${dd}_${m}_${y}`;\n return `https://www.omie.es/sites/default/files/dados/AGNO_${y}/MES_${m}/TXT/INT_PBC_EV_H_1_${s}_${s}.TXT`;\n}\n\nfunction formatDateLisbon(date) {\n return new Intl.DateTimeFormat('en-CA', {\n timeZone: 'Europe/Lisbon',\n year: 'numeric',\n month: '2-digit',\n day: '2-digit'\n }).format(date);\n}\n\nfunction addDays(date, days) {\n const d = new Date(date);\n d.setDate(d.getDate() + days);\n return d;\n}\n\nconst startDateStr = msg.startDate;\nconst endDateStr = msg.endDate;\n\nif (!startDateStr || !endDateStr) {\n node.error(\"Faltam startDate e/ou endDate no msg.payload\");\n return null;\n}\n\nconst startDate = new Date(`${startDateStr}T00:00:00`);\nconst endDate = new Date(`${endDateStr}T00:00:00`);\n\nif (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) {\n node.error(\"Datas inválidas. Usa o formato YYYY-MM-DD\");\n return null;\n}\n\nif (startDate > endDate) {\n node.error(\"startDate não pode ser maior que endDate\");\n return null;\n}\n\nconst items = [];\nlet current = new Date(startDate);\n\nwhile (current <= endDate) {\n const today = formatDateLisbon(current);\n const tomorrow = formatDateLisbon(addDays(current, 1));\n\n items.push({\n today_date: today,\n tomorrow_date: tomorrow,\n today_url: buildUrl(today),\n tomorrow_url: buildUrl(tomorrow)\n });\n\n current.setDate(current.getDate() + 1);\n}\n\nmsg.payload = items;\nmsg.parts = undefined;\nreturn msg;",
"outputs": 1,
"timeout": "",
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 360,
"y": 1900,
"wires": [
[
"split_range_001"
]
]
},
{
"id": "split_range_001",
"type": "split",
"z": "fd173bdc0d418401",
"name": "split dates",
"splt": "\\n",
"spltType": "str",
"arraySplt": 1,
"arraySpltType": "len",
"stream": false,
"addname": "",
"property": "payload",
"x": 340,
"y": 1940,
"wires": [
[
"fn_prepare_today_001"
]
]
},
{
"id": "fn_prepare_today_001",
"type": "function",
"z": "fd173bdc0d418401",
"name": "prepare today request",
"func": "msg.today_date = msg.payload.today_date;\nmsg.tomorrow_date = msg.payload.tomorrow_date;\nmsg.today_url = msg.payload.today_url;\nmsg.tomorrow_url = msg.payload.tomorrow_url;\nmsg.url = msg.today_url;\nreturn msg;",
"outputs": 1,
"timeout": "",
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 380,
"y": 1980,
"wires": [
[
"http_today_001"
]
]
},
{
"id": "http_today_001",
"type": "http request",
"z": "fd173bdc0d418401",
"name": "fetch today",
"method": "GET",
"ret": "txt",
"paytoqs": "ignore",
"url": "",
"tls": "",
"persist": false,
"proxy": "",
"insecureHTTPParser": false,
"authType": "",
"senderr": false,
"headers": [],
"x": 350,
"y": 2020,
"wires": [
[
"fn_store_today_001"
]
]
},
{
"id": "fn_store_today_001",
"type": "function",
"z": "fd173bdc0d418401",
"name": "store today raw",
"func": "msg.today_raw = msg.payload;\nmsg.url = msg.tomorrow_url;\nreturn msg;",
"outputs": 1,
"timeout": "",
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 360,
"y": 2060,
"wires": [
[
"http_tomorrow_001"
]
]
},
{
"id": "http_tomorrow_001",
"type": "http request",
"z": "fd173bdc0d418401",
"name": "fetch tomorrow",
"method": "GET",
"ret": "txt",
"paytoqs": "ignore",
"url": "",
"tls": "",
"persist": false,
"proxy": "",
"insecureHTTPParser": false,
"authType": "",
"senderr": false,
"headers": [],
"x": 360,
"y": 2100,
"wires": [
[
"fn_parse_pair_001"
]
]
},
{
"id": "fn_parse_pair_001",
"type": "function",
"z": "fd173bdc0d418401",
"name": "parse today + tomorrow",
"func": "function parseOMIE(text) {\n if (!text || typeof text !== 'string') return [];\n\n const lines = text.split('\\n').map(l => l.trim()).filter(l => l);\n const dataLines = lines.slice(2);\n const series = {};\n\n for (const line of dataLines) {\n const cols = line.split(';').map(c => c.trim());\n const name = cols[0];\n if (!name) continue;\n\n const values = [];\n for (let i = 1; i < cols.length; i++) {\n if (!cols[i]) continue;\n const val = parseFloat(cols[i].replace(',', '.'));\n if (!isNaN(val)) values.push(val);\n }\n\n if (values.length > 0) series[name] = values;\n }\n\n const keys = Object.keys(series);\n const ptKey = keys.find(k => k.toLowerCase().includes('portugu'));\n return ptKey ? series[ptKey] : [];\n}\n\nfunction mean(arr) {\n if (!arr || arr.length === 0) return null;\n return Math.round((arr.reduce((a, b) => a + b, 0) / arr.length) * 100) / 100;\n}\n\nconst today_pt = parseOMIE(msg.today_raw);\nconst tomorrow_pt = parseOMIE(msg.payload);\n\nconst today_lisbon_pt = [...today_pt.slice(4), ...tomorrow_pt.slice(0, 4)];\nconst tomorrow_lisbon_pt = tomorrow_pt.slice(4);\n\nmsg.payload = {\n today_date: msg.today_date,\n tomorrow_date: msg.tomorrow_date,\n today_url: msg.today_url,\n tomorrow_url: msg.tomorrow_url,\n today_pt: today_pt,\n tomorrow_pt: tomorrow_pt,\n OMIE_today_avg_pt: mean(today_pt),\n OMIE_tomorrow_avg_pt: mean(tomorrow_pt),\n today_avg_pt: mean(today_lisbon_pt),\n tomorrow_avg_pt: mean(tomorrow_lisbon_pt)\n};\n\nreturn msg;",
"outputs": 1,
"timeout": "",
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 390,
"y": 2140,
"wires": [
[
"join_results_001"
]
]
},
{
"id": "join_results_001",
"type": "join",
"z": "fd173bdc0d418401",
"name": "join results",
"mode": "auto",
"build": "array",
"property": "payload",
"propertyType": "msg",
"key": "topic",
"joiner": "\\n",
"joinerType": "str",
"useparts": true,
"accumulate": false,
"timeout": "",
"count": "",
"reduceRight": false,
"reduceExp": "",
"reduceInit": "",
"reduceInitType": "",
"reduceFixup": "",
"x": 350,
"y": 2180,
"wires": [
[
"fn_summary_001"
]
]
},
{
"id": "fn_summary_001",
"type": "function",
"z": "fd173bdc0d418401",
"name": "summary",
"func": "const rows = msg.payload || [];\n\nfunction mean(values) {\n const valid = values.filter(v => typeof v === 'number' && !isNaN(v));\n if (valid.length === 0) return null;\n return Math.round((valid.reduce((a, b) => a + b, 0) / valid.length) * 100) / 100;\n}\n\nmsg.payload = {\n total_days: rows.length,\n start_date: rows.length ? rows[0].today_date : null,\n end_date: rows.length ? rows[rows.length - 1].today_date : null,\n\n period_avg: {\n OMIE_today_avg_pt: mean(rows.map(r => r.OMIE_today_avg_pt)),\n OMIE_tomorrow_avg_pt: mean(rows.map(r => r.OMIE_tomorrow_avg_pt)),\n today_avg_pt: mean(rows.map(r => r.today_avg_pt)),\n tomorrow_avg_pt: mean(rows.map(r => r.tomorrow_avg_pt))\n },\n\n results: rows\n};\n\nreturn msg;",
"outputs": 1,
"timeout": "",
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 340,
"y": 2220,
"wires": [
[
"debug_results_001"
]
]
},
{
"id": "debug_results_001",
"type": "debug",
"z": "fd173bdc0d418401",
"name": "results",
"active": true,
"tosidebar": true,
"complete": "payload",
"targetType": "msg",
"x": 510,
"y": 2220,
"wires": []
}
]
@luuuis uma ajudinha 




