The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"name": "An\u00e1lise OMIE - Melhor Fixo Auto",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"triggerAtHour": 6
}
]
}
},
"id": "node-schedule",
"name": "Diariamente",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [
0,
300
]
},
{
"parameters": {
"jsCode": "// Gera a lista de URLs OMIE para os \u00faltimos 30 dias\nconst dias = 30;\nconst hoje = new Date();\nconst items = [];\n\nfor (let i = dias; i >= 0; i--) {\n const d = new Date(hoje);\n d.setDate(d.getDate() - i);\n const ano = d.getFullYear();\n const mes = String(d.getMonth() + 1).padStart(2, '0');\n const dia = String(d.getDate()).padStart(2, '0');\n items.push({\n json: {\n url: `https://www.omie.es/en/file-download?parents=marginalpdbcpt&filename=marginalpdbcpt_${ano}${mes}${dia}.1`\n }\n });\n}\n\nreturn items;"
},
"id": "node-gerar-urls",
"name": "Gerar URLs OMIE",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
220,
300
]
},
{
"parameters": {
"url": "={{ $json.url }}",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "User-Agent",
"value": "Mozilla/5.0"
},
{
"name": "Referer",
"value": "https://www.omie.es/"
}
]
},
"options": {
"allowUnauthorizedCerts": true,
"response": {
"response": {
"responseFormat": "text"
}
},
"timeout": 15000
}
},
"id": "node-http-omie",
"name": "HTTP Request OMIE",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
440,
300
],
"continueOnFail": true
},
{
"parameters": {
"jsCode": "// Agrega os 31 ficheiros OMIE num \u00fanico item com a m\u00e9dia\nconst todosPrecos = [];\n\nfor (const item of $input.all()) {\n const texto = item.json.data;\n if (!texto || typeof texto !== 'string') continue;\n for (const linha of texto.split('\\n')) {\n const partes = linha.trim().split(';');\n // Formato OMIE: ANO;MES;DIA;HORA;PRECO_PT;PRECO_ES\n if (partes.length >= 5 && /^\\d{4}$/.test(partes[0].trim())) {\n const preco = parseFloat(partes[4].replace(',', '.'));\n if (!isNaN(preco)) todosPrecos.push(preco);\n }\n }\n}\n\nif (todosPrecos.length === 0) {\n return [{ json: { erro: 'Sem dados OMIE dispon\u00edveis' } }];\n}\n\nconst media = todosPrecos.reduce((a, b) => a + b, 0) / todosPrecos.length;\n\nreturn [{\n json: {\n media_omie_mwh: media,\n num_precos: todosPrecos.length\n }\n}];"
},
"id": "node-agregar-omie",
"name": "Agregar OMIE",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
660,
300
]
},
{
"parameters": {
"url": "https://huggingface.co/spaces/tiagofelicia/simulador-tarifarios-eletricidade/resolve/main/data/csv/Tarifarios_fixos.csv",
"options": {
"response": {
"response": {
"responseFormat": "text"
}
},
"timeout": 30000
}
},
"id": "node-http-csv",
"name": "HTTP Request CSV Tarif\u00e1rios",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
880,
300
],
"continueOnFail": false
},
{
"parameters": {
"jsCode": "// \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\n// \u2551 \u2699\ufe0f CONFIGURA\u00c7\u00c3O \u2551\n// \u2551 S\u00f3 precisas de editar esta sec\u00e7\u00e3o \u2551\n// \u255a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255d\n\nconst CONFIG = {\n\n // \u2500\u2500 Consumo e contrato \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n consumo_kwh: 700, // kWh/m\u00eas\n dias: 30, // dias do per\u00edodo de fatura\u00e7\u00e3o\n potencia_kva: 6.90, // kVA contratados (filtra tarif\u00e1rios do CSV)\n ciclo: \"Simples\", // \"Simples\" | \"Bi-hor\u00e1rio\" | \"Tri-hor\u00e1rio\"\n\n // \u2500\u2500 Tarif\u00e1rio FIXO \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // null \u2192 escolhe automaticamente o mais barato do CSV do Tiago Fel\u00edcia\n // {...} \u2192 usa estes valores directamente (ignora o CSV)\n //\n // ATEN\u00c7\u00c3O: os valores do CSV j\u00e1 incluem TAR (tar_incluida = true na maioria).\n // Se colocares valores manuais, usa os valores FINAIS da tua fatura\n // (ou seja, com TAR e TSE j\u00e1 inclu\u00eddas), e coloca tar_ja_incluida: true.\n //\n // Exemplo manual:\n // fixo_manual: {\n // nome: \"G9 | Vantagem+\",\n // energia_kwh: 0.1348, // valor bruto do CSV (inclui TAR + TSE)\n // potencia_dia: 0.4498, // valor bruto do CSV (inclui TAR)\n // tar_en_incluida: true,\n // tar_pot_incluida: true,\n // tse_incluida: true,\n // },\n fixo_manual: null,\n\n // \u2500\u2500 Filtros para escolha autom\u00e1tica do melhor fixo \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // (irrelevante se fixo_manual estiver preenchido)\n // Usa string vazia \"\" para ignorar esse filtro.\n filtros: {\n segmento: \"Residencial\", // \"Residencial\" | \"Empresarial\" | \"\"\n faturacao: \"eletr\u00f3nica\", // palavra parcial (ex: \"eletr\u00f3nica\", \"papel\")\n pagamento: \"D\u00e9bito\", // palavra parcial (ex: \"D\u00e9bito\", \"Multibanco\")\n },\n\n // \u2500\u2500 Tarif\u00e1rio INDEXADO (OMIE) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Valores espec\u00edficos do contrato indexado.\n // A TAR e TSE s\u00e3o SEMPRE adicionadas por cima no indexado (n\u00e3o est\u00e3o inclu\u00eddas).\n indexado: {\n nome: \"G9 | Smart Index\",\n // Margem do comercializador em \u20ac/kWh (G9_CGS + G9_AC do contrato)\n margem_kwh: 0.0150,\n // Fator de perdas de rede (G9_FA \u2014 tipicamente entre 1.0 e 1.20)\n // Verifica no teu contrato. G9 usa ~1.16 no per\u00edodo de inverno.\n // Se n\u00e3o souberes, usa 1.0 para estimativa conservadora.\n fator_perdas: 1.0,\n },\n\n // \u2500\u2500 Tarifas reguladas ERSE 2026 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Atualizar anualmente em Janeiro.\n // Fonte: https://www.tiagofelicia.pt/tarifas-acesso-redes.html\n tar: {\n energia_kwh: 0.0607, // \u20ac/kWh \u2014 tarifa simples BTN\n potencia_dia: 0.3436, // \u20ac/dia \u2014 para 6.9 kVA (alterar se mudares de pot\u00eancia)\n },\n\n};\n\n// \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\n// \u2551 N\u00c3O \u00c9 NECESS\u00c1RIO EDITAR ABAIXO DAQUI \u2551\n// \u255a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255d\n\n// Constantes reguladas ERSE 2026 (n\u00e3o mudam a meio do ano)\nconst TSE = 0.0026; // \u20ac/kWh \u2014 financiamento Tarifa Social Electricidade\n\nconst r4 = (v) => Math.round(v * 10000) / 10000;\nconst r2 = (v) => Math.round(v * 100) / 100;\n\n// \u2500\u2500 Normaliza\u00e7\u00e3o de texto para compara\u00e7\u00f5es \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst norm = (s) => (s || '')\n .toLowerCase()\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .trim();\n\n// \u2500\u2500 Parser CSV robusto (lida com campos entre aspas) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nfunction parseCSVLine(linha) {\n const cols = [];\n let cur = '';\n let inQ = false;\n for (const ch of linha) {\n if (ch === '\"') { inQ = !inQ; }\n else if (ch === ',' && !inQ) { cols.push(cur.trim()); cur = ''; }\n else { cur += ch; }\n }\n cols.push(cur.trim());\n return cols;\n}\n\nconst parseBool = (v) => {\n const s = (v || '').toLowerCase().trim();\n return s === 'true' || s === 'sim' || s === '1';\n};\nconst parseNum = (v) => parseFloat((v || '0').replace(',', '.')) || 0;\n\n// \u2500\u2500 Leitura dos dados dos n\u00f3s anteriores \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst omieData = $('Agregar OMIE').first().json;\nif (omieData.erro) {\n return [{ json: { erro: omieData.erro } }];\n}\n\nconst mediaOmie_MWh = omieData.media_omie_mwh; // \u20ac/MWh\nconst mediaOmie_kWh = mediaOmie_MWh / 1000; // \u20ac/kWh\nconst csvTexto = $input.first().json.data;\n\n// \u2500\u2500 Parse do CSV e c\u00e1lculo do melhor fixo \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// L\u00f3gica id\u00eantica ao simulador do Tiago Fel\u00edcia (calculos.js):\n//\n// 1. L\u00ea preco_energia_simples e preco_potencia_dia do CSV (valores brutos)\n// 2. Se tar_incluida_energia=true \u2192 energia_comercial = bruto - TAR_en\n// Se tar_incluida_energia=false \u2192 energia_comercial = bruto\n// 3. energia_final = energia_comercial + TAR_en + (tse_incluida ? 0 : TSE)\n// 4. Mesmo processo para pot\u00eancia\n// 5. Custo = energia_final * consumo + potencia_final * dias\n//\nfunction obterTarifarios(csvTexto) {\n const linhas = csvTexto.split('\\n').map(l => l.trim()).filter(Boolean);\n if (linhas.length < 2) throw new Error('CSV vazio ou inv\u00e1lido');\n\n // Mapear cabe\u00e7alho \u2192 \u00edndice de coluna\n const cab = parseCSVLine(linhas[0]).map(c => c.replace(/\"/g, '').trim().toLowerCase());\n const col = (nome) => cab.findIndex(c => c.includes(nome.toLowerCase()));\n\n // \u00cdndices das colunas relevantes (nomes do CSV do Tiago Fel\u00edcia)\n const C = {\n comercializador: col('comercializador'),\n nome: col('nome'),\n tipo: col('tipo'),\n ciclo: col('opcao_horaria'),\n potKva: col('potencia_kva'),\n energia: col('preco_energia_simples'),\n potDia: col('preco_potencia_dia'),\n tarEnIncl: col('tar_incluida_energia'),\n tarPotIncl: col('tar_incluida_potencia'),\n tseIncl: col('financiamento_tse'),\n segmento: col('segmento'),\n faturacao: col('faturacao'),\n pagamento: col('pagamento'),\n descFatura: col('desconto_fatura'),\n };\n\n const cicloChave = norm(CONFIG.ciclo).split('-')[0].split(' ')[0]; // \"simples\", \"bi\", \"tri\"\n\n const fixos = [];\n\n for (let i = 1; i < linhas.length; i++) {\n const cols = parseCSVLine(linhas[i]);\n if (cols.length < 10) continue;\n\n const tipo = (cols[C.tipo] || '').replace(/\"/g, '').trim();\n const ciclo = norm(cols[C.ciclo] || '');\n const potKva = parseNum(cols[C.potKva]);\n const segmento = norm(cols[C.segmento] || '');\n const faturacao = norm(cols[C.faturacao] || '');\n const pagamento = norm(cols[C.pagamento] || '');\n\n // \u2500\u2500 Filtros obrigat\u00f3rios \u2500\u2500\n if (norm(tipo) !== 'fixo') continue;\n if (Math.abs(potKva - CONFIG.potencia_kva) > 0.1) continue;\n if (!ciclo.includes(cicloChave)) continue;\n\n // \u2500\u2500 Filtros opcionais \u2500\u2500\n const f = CONFIG.filtros;\n if (f.segmento === 'Residencial' && !segmento.includes('domestico')) continue;\n if (f.segmento === 'Empresarial' && !segmento.includes('nao domestico') && !segmento.includes('nao-domestico')) continue;\n if (f.faturacao && !faturacao.includes(norm(f.faturacao))) continue;\n if (f.pagamento && !pagamento.includes(norm(f.pagamento))) continue;\n\n // \u2500\u2500 Leitura dos pre\u00e7os brutos \u2500\u2500\n const energiaBruta = parseNum(cols[C.energia]);\n const potDiaBruta = parseNum(cols[C.potDia]);\n if (energiaBruta <= 0 || potDiaBruta <= 0) continue;\n\n const tarEnIncl = parseBool(cols[C.tarEnIncl]);\n const tarPotIncl = parseBool(cols[C.tarPotIncl]);\n const tseIncl = parseBool(cols[C.tseIncl]);\n\n // \u2500\u2500 Normaliza\u00e7\u00e3o exacta (igual ao simulador) \u2500\u2500\n // Extrai componente comercial (sem TAR)\n const energiaComercial = tarEnIncl\n ? energiaBruta - CONFIG.tar.energia_kwh\n : energiaBruta;\n\n const potComercial = tarPotIncl\n ? potDiaBruta - CONFIG.tar.potencia_dia\n : potDiaBruta;\n\n // Re-adiciona TAR regulada + TSE se n\u00e3o inclu\u00edda\n const energiaFinal = energiaComercial + CONFIG.tar.energia_kwh + (tseIncl ? 0 : TSE);\n const potFinal = potComercial + CONFIG.tar.potencia_dia;\n\n // Desconto de fatura (se existir)\n const descFatura = parseNum(cols[C.descFatura] || '0');\n const descTotal = descFatura * (CONFIG.dias / 30); // proporcional\n\n const custoEnergia = energiaFinal * CONFIG.consumo_kwh;\n const custoPot = potFinal * CONFIG.dias;\n const custoTotal = custoEnergia + custoPot - descTotal;\n\n fixos.push({\n comercializador: (cols[C.comercializador] || '').replace(/\"/g, '').trim(),\n nome: (cols[C.nome] || '').replace(/\"/g, '').trim(),\n energia_kwh: r4(energiaFinal),\n potencia_dia: r4(potFinal),\n energia_comercial_kwh: r4(energiaComercial),\n pot_comercial_dia: r4(potComercial),\n desconto_mes: descFatura,\n custo_estimado: r2(custoTotal),\n tar_en_incl: tarEnIncl,\n tar_pot_incl: tarPotIncl,\n tse_incl: tseIncl,\n });\n }\n\n if (fixos.length === 0) {\n throw new Error(\n `Nenhum tarif\u00e1rio fixo encontrado para ${CONFIG.potencia_kva} kVA / ` +\n `${CONFIG.ciclo} com filtros: ${JSON.stringify(CONFIG.filtros)}`\n );\n }\n\n fixos.sort((a, b) => a.custo_estimado - b.custo_estimado);\n return fixos;\n}\n\n// \u2500\u2500 Obter melhor fixo \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nlet melhorFixo;\nlet fonte;\n\nif (CONFIG.fixo_manual) {\n // Manual: normaliza da mesma forma\n const m = CONFIG.fixo_manual;\n const tarEnIncl = m.tar_en_incluida !== false;\n const tarPotIncl = m.tar_pot_incluida !== false;\n const tseIncl = m.tse_incluida !== false;\n\n const energiaComercial = tarEnIncl ? m.energia_kwh - CONFIG.tar.energia_kwh : m.energia_kwh;\n const potComercial = tarPotIncl ? m.potencia_dia - CONFIG.tar.potencia_dia : m.potencia_dia;\n const energiaFinal = energiaComercial + CONFIG.tar.energia_kwh + (tseIncl ? 0 : TSE);\n const potFinal = potComercial + CONFIG.tar.potencia_dia;\n\n melhorFixo = {\n nome: m.nome,\n comercializador: '',\n energia_kwh: r4(energiaFinal),\n potencia_dia: r4(potFinal),\n custo_estimado: r2(energiaFinal * CONFIG.consumo_kwh + potFinal * CONFIG.dias),\n };\n fonte = 'manual';\n} else {\n let todos;\n try {\n todos = obterTarifarios(csvTexto);\n } catch (e) {\n return [{ json: { erro: e.message } }];\n }\n melhorFixo = todos[0];\n fonte = 'automatico (CSV Tiago Fel\u00edcia)';\n}\n\n// \u2500\u2500 C\u00e1lculo do custo indexado \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// L\u00f3gica do simulador para G9 Smart Index (e equivalentes):\n// pre\u00e7o_kwh = OMIE_\u20ac/kWh * fator_perdas + margem + TAR_energia + TSE\n// custo = pre\u00e7o_kwh * consumo + TAR_potencia * dias\n//\n// A TAR e TSE s\u00e3o SEMPRE adicionadas no indexado (tar_e_incl = false no CSV)\n// O fator_perdas compensa as perdas de rede (varia ~1.10-1.20 conforme contrato)\n//\nconst precoKwhIndexado = (\n mediaOmie_kWh * CONFIG.indexado.fator_perdas\n + CONFIG.indexado.margem_kwh\n + CONFIG.tar.energia_kwh\n + TSE\n);\nconst custoIndexado = (\n CONFIG.consumo_kwh * precoKwhIndexado\n + CONFIG.dias * CONFIG.tar.potencia_dia\n);\n\n// \u2500\u2500 Break-even (a partir de que OMIE o fixo \u00e9 mais barato) \u2500\u2500\u2500\u2500\u2500\n//\n// Resolve: custo_fixo = custo_indexado\n// melhorFixo.custo = consumo * (OMIE_kWh * perdas + margem + TAR + TSE) + dias * TAR_pot\n// OMIE_kWh_breakeven = (custo_fixo/consumo - margem - TAR - TSE) / perdas\n//\nconst custoFixo = melhorFixo.custo_estimado;\nconst breakeven_kWh = (\n (custoFixo - CONFIG.dias * CONFIG.tar.potencia_dia) / CONFIG.consumo_kwh\n - CONFIG.indexado.margem_kwh\n - CONFIG.tar.energia_kwh\n - TSE\n) / CONFIG.indexado.fator_perdas;\nconst breakeven_MWh = r2(breakeven_kWh * 1000);\n\nconst poupanca = r2(Math.abs(custoFixo - custoIndexado));\nconst fixoMaisBarato = custoFixo <= r2(custoIndexado);\nconst recomendacao = fixoMaisBarato ? melhorFixo.nome : CONFIG.indexado.nome;\n\n// \u2500\u2500 Resumo formatado \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst data = new Date().toLocaleDateString('pt-PT');\nconst maisBaratoLabel = fixoMaisBarato\n ? `\ud83c\udfc6 FIXO mais barato \u2014 poupa ${poupanca}\u20ac`\n : `\ud83c\udfc6 INDEXADO mais barato \u2014 poupa ${poupanca}\u20ac`;\n\nlet resumo = `\ud83d\udcca *AN\u00c1LISE OMIE* (${data})\\n`;\nresumo += `\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\\n\\n`;\nresumo += `\u26a1 *MERCADO OMIE (\u00faltimos 30 dias):*\\n`;\nresumo += `\u2022 M\u00e9dia: *${r2(mediaOmie_MWh)} \u20ac/MWh*\\n`;\nresumo += `\u2022 Break-even: ${breakeven_MWh} \u20ac/MWh\\n\\n`;\nresumo += `\ud83d\udd12 *MELHOR FIXO (${fonte}):*\\n`;\nresumo += `\u2022 ${melhorFixo.nome}\\n`;\nresumo += `\u2022 Energia: ${melhorFixo.energia_kwh} \u20ac/kWh | Pot\u00eancia: ${melhorFixo.potencia_dia} \u20ac/dia\\n`;\nresumo += `\u2022 Custo estimado: *${custoFixo}\u20ac*\\n\\n`;\nresumo += `\ud83d\udcc8 *INDEXADO (${CONFIG.indexado.nome}):*\\n`;\nresumo += `\u2022 Pre\u00e7o kWh: ${r4(precoKwhIndexado)} \u20ac/kWh\\n`;\nresumo += `\u2022 Custo estimado: *${r2(custoIndexado)}\u20ac*\\n\\n`;\nresumo += `\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\\n`;\nresumo += `\ud83d\udca1 *${maisBaratoLabel}*\\n`;\nresumo += ` Recomenda\u00e7\u00e3o: *${recomendacao}*`;\n\nreturn [{\n json: {\n data_analise: data,\n media_omie_eur_mwh: r2(mediaOmie_MWh),\n breakeven_eur_mwh: breakeven_MWh,\n omie_acima_breakeven: mediaOmie_MWh > breakeven_MWh,\n // Melhor fixo\n melhor_fixo_nome: melhorFixo.nome,\n melhor_fixo_comercializador: melhorFixo.comercializador || '',\n melhor_fixo_fonte: fonte,\n melhor_fixo_energia_kwh: melhorFixo.energia_kwh,\n melhor_fixo_potencia_dia: melhorFixo.potencia_dia,\n custo_melhor_fixo_eur: custoFixo,\n // Indexado\n indexado_nome: CONFIG.indexado.nome,\n indexado_preco_kwh: r4(precoKwhIndexado),\n custo_indexado_eur: r2(custoIndexado),\n // Compara\u00e7\u00e3o\n poupanca_eur: poupanca,\n recomendacao: recomendacao,\n fixo_mais_barato: fixoMaisBarato,\n num_precos_omie: omieData.num_precos,\n resumo,\n }\n}];"
},
"id": "node-calculos",
"name": "C\u00e1lculos",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1100,
300
]
},
{
"parameters": {
"method": "POST",
"url": "https://example.com/webhook",
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "content",
"value": "={{ $json.resumo }}"
}
]
},
"options": {}
},
"id": "node-notificacao",
"name": "Notifica\u00e7\u00e3o",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
1320,
300
]
}
],
"connections": {
"Diariamente": {
"main": [
[
{
"node": "Gerar URLs OMIE",
"type": "main",
"index": 0
}
]
]
},
"Gerar URLs OMIE": {
"main": [
[
{
"node": "HTTP Request OMIE",
"type": "main",
"index": 0
}
]
]
},
"HTTP Request OMIE": {
"main": [
[
{
"node": "Agregar OMIE",
"type": "main",
"index": 0
}
]
]
},
"Agregar OMIE": {
"main": [
[
{
"node": "HTTP Request CSV Tarif\u00e1rios",
"type": "main",
"index": 0
}
]
]
},
"HTTP Request CSV Tarif\u00e1rios": {
"main": [
[
{
"node": "C\u00e1lculos",
"type": "main",
"index": 0
}
]
]
},
"C\u00e1lculos": {
"main": [
[
{
"node": "Notifica\u00e7\u00e3o",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
},
"tags": []
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Análise OMIE - Melhor Fixo Auto. Uses httpRequest. Scheduled trigger; 7 nodes.
Source: https://github.com/pmpbaptista/indexado-vs-fixo/blob/a8bfa7e2470bc81a5c1332deab7fe4ae62b81970/n8n/analise_omie.json — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
As n8n instances scale, teams often lose track of sub-workflows—who uses them, where they are referenced, and whether they can be safely updated. This leads to inefficiencies like unnecessary copies o
This workflow is an improvement of this workflow by Greg Brzezinka.
N8N-Workflow-Github-Manager. Uses github, httpRequest, n8n. Scheduled trigger; 38 nodes.
This workflow uses KlickTipp community nodes, available for self-hosted n8n instances only.
This workflow acts as an automated engagement bot. It sends a Direct Message (DM) with a link or resource to any follower who replies to your post with a specific target keyword.