([^<]*)<\\/div>\\s*<\\/div>)?/g;\n\nconst parsed = [];\nfor (const m of html.matchAll(re)) {\n const index = Number(m[1]);\n const label = m[2].trim();\n const raw = (m[3] ?? '').trim() || null;\n const { value, unit, state, on } = parseValue(raw);\n const key = `${String(index).padStart(2,'0')}_${toKey(label)}`;\n parsed.push({ index, label, key, raw, value, unit, state, on });\n}\n\n// 3) Kompaktes Objekt + Einheiten-Mapping bauen\nconst flat = {};\nconst units = {};\nfor (const p of parsed) {\n flat[p.key] = (p.value ?? p.state ?? p.raw ?? null);\n if (p.unit) units[p.key] = p.unit;\n}\n\n// 4) Ein einziges Ergebnis-Item zurückgeben\nreturn [{ json: { flat, units, items: parsed } }];\n"
+ },
+ "type": "n8n-nodes-base.code",
+ "typeVersion": 2,
+ "position": [
+ -224,
+ 288
+ ],
+ "id": "509329e8-02f5-473f-a09c-f334bc441340",
+ "name": "transfer data to readable format"
+ },
+ {
+ "parameters": {
+ "url": "http://192.168.2.68:8093/v1/state/0_userdata.0.haus.heizung.pelletheizung.hot_water_temperature",
+ "sendQuery": true,
+ "queryParameters": {
+ "parameters": [
+ {
+ "name": "value",
+ "value": "={{ $('transfer data to readable format').item.json.flat['08_unbenutzt']"
+ }
+ ]
+ },
+ "sendHeaders": true,
+ "headerParameters": {
+ "parameters": [
+ {
+ "name": "value",
+ "value": "={{ $('transfer data to readable format').item.json.flat['08_unbenutzt'] }}"
+ }
+ ]
+ },
+ "options": {}
+ },
+ "type": "n8n-nodes-base.httpRequest",
+ "typeVersion": 4.2,
+ "position": [
+ 0,
+ 384
+ ],
+ "id": "ee3b68e3-7b85-41c8-9a2d-276e8bb8da17",
+ "name": "set Warmwasser Temperatur"
+ },
+ {
+ "parameters": {
+ "url": "http://192.168.2.68:8093/v1/state/0_userdata.0.haus.heizung.pelletheizung.heating_circuit_temperature",
+ "sendQuery": true,
+ "queryParameters": {
+ "parameters": [
+ {
+ "name": "value",
+ "value": "={{ $('transfer data to readable format').item.json.flat['03_unbenutzt'] }}"
+ }
+ ]
+ },
+ "sendHeaders": true,
+ "headerParameters": {
+ "parameters": [
+ {
+ "name": "value",
+ "value": "={{ $('transfer data to readable format').item.json.flat['03_unbenutzt'] }}"
+ }
+ ]
+ },
+ "options": {}
+ },
+ "type": "n8n-nodes-base.httpRequest",
+ "typeVersion": 4.2,
+ "position": [
+ 0,
+ 576
+ ],
+ "id": "5b95f25f-a896-46ef-a455-cb915a76b388",
+ "name": "set Heizkreis Temperatur"
+ },
+ {
+ "parameters": {
+ "url": "http://192.168.2.68:8093/v1/state/0_userdata.0.haus.heizung.pelletheizung.heat_pump_consumption",
+ "sendQuery": true,
+ "queryParameters": {
+ "parameters": [
+ {
+ "name": "value",
+ "value": "={{ $json.flat['16_Stromzahler_WP'] }}"
+ }
+ ]
+ },
+ "sendHeaders": true,
+ "headerParameters": {
+ "parameters": [
+ {
+ "name": "value",
+ "value": "={{ $json.flat['16_Stromzahler_WP'] }}"
+ }
+ ]
+ },
+ "options": {}
+ },
+ "type": "n8n-nodes-base.httpRequest",
+ "typeVersion": 4.2,
+ "position": [
+ 0,
+ 192
+ ],
+ "id": "52d65947-58f8-423d-a746-ba108d74dd06",
+ "name": "set Verbrauch Waermepumpe"
+ },
+ {
+ "parameters": {
+ "url": "http://192.168.2.68:8093/v1/state/0_userdata.0.haus.heizung.outer_temperature",
+ "sendQuery": true,
+ "queryParameters": {
+ "parameters": [
+ {
+ "name": "value",
+ "value": "={{ $json.flat['06_T_Aussen'] }}"
+ }
+ ]
+ },
+ "sendHeaders": true,
+ "headerParameters": {
+ "parameters": [
+ {
+ "name": "value",
+ "value": "={{ $json.flat['06_T_Aussen'] }}"
+ }
+ ]
+ },
+ "options": {}
+ },
+ "type": "n8n-nodes-base.httpRequest",
+ "typeVersion": 4.2,
+ "position": [
+ 0,
+ 0
+ ],
+ "id": "e895b3a4-620c-4623-9267-6cab2d353f50",
+ "name": "set outer temperature"
+ }
+ ],
+ "pinData": {},
+ "connections": {
+ "Schedule Trigger": {
+ "main": [
+ [
+ {
+ "node": "get Data from CMI Interface local",
+ "type": "main",
+ "index": 0
+ }
+ ]
+ ]
+ },
+ "get Data from CMI Interface local": {
+ "main": [
+ [
+ {
+ "node": "transfer data to readable format",
+ "type": "main",
+ "index": 0
+ }
+ ]
+ ]
+ },
+ "transfer data to readable format": {
+ "main": [
+ [
+ {
+ "node": "set Warmwasser Temperatur",
+ "type": "main",
+ "index": 0
+ },
+ {
+ "node": "set Verbrauch Waermepumpe",
+ "type": "main",
+ "index": 0
+ },
+ {
+ "node": "set Heizkreis Temperatur",
+ "type": "main",
+ "index": 0
+ },
+ {
+ "node": "set outer temperature",
+ "type": "main",
+ "index": 0
+ }
+ ]
+ ]
+ }
+ },
+ "active": true,
+ "settings": {
+ "executionOrder": "v1",
+ "timeSavedMode": "fixed",
+ "callerPolicy": "workflowsFromSameOwner",
+ "availableInMCP": false
+ },
+ "versionId": "ff580cc5-a6c7-49be-8ac9-7a607d4537ed",
+ "meta": {
+ "instanceId": "3cc6c4256e2bbdec1b3708c49dc3889c7266357f3e239651c157c2de760e6c65"
+ },
+ "id": "ygJYiiFM97WiWeY5",
+ "tags": [
+ {
+ "updatedAt": "2025-12-20T20:03:34.739Z",
+ "createdAt": "2025-12-20T20:03:34.739Z",
+ "id": "i5rtQijMRj2sx5Zj",
+ "name": "Heizung"
+ },
+ {
+ "updatedAt": "2025-12-20T19:56:59.512Z",
+ "createdAt": "2025-12-20T19:56:59.512Z",
+ "id": "9G8OthZJpXo6BPbV",
+ "name": "Smart Home"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/workflows/Heizung/Pelletheizung_ Abfrage Kessel.json b/workflows/Heizung/Pelletheizung_ Abfrage Kessel.json
new file mode 100644
index 0000000..6ecd2bc
--- /dev/null
+++ b/workflows/Heizung/Pelletheizung_ Abfrage Kessel.json
@@ -0,0 +1,195 @@
+{
+ "name": "Pelletheizung: Abfrage Kessel",
+ "nodes": [
+ {
+ "parameters": {
+ "url": "https://stokercloud.dk/v16bckbeta/dataout2/controllerdata2.php?screen=b1,0,b2,5,b3,4,b4,6,b5,12,b6,14,b7,15,b8,16,b9,9,b10,0,d1,3,d2,4,d3,0,d4,0,d5,0,d6,0,d7,0,d8,0,d9,0,d10,0,h1,2,h2,3,h3,4,h4,7,h5,8,h6,1,h7,5,h8,13,h9,0,h10,0,w1,2,w2,3,w3,9,w4,0,w5,0&token=958f4bcf6d8251da548e773176ca0925ff7840bdce7daeb8bcf72f00cf5201087fd760aeae882f66729695445feb8bbd55307f9279da03ae211ce9e4dd5229f7e950b3008574b55ea095001693fa7765fe09a1ab6553a3a8d8e70a4cb1916d43",
+ "options": {}
+ },
+ "type": "n8n-nodes-base.httpRequest",
+ "typeVersion": 4.2,
+ "position": [
+ -224,
+ 192
+ ],
+ "id": "ae5635a9-5b88-485d-8d46-b20bee634452",
+ "name": "get Values from Stokercloud"
+ },
+ {
+ "parameters": {
+ "url": "http://192.168.2.68:8093/v1/state/0_userdata.0.haus.heizung.pelletheizung.boiler_temperature",
+ "sendQuery": true,
+ "queryParameters": {
+ "parameters": [
+ {
+ "name": "value",
+ "value": "={{ $json.frontdata[1].value }}"
+ }
+ ]
+ },
+ "sendHeaders": true,
+ "headerParameters": {
+ "parameters": [
+ {
+ "name": "value",
+ "value": "={{ $json.frontdata[1].value }}"
+ }
+ ]
+ },
+ "options": {}
+ },
+ "type": "n8n-nodes-base.httpRequest",
+ "typeVersion": 4.2,
+ "position": [
+ 0,
+ 0
+ ],
+ "id": "23782057-3c0d-4a49-b475-d74abcc4a459",
+ "name": "set boiler temperature"
+ },
+ {
+ "parameters": {
+ "url": "http://192.168.2.68:8093/v1/state/0_userdata.0.haus.heizung.pelletheizung.boiler_power",
+ "sendQuery": true,
+ "queryParameters": {
+ "parameters": [
+ {
+ "name": "value",
+ "value": "={{ $json.boilerdata[1].value }}"
+ }
+ ]
+ },
+ "sendHeaders": true,
+ "headerParameters": {
+ "parameters": [
+ {
+ "name": "value",
+ "value": "={{ $json.boilerdata[1].value }}"
+ }
+ ]
+ },
+ "options": {}
+ },
+ "type": "n8n-nodes-base.httpRequest",
+ "typeVersion": 4.2,
+ "position": [
+ 0,
+ 192
+ ],
+ "id": "eaffbad5-8bb2-484a-8cd5-34fca3c97f23",
+ "name": "set boiler power"
+ },
+ {
+ "parameters": {
+ "rule": {
+ "interval": [
+ {
+ "field": "minutes"
+ }
+ ]
+ }
+ },
+ "type": "n8n-nodes-base.scheduleTrigger",
+ "typeVersion": 1.2,
+ "position": [
+ -448,
+ 192
+ ],
+ "id": "6f6781a6-95fa-4ad7-991d-deb66d86be90",
+ "name": "Trigger 5 minutes"
+ },
+ {
+ "parameters": {
+ "url": "http://192.168.2.68:8093/v1/state/0_userdata.0.haus.heizung.pelletheizung.boiler_power_kw",
+ "sendQuery": true,
+ "queryParameters": {
+ "parameters": [
+ {
+ "name": "value",
+ "value": "={{ $json.boilerdata[0].value }}"
+ }
+ ]
+ },
+ "sendHeaders": true,
+ "headerParameters": {
+ "parameters": [
+ {
+ "name": "value",
+ "value": "={{ $json.boilerdata[0].value }}"
+ }
+ ]
+ },
+ "options": {}
+ },
+ "type": "n8n-nodes-base.httpRequest",
+ "typeVersion": 4.2,
+ "position": [
+ 0,
+ 384
+ ],
+ "id": "7826f720-ad10-487c-95b3-6b21a74c2284",
+ "name": "set boiler power kw"
+ }
+ ],
+ "pinData": {},
+ "connections": {
+ "get Values from Stokercloud": {
+ "main": [
+ [
+ {
+ "node": "set boiler temperature",
+ "type": "main",
+ "index": 0
+ },
+ {
+ "node": "set boiler power",
+ "type": "main",
+ "index": 0
+ },
+ {
+ "node": "set boiler power kw",
+ "type": "main",
+ "index": 0
+ }
+ ]
+ ]
+ },
+ "Trigger 5 minutes": {
+ "main": [
+ [
+ {
+ "node": "get Values from Stokercloud",
+ "type": "main",
+ "index": 0
+ }
+ ]
+ ]
+ }
+ },
+ "active": true,
+ "settings": {
+ "executionOrder": "v1",
+ "timeSavedMode": "fixed",
+ "callerPolicy": "workflowsFromSameOwner",
+ "availableInMCP": false
+ },
+ "versionId": "4d76bfdb-5d2c-4eae-8d58-14d28cb18a7d",
+ "meta": {
+ "instanceId": "3cc6c4256e2bbdec1b3708c49dc3889c7266357f3e239651c157c2de760e6c65"
+ },
+ "id": "L5LZdEzKKQZWaHMd",
+ "tags": [
+ {
+ "updatedAt": "2025-12-20T20:03:34.739Z",
+ "createdAt": "2025-12-20T20:03:34.739Z",
+ "id": "i5rtQijMRj2sx5Zj",
+ "name": "Heizung"
+ },
+ {
+ "updatedAt": "2025-12-20T19:56:59.512Z",
+ "createdAt": "2025-12-20T19:56:59.512Z",
+ "id": "9G8OthZJpXo6BPbV",
+ "name": "Smart Home"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/workflows/Heizung/Pelletheizung_ Abfrage Verbrauch.json b/workflows/Heizung/Pelletheizung_ Abfrage Verbrauch.json
new file mode 100644
index 0000000..d6a872b
--- /dev/null
+++ b/workflows/Heizung/Pelletheizung_ Abfrage Verbrauch.json
@@ -0,0 +1,461 @@
+{
+ "name": "Pelletheizung: Abfrage Verbrauch",
+ "nodes": [
+ {
+ "parameters": {
+ "url": "https://stokercloud.dk/v16bckbeta/dataout2/controllerdata2.php?screen=b1,0,b2,5,b3,4,b4,6,b5,12,b6,14,b7,15,b8,16,b9,9,b10,0,d1,3,d2,4,d3,0,d4,0,d5,0,d6,0,d7,0,d8,0,d9,0,d10,0,h1,2,h2,3,h3,4,h4,7,h5,8,h6,1,h7,5,h8,13,h9,0,h10,0,w1,2,w2,3,w3,9,w4,0,w5,0&token=958f4bcf6d8251da548e773176ca0925ff7840bdce7daeb8bcf72f00cf5201087fd760aeae882f66729695445feb8bbd55307f9279da03ae211ce9e4dd5229f7e950b3008574b55ea095001693fa7765fe09a1ab6553a3a8d8e70a4cb1916d43",
+ "options": {}
+ },
+ "type": "n8n-nodes-base.httpRequest",
+ "typeVersion": 4.2,
+ "position": [
+ -224,
+ 288
+ ],
+ "id": "c09de7e8-760d-4716-a908-382d43c2258a",
+ "name": "HTTP Request"
+ },
+ {
+ "parameters": {
+ "chatId": "749279624",
+ "text": "=Der aktuelle Füllstand des Pelletsilos beträgt {{ $('HTTP Request').item.json.hopperdata[5].value }} kg. Der heutige Verbrauch liegt bei {{ $('HTTP Request').item.json.hopperdata[1].value }} kg.",
+ "additionalFields": {}
+ },
+ "type": "n8n-nodes-base.telegram",
+ "typeVersion": 1.2,
+ "position": [
+ 224,
+ 576
+ ],
+ "id": "953efaeb-f1e5-4515-b58a-46cbc6b72fbc",
+ "name": "Telegram",
+ "webhookId": "ddd87e24-21a8-4037-a549-8991f0c31d97",
+ "credentials": {
+ "telegramApi": {
+ "id": "EUy2hT71fSdnEr2w",
+ "name": "Telegram account"
+ }
+ },
+ "disabled": true
+ },
+ {
+ "parameters": {
+ "operation": "upsert",
+ "table": {
+ "__rl": true,
+ "value": "Pellets",
+ "mode": "list",
+ "cachedResultName": "Pellets"
+ },
+ "dataMode": "defineBelow",
+ "columnToMatchOn": "Datum",
+ "valueToMatchOn": "={{ $now.toFormat('yyyy-MM-dd')}}",
+ "valuesToSend": {
+ "values": [
+ {
+ "column": "Datum",
+ "value": "={{ $now.toFormat('yyyy-MM-dd')}}"
+ },
+ {
+ "column": "Fuellstand",
+ "value": "={{ $json.hopperdata[5].value }}"
+ },
+ {
+ "column": "Pellets Verbrauch [kg]",
+ "value": "={{ $json.hopperdata[1].value }}"
+ }
+ ]
+ },
+ "options": {}
+ },
+ "type": "n8n-nodes-base.mySql",
+ "typeVersion": 2.4,
+ "position": [
+ 0,
+ 576
+ ],
+ "id": "25651cad-8917-4aff-a0e7-9aff0dd9352f",
+ "name": "MySQL",
+ "credentials": {
+ "mySql": {
+ "id": "GvOnFzLTFlbKtgUM",
+ "name": "MySQL account - homelab"
+ }
+ }
+ },
+ {
+ "parameters": {
+ "url": "http://192.168.2.68:8093/v1/state/0_userdata.0.haus.heizung.pelletheizung.pellet_fuellstand_silo",
+ "sendQuery": true,
+ "queryParameters": {
+ "parameters": [
+ {
+ "name": "value",
+ "value": "={{ $json.hopperdata[5].value }}"
+ }
+ ]
+ },
+ "sendHeaders": true,
+ "headerParameters": {
+ "parameters": [
+ {
+ "name": "value",
+ "value": "={{ $json.hopperdata[5].value }}"
+ }
+ ]
+ },
+ "options": {}
+ },
+ "type": "n8n-nodes-base.httpRequest",
+ "typeVersion": 4.2,
+ "position": [
+ 0,
+ 384
+ ],
+ "id": "d365485b-573f-4a41-b139-81d64160cd58",
+ "name": "schreibe Füllstand Silo"
+ },
+ {
+ "parameters": {
+ "url": "http://192.168.2.68:8093/v1/state/0_userdata.0.haus.heizung.pelletheizung.pellet_verbrauch_tag",
+ "sendQuery": true,
+ "queryParameters": {
+ "parameters": [
+ {
+ "name": "value",
+ "value": "={{ $json.hopperdata[1].value }}"
+ }
+ ]
+ },
+ "sendHeaders": true,
+ "headerParameters": {
+ "parameters": [
+ {
+ "name": "value",
+ "value": "={{ $json.hopperdata[5].value }}"
+ }
+ ]
+ },
+ "options": {}
+ },
+ "type": "n8n-nodes-base.httpRequest",
+ "typeVersion": 4.2,
+ "position": [
+ 0,
+ 192
+ ],
+ "id": "2111a02b-c534-4d47-85c2-0df590f91cb4",
+ "name": "schreibe Verbrauch 24h"
+ },
+ {
+ "parameters": {
+ "rule": {
+ "interval": [
+ {
+ "triggerAtHour": 23,
+ "triggerAtMinute": 59
+ }
+ ]
+ }
+ },
+ "type": "n8n-nodes-base.scheduleTrigger",
+ "typeVersion": 1.2,
+ "position": [
+ -448,
+ 384
+ ],
+ "id": "6aa9d692-e5c7-488e-a9cd-c9999852fa59",
+ "name": "Trigger 23:59"
+ },
+ {
+ "parameters": {
+ "rule": {
+ "interval": [
+ {
+ "field": "minutes",
+ "minutesInterval": 30
+ }
+ ]
+ }
+ },
+ "type": "n8n-nodes-base.scheduleTrigger",
+ "typeVersion": 1.2,
+ "position": [
+ -448,
+ 192
+ ],
+ "id": "9f19dd5b-d172-4668-9325-829f8278fdec",
+ "name": "Trigger 30 minutes"
+ },
+ {
+ "parameters": {
+ "conditions": {
+ "options": {
+ "caseSensitive": true,
+ "leftValue": "",
+ "typeValidation": "loose",
+ "version": 2
+ },
+ "conditions": [
+ {
+ "id": "b00d73a4-b3aa-496e-9730-fb3110944925",
+ "leftValue": "={{ $('HTTP Request').item.json.hopperdata[5].value }}",
+ "rightValue": 1000,
+ "operator": {
+ "type": "number",
+ "operation": "lt"
+ }
+ }
+ ],
+ "combinator": "and"
+ },
+ "looseTypeValidation": true,
+ "options": {}
+ },
+ "type": "n8n-nodes-base.if",
+ "typeVersion": 2.2,
+ "position": [
+ 224,
+ 384
+ ],
+ "id": "a091b1e3-bad8-4e2a-9fa5-3892fa8eb3d9",
+ "name": "If1"
+ },
+ {
+ "parameters": {
+ "fromEmail": "pelletlager@scheidel.biz",
+ "toEmail": "michael.scheidel@scheidel.biz",
+ "subject": "=Es ist Zeit Pellets nachzubestellen. Stand: {{ $('HTTP Request').item.json.hopperdata[5].value }} kg",
+ "html": "=Der aktuelle Silostand liegt bei {{ $('HTTP Request').item.json.hopperdata[5].value }} kg. Es ist Zeit nachzubestllen",
+ "options": {}
+ },
+ "type": "n8n-nodes-base.emailSend",
+ "typeVersion": 2.1,
+ "position": [
+ 448,
+ 384
+ ],
+ "id": "7f87bdc8-a659-401a-9d92-8751587aded2",
+ "name": "Send email",
+ "webhookId": "3ea799df-e2df-4291-a530-7534fd6edd34",
+ "credentials": {
+ "smtp": {
+ "id": "wgI3pOhkySCL5ngP",
+ "name": "SMTP account"
+ }
+ }
+ },
+ {
+ "parameters": {
+ "url": "http://192.168.2.68:8093/v1/state/0_userdata.0.haus.heizung.pelletheizung.connection_status",
+ "sendQuery": true,
+ "queryParameters": {
+ "parameters": [
+ {
+ "name": "value",
+ "value": "={{ $json.notconnected }}"
+ }
+ ]
+ },
+ "sendHeaders": true,
+ "headerParameters": {
+ "parameters": [
+ {
+ "name": "value",
+ "value": "={{ $json.notconnected }}"
+ }
+ ]
+ },
+ "options": {}
+ },
+ "type": "n8n-nodes-base.httpRequest",
+ "typeVersion": 4.2,
+ "position": [
+ 0,
+ 0
+ ],
+ "id": "3859cbb8-e79d-4852-8dec-735d725e5c8e",
+ "name": "schreibe connection_staus"
+ },
+ {
+ "parameters": {
+ "conditions": {
+ "options": {
+ "caseSensitive": true,
+ "leftValue": "",
+ "typeValidation": "loose",
+ "version": 2
+ },
+ "conditions": [
+ {
+ "id": "d887854d-7feb-480e-8adc-d8352db92ef2",
+ "leftValue": "={{ $json.val }}",
+ "rightValue": 0,
+ "operator": {
+ "type": "number",
+ "operation": "notEquals"
+ }
+ }
+ ],
+ "combinator": "and"
+ },
+ "looseTypeValidation": true,
+ "options": {}
+ },
+ "type": "n8n-nodes-base.if",
+ "typeVersion": 2.2,
+ "position": [
+ 224,
+ 0
+ ],
+ "id": "4668bc29-c9f1-4820-980f-f0f999887da9",
+ "name": "If2"
+ },
+ {
+ "parameters": {
+ "chatId": "749279624",
+ "text": "=Die Netzverbindung zur Heizung ist unterbrochen!",
+ "additionalFields": {}
+ },
+ "type": "n8n-nodes-base.telegram",
+ "typeVersion": 1.2,
+ "position": [
+ 448,
+ 0
+ ],
+ "id": "741ca3bb-f78c-4027-ac72-4f9220b1bd91",
+ "name": "Telegram1",
+ "webhookId": "ddd87e24-21a8-4037-a549-8991f0c31d97",
+ "credentials": {
+ "telegramApi": {
+ "id": "EUy2hT71fSdnEr2w",
+ "name": "Telegram account"
+ }
+ }
+ }
+ ],
+ "pinData": {},
+ "connections": {
+ "HTTP Request": {
+ "main": [
+ [
+ {
+ "node": "MySQL",
+ "type": "main",
+ "index": 0
+ },
+ {
+ "node": "schreibe Füllstand Silo",
+ "type": "main",
+ "index": 0
+ },
+ {
+ "node": "schreibe Verbrauch 24h",
+ "type": "main",
+ "index": 0
+ },
+ {
+ "node": "schreibe connection_staus",
+ "type": "main",
+ "index": 0
+ }
+ ]
+ ]
+ },
+ "MySQL": {
+ "main": [
+ [
+ {
+ "node": "Telegram",
+ "type": "main",
+ "index": 0
+ }
+ ]
+ ]
+ },
+ "schreibe Füllstand Silo": {
+ "main": [
+ [
+ {
+ "node": "If1",
+ "type": "main",
+ "index": 0
+ }
+ ]
+ ]
+ },
+ "Trigger 23:59": {
+ "main": [
+ [
+ {
+ "node": "HTTP Request",
+ "type": "main",
+ "index": 0
+ }
+ ]
+ ]
+ },
+ "Trigger 30 minutes": {
+ "main": [
+ [
+ {
+ "node": "HTTP Request",
+ "type": "main",
+ "index": 0
+ }
+ ]
+ ]
+ },
+ "If1": {
+ "main": [
+ [
+ {
+ "node": "Send email",
+ "type": "main",
+ "index": 0
+ }
+ ]
+ ]
+ },
+ "schreibe connection_staus": {
+ "main": [
+ [
+ {
+ "node": "If2",
+ "type": "main",
+ "index": 0
+ }
+ ]
+ ]
+ },
+ "If2": {
+ "main": [
+ [
+ {
+ "node": "Telegram1",
+ "type": "main",
+ "index": 0
+ }
+ ]
+ ]
+ }
+ },
+ "active": true,
+ "settings": {
+ "executionOrder": "v1"
+ },
+ "versionId": "ef221069-21a2-4c44-b925-b20fb23cf4a4",
+ "meta": {
+ "templateCredsSetupCompleted": true,
+ "instanceId": "3cc6c4256e2bbdec1b3708c49dc3889c7266357f3e239651c157c2de760e6c65"
+ },
+ "id": "t3q9pyWyzAdiHiyl",
+ "tags": [
+ {
+ "updatedAt": "2025-12-20T19:56:59.512Z",
+ "createdAt": "2025-12-20T19:56:59.512Z",
+ "id": "9G8OthZJpXo6BPbV",
+ "name": "Smart Home"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/workflows/Heizung/Wärmepumpe_ Tagesverbrauch.json b/workflows/Heizung/Wärmepumpe_ Tagesverbrauch.json
new file mode 100644
index 0000000..d747c79
--- /dev/null
+++ b/workflows/Heizung/Wärmepumpe_ Tagesverbrauch.json
@@ -0,0 +1,576 @@
+{
+ "name": "Wärmepumpe: Tagesverbrauch",
+ "nodes": [
+ {
+ "parameters": {
+ "jsCode": "// INPUT: items = [{ json: { data: \"
...
\" } }]\n// OUTPUT: items = [{ json: { Adresse, Bezeichnung, Wert, Einheit, Waehrung, Raw, Key } }, ...]\n\n// kleine Helfer\nfunction slug(s) {\n return String(s)\n .normalize('NFD').replace(/[\\u0300-\\u036f]/g, '')\n .replace(/ä/g,'ae').replace(/ö/g,'oe').replace(/ü/g,'ue')\n .replace(/Ä/g,'Ae').replace(/Ö/g,'Oe').replace(/Ü/g,'Ue')\n .replace(/ß/g,'ss')\n .replace(/[^A-Za-z0-9]+/g,'_')\n .replace(/^_+|_+$/g,'')\n .toLowerCase();\n}\n\nfunction parseNumUnit(raw) {\n if (!raw) return { value: null, unit: null, currency: null };\n let t = raw.replace(/ /g, ' ').trim();\n\n // Währung vorne oder hinten (€, $, £)\n let currency = null;\n const curLead = t.match(/^[€$£]/);\n const curTrail = t.match(/[€$£]$/);\n if (curLead) { currency = curLead[0]; t = t.slice(1).trim(); }\n else if (curTrail) { currency = curTrail[0]; t = t.slice(0, -1).trim(); }\n\n // Zahl (Komma oder Punkt)\n const numMatch = t.match(/-?\\d+(?:[.,]\\d+)?/);\n const value = numMatch ? parseFloat(numMatch[0].replace(',', '.')) : null;\n const unit = numMatch ? (t.replace(numMatch[0], '').trim() || null) : null;\n\n return { value, unit, currency };\n}\n\n// 1) HTML einsammeln (idR nur ein Item)\nconst html = items.map(i => i.json?.data ?? i.json?.body ?? i.json?.html ?? '').join('\\n');\n\n// 2) VALUE-Blöcke parsen\nconst re = /
\\s*
([^<]+)<\\/div>\\s*
([^<]+)<\\/div>\\s*<\\/div>/g;\n\nconst rows = [];\nfor (const m of html.matchAll(re)) {\n const adresse = m[1].trim();\n const label = m[2].trim();\n const raw = m[3].trim();\n\n const { value, unit, currency } = parseNumUnit(raw);\n const key = slug(label);\n\n rows.push({\n Adresse: adresse,\n Bezeichnung: label,\n Wert: (value !== null ? value : raw), // Zahl bevorzugt, sonst Rohstring\n Einheit: unit || '',\n Waehrung: currency || '',\n Raw: raw,\n Key: key\n });\n}\n\n// 3) Als **einzelne Items** zurückgeben (ein Item pro Wert/Zeile)\nreturn rows.map(r => ({ json: r }));\n"
+ },
+ "type": "n8n-nodes-base.code",
+ "typeVersion": 2,
+ "position": [
+ 224,
+ 0
+ ],
+ "id": "05b8699b-62c3-4f52-9829-03ebba00f470",
+ "name": "Code in JavaScript"
+ },
+ {
+ "parameters": {
+ "jsCode": "// INPUT: 19 Items vom Parser (Adresse, Bezeichnung, Wert, Einheit, Waehrung, Key)\n// OUTPUT: 1 Item mit vielen Feldern: leistung, tageszaehlerstand, ...\n\nconst out = {};\nconst units = {}; // falls du Einheiten brauchst\n\nfor (const it of items) {\n const j = it.json;\n // Zahl bevorzugt, sonst Rohstring\n out[j.Key] = (j.Wert ?? j.Raw ?? null);\n if (j.Einheit) units[j.Key] = j.Einheit;\n if (j.Waehrung) units[j.Key] = (units[j.Key] ? units[j.Key] + ' ' : '') + j.Waehrung;\n}\n\n// Ein einziges Item zurückgeben\nreturn [{ json: { ...out, _units: units } }];\n"
+ },
+ "type": "n8n-nodes-base.code",
+ "typeVersion": 2,
+ "position": [
+ 448,
+ 0
+ ],
+ "id": "61d9d196-8224-4363-b46c-2186979f9d4e",
+ "name": "Code in JavaScript1"
+ },
+ {
+ "parameters": {
+ "rule": {
+ "interval": [
+ {
+ "field": "minutes"
+ }
+ ]
+ }
+ },
+ "type": "n8n-nodes-base.scheduleTrigger",
+ "typeVersion": 1.2,
+ "position": [
+ -224,
+ 96
+ ],
+ "id": "8c6654b8-560d-4126-96d4-372d2567e8e0",
+ "name": "Schedule Trigger"
+ },
+ {
+ "parameters": {
+ "url": "http://192.168.2.68:8093/v1/state/0_userdata.0.haus.heizung.waermepumpe.heat_pump_daily_consumption",
+ "sendQuery": true,
+ "queryParameters": {
+ "parameters": [
+ {
+ "name": "value",
+ "value": "={{ $('Code in JavaScript1').item.json.tageszahlerstand }}"
+ }
+ ]
+ },
+ "options": {}
+ },
+ "type": "n8n-nodes-base.httpRequest",
+ "typeVersion": 4.2,
+ "position": [
+ 896,
+ 0
+ ],
+ "id": "ab729e47-cce9-4cf0-a5b3-56c8e5c1def3",
+ "name": "update Tageszählerstand iobroker"
+ },
+ {
+ "parameters": {
+ "url": "http://192.168.2.186/INCLUDE/devpagex.cgi?pagex2=01055c07&_=1759570693948",
+ "authentication": "genericCredentialType",
+ "genericAuthType": "httpBasicAuth",
+ "sendQuery": true,
+ "queryParameters": {
+ "parameters": [
+ {
+ "name": "admin",
+ "value": "admin"
+ }
+ ]
+ },
+ "options": {}
+ },
+ "type": "n8n-nodes-base.httpRequest",
+ "typeVersion": 4.2,
+ "position": [
+ 0,
+ 0
+ ],
+ "id": "59028407-fb4b-4ee0-a539-3505cf2fffd3",
+ "name": "get Tageszählerstand WP",
+ "credentials": {
+ "httpBasicAuth": {
+ "id": "iJkXePPAceSyENTx",
+ "name": "CMI CAN Bus local"
+ }
+ }
+ },
+ {
+ "parameters": {
+ "url": "http://192.168.2.186/INCLUDE/devpagex.cgi?pagex2=01145c07&_=1759576852400",
+ "authentication": "genericCredentialType",
+ "genericAuthType": "httpBasicAuth",
+ "sendQuery": true,
+ "queryParameters": {
+ "parameters": [
+ {
+ "name": "admin",
+ "value": "admin"
+ }
+ ]
+ },
+ "options": {}
+ },
+ "type": "n8n-nodes-base.httpRequest",
+ "typeVersion": 4.2,
+ "position": [
+ 0,
+ 192
+ ],
+ "id": "545bac82-ea34-461d-955e-9ceebe4dc82a",
+ "name": "get Tageszählerstand PV WP",
+ "credentials": {
+ "httpBasicAuth": {
+ "id": "iJkXePPAceSyENTx",
+ "name": "CMI CAN Bus local"
+ }
+ }
+ },
+ {
+ "parameters": {
+ "jsCode": "// INPUT: items = [{ json: { data: \"
...
\" } }]\n// OUTPUT: items = [{ json: { Adresse, Bezeichnung, Wert, Einheit, Waehrung, Raw, Key } }, ...]\n\n// kleine Helfer\nfunction slug(s) {\n return String(s)\n .normalize('NFD').replace(/[\\u0300-\\u036f]/g, '')\n .replace(/ä/g,'ae').replace(/ö/g,'oe').replace(/ü/g,'ue')\n .replace(/Ä/g,'Ae').replace(/Ö/g,'Oe').replace(/Ü/g,'Ue')\n .replace(/ß/g,'ss')\n .replace(/[^A-Za-z0-9]+/g,'_')\n .replace(/^_+|_+$/g,'')\n .toLowerCase();\n}\n\nfunction parseNumUnit(raw) {\n if (!raw) return { value: null, unit: null, currency: null };\n let t = raw.replace(/ /g, ' ').trim();\n\n // Währung vorne oder hinten (€, $, £)\n let currency = null;\n const curLead = t.match(/^[€$£]/);\n const curTrail = t.match(/[€$£]$/);\n if (curLead) { currency = curLead[0]; t = t.slice(1).trim(); }\n else if (curTrail) { currency = curTrail[0]; t = t.slice(0, -1).trim(); }\n\n // Zahl (Komma oder Punkt)\n const numMatch = t.match(/-?\\d+(?:[.,]\\d+)?/);\n const value = numMatch ? parseFloat(numMatch[0].replace(',', '.')) : null;\n const unit = numMatch ? (t.replace(numMatch[0], '').trim() || null) : null;\n\n return { value, unit, currency };\n}\n\n// 1) HTML einsammeln (idR nur ein Item)\nconst html = items.map(i => i.json?.data ?? i.json?.body ?? i.json?.html ?? '').join('\\n');\n\n// 2) VALUE-Blöcke parsen\nconst re = /
\\s*
([^<]+)<\\/div>\\s*
([^<]+)<\\/div>\\s*<\\/div>/g;\n\nconst rows = [];\nfor (const m of html.matchAll(re)) {\n const adresse = m[1].trim();\n const label = m[2].trim();\n const raw = m[3].trim();\n\n const { value, unit, currency } = parseNumUnit(raw);\n const key = slug(label);\n\n rows.push({\n Adresse: adresse,\n Bezeichnung: label,\n Wert: (value !== null ? value : raw), // Zahl bevorzugt, sonst Rohstring\n Einheit: unit || '',\n Waehrung: currency || '',\n Raw: raw,\n Key: key\n });\n}\n\n// 3) Als **einzelne Items** zurückgeben (ein Item pro Wert/Zeile)\nreturn rows.map(r => ({ json: r }));\n"
+ },
+ "type": "n8n-nodes-base.code",
+ "typeVersion": 2,
+ "position": [
+ 224,
+ 192
+ ],
+ "id": "8f08ee8b-d3eb-4d7e-baa7-6fad114e40b0",
+ "name": "Code in JavaScript2"
+ },
+ {
+ "parameters": {
+ "jsCode": "// INPUT: 19 Items vom Parser (Adresse, Bezeichnung, Wert, Einheit, Waehrung, Key)\n// OUTPUT: 1 Item mit vielen Feldern: leistung, tageszaehlerstand, ...\n\nconst out = {};\nconst units = {}; // falls du Einheiten brauchst\n\nfor (const it of items) {\n const j = it.json;\n // Zahl bevorzugt, sonst Rohstring\n out[j.Key] = (j.Wert ?? j.Raw ?? null);\n if (j.Einheit) units[j.Key] = j.Einheit;\n if (j.Waehrung) units[j.Key] = (units[j.Key] ? units[j.Key] + ' ' : '') + j.Waehrung;\n}\n\n// Ein einziges Item zurückgeben\nreturn [{ json: { ...out, _units: units } }];\n"
+ },
+ "type": "n8n-nodes-base.code",
+ "typeVersion": 2,
+ "position": [
+ 448,
+ 192
+ ],
+ "id": "d1a4e45e-854b-4359-8da0-3e85f0c41dc4",
+ "name": "Code in JavaScript3"
+ },
+ {
+ "parameters": {
+ "operation": "upsert",
+ "table": {
+ "__rl": true,
+ "value": "Waermepumpe",
+ "mode": "list",
+ "cachedResultName": "Waermepumpe"
+ },
+ "dataMode": "defineBelow",
+ "columnToMatchOn": "Datum",
+ "valueToMatchOn": "={{ $now.toFormat('yyyy-MM-dd')}}",
+ "valuesToSend": {
+ "values": [
+ {
+ "column": "Tagesverbrauch",
+ "value": "={{ $json.tageszahlerstand }}"
+ }
+ ]
+ },
+ "options": {}
+ },
+ "type": "n8n-nodes-base.mySql",
+ "typeVersion": 2.5,
+ "position": [
+ 672,
+ 0
+ ],
+ "id": "797700c3-040b-4a27-b621-68e806b65730",
+ "name": "update Tagesverbrauch mysql",
+ "credentials": {
+ "mySql": {
+ "id": "GvOnFzLTFlbKtgUM",
+ "name": "MySQL account - homelab"
+ }
+ }
+ },
+ {
+ "parameters": {
+ "operation": "upsert",
+ "table": {
+ "__rl": true,
+ "value": "Waermepumpe",
+ "mode": "list",
+ "cachedResultName": "Waermepumpe"
+ },
+ "dataMode": "defineBelow",
+ "columnToMatchOn": "Datum",
+ "valueToMatchOn": "={{ $now.toFormat('yyyy-MM-dd')}}",
+ "valuesToSend": {
+ "values": [
+ {
+ "column": "Anteil PV",
+ "value": "={{ $json.tageszahlerstand }}"
+ }
+ ]
+ },
+ "options": {}
+ },
+ "type": "n8n-nodes-base.mySql",
+ "typeVersion": 2.5,
+ "position": [
+ 672,
+ 192
+ ],
+ "id": "7546d115-42c1-4cf9-ae9c-9030a86f9a7c",
+ "name": "update Tagesverbrauch PV mysql",
+ "credentials": {
+ "mySql": {
+ "id": "GvOnFzLTFlbKtgUM",
+ "name": "MySQL account - homelab"
+ }
+ }
+ },
+ {
+ "parameters": {
+ "operation": "select",
+ "table": {
+ "__rl": true,
+ "value": "Waermepumpe",
+ "mode": "list",
+ "cachedResultName": "Waermepumpe"
+ },
+ "where": {
+ "values": [
+ {
+ "column": "Datum",
+ "value": "={{ $now.toFormat('yyyy-MM-dd')}}"
+ }
+ ]
+ },
+ "options": {}
+ },
+ "type": "n8n-nodes-base.mySql",
+ "typeVersion": 2.5,
+ "position": [
+ 1344,
+ 96
+ ],
+ "id": "6c0fce95-29f5-4c9a-bd06-6ce474207b01",
+ "name": "Select rows from a table",
+ "credentials": {
+ "mySql": {
+ "id": "GvOnFzLTFlbKtgUM",
+ "name": "MySQL account - homelab"
+ }
+ }
+ },
+ {
+ "parameters": {
+ "operation": "update",
+ "table": {
+ "__rl": true,
+ "value": "Waermepumpe",
+ "mode": "list",
+ "cachedResultName": "Waermepumpe"
+ },
+ "dataMode": "defineBelow",
+ "columnToMatchOn": "Datum",
+ "valueToMatchOn": "={{ $now.toFormat('yyyy-MM-dd')}}",
+ "valuesToSend": {
+ "values": [
+ {
+ "column": "Anteil Netzbezug",
+ "value": "={{ $json['Anteil Netzbezug'] }}"
+ }
+ ]
+ },
+ "options": {}
+ },
+ "type": "n8n-nodes-base.mySql",
+ "typeVersion": 2.5,
+ "position": [
+ 1792,
+ 96
+ ],
+ "id": "b0e2962f-490d-4f17-be1c-0f8bbe80d510",
+ "name": "Update rows in a table",
+ "credentials": {
+ "mySql": {
+ "id": "GvOnFzLTFlbKtgUM",
+ "name": "MySQL account - homelab"
+ }
+ }
+ },
+ {
+ "parameters": {
+ "mode": "chooseBranch",
+ "useDataOfInput": 2
+ },
+ "type": "n8n-nodes-base.merge",
+ "typeVersion": 3.2,
+ "position": [
+ 1120,
+ 96
+ ],
+ "id": "e3aedba7-b520-40c7-b0ac-80c231bafbd8",
+ "name": "Merge"
+ },
+ {
+ "parameters": {
+ "jsCode": "// Verarbeite alle eingehenden Items\nreturn $input.all().map(item => {\n const tagesverbrauch = Number(item.json[\"Tagesverbrauch\"]) || 0;\n const anteilPV = Number(item.json[\"Anteil PV\"]) || 0;\n\n // Berechnung\n const anteilNetzbezug = tagesverbrauch - anteilPV;\n\n // Neues Feld hinzufügen\n item.json[\"Anteil Netzbezug\"] = anteilNetzbezug;\n\n return item;\n});\n"
+ },
+ "type": "n8n-nodes-base.code",
+ "typeVersion": 2,
+ "position": [
+ 1568,
+ 96
+ ],
+ "id": "b709fffd-4cf1-46ae-839e-fb72a4902b0b",
+ "name": "calculate Netzbezug"
+ },
+ {
+ "parameters": {
+ "url": "http://192.168.2.68:8093/v1/state/0_userdata.0.haus.heizung.waermepumpe.heat_pump_daily_consumption_pv",
+ "sendQuery": true,
+ "queryParameters": {
+ "parameters": [
+ {
+ "name": "value",
+ "value": "={{ $('Code in JavaScript3').item.json.tageszahlerstand }}"
+ }
+ ]
+ },
+ "options": {}
+ },
+ "type": "n8n-nodes-base.httpRequest",
+ "typeVersion": 4.2,
+ "position": [
+ 896,
+ 192
+ ],
+ "id": "a0db8fee-4d48-49b0-a329-80c90783e530",
+ "name": "update Tagesverbrauch PV"
+ },
+ {
+ "parameters": {
+ "url": "http://192.168.2.68:8093/v1/state/0_userdata.0.haus.heizung.waermepumpe.heat_pump_daily_consumption_power",
+ "sendQuery": true,
+ "queryParameters": {
+ "parameters": [
+ {
+ "name": "value",
+ "value": "={{ $('calculate Netzbezug').item.json['Anteil Netzbezug'] }}"
+ }
+ ]
+ },
+ "options": {}
+ },
+ "type": "n8n-nodes-base.httpRequest",
+ "typeVersion": 4.2,
+ "position": [
+ 2016,
+ 96
+ ],
+ "id": "6dcc484c-e75a-46b2-9049-87a4e48d2d1d",
+ "name": "update Netzbezug"
+ }
+ ],
+ "pinData": {},
+ "connections": {
+ "Code in JavaScript": {
+ "main": [
+ [
+ {
+ "node": "Code in JavaScript1",
+ "type": "main",
+ "index": 0
+ }
+ ]
+ ]
+ },
+ "Code in JavaScript1": {
+ "main": [
+ [
+ {
+ "node": "update Tagesverbrauch mysql",
+ "type": "main",
+ "index": 0
+ }
+ ]
+ ]
+ },
+ "Schedule Trigger": {
+ "main": [
+ [
+ {
+ "node": "get Tageszählerstand WP",
+ "type": "main",
+ "index": 0
+ },
+ {
+ "node": "get Tageszählerstand PV WP",
+ "type": "main",
+ "index": 0
+ }
+ ]
+ ]
+ },
+ "get Tageszählerstand WP": {
+ "main": [
+ [
+ {
+ "node": "Code in JavaScript",
+ "type": "main",
+ "index": 0
+ }
+ ]
+ ]
+ },
+ "get Tageszählerstand PV WP": {
+ "main": [
+ [
+ {
+ "node": "Code in JavaScript2",
+ "type": "main",
+ "index": 0
+ }
+ ]
+ ]
+ },
+ "Code in JavaScript2": {
+ "main": [
+ [
+ {
+ "node": "Code in JavaScript3",
+ "type": "main",
+ "index": 0
+ }
+ ]
+ ]
+ },
+ "Code in JavaScript3": {
+ "main": [
+ [
+ {
+ "node": "update Tagesverbrauch PV mysql",
+ "type": "main",
+ "index": 0
+ }
+ ]
+ ]
+ },
+ "update Tagesverbrauch mysql": {
+ "main": [
+ [
+ {
+ "node": "update Tageszählerstand iobroker",
+ "type": "main",
+ "index": 0
+ }
+ ]
+ ]
+ },
+ "Select rows from a table": {
+ "main": [
+ [
+ {
+ "node": "calculate Netzbezug",
+ "type": "main",
+ "index": 0
+ }
+ ]
+ ]
+ },
+ "Update rows in a table": {
+ "main": [
+ [
+ {
+ "node": "update Netzbezug",
+ "type": "main",
+ "index": 0
+ }
+ ]
+ ]
+ },
+ "update Tageszählerstand iobroker": {
+ "main": [
+ [
+ {
+ "node": "Merge",
+ "type": "main",
+ "index": 0
+ }
+ ]
+ ]
+ },
+ "update Tagesverbrauch PV mysql": {
+ "main": [
+ [
+ {
+ "node": "update Tagesverbrauch PV",
+ "type": "main",
+ "index": 0
+ }
+ ]
+ ]
+ },
+ "Merge": {
+ "main": [
+ [
+ {
+ "node": "Select rows from a table",
+ "type": "main",
+ "index": 0
+ }
+ ]
+ ]
+ },
+ "calculate Netzbezug": {
+ "main": [
+ [
+ {
+ "node": "Update rows in a table",
+ "type": "main",
+ "index": 0
+ }
+ ]
+ ]
+ },
+ "update Tagesverbrauch PV": {
+ "main": [
+ [
+ {
+ "node": "Merge",
+ "type": "main",
+ "index": 1
+ }
+ ]
+ ]
+ }
+ },
+ "active": true,
+ "settings": {
+ "executionOrder": "v1"
+ },
+ "versionId": "8b467f30-717c-41e3-9051-236e31116740",
+ "meta": {
+ "templateCredsSetupCompleted": true,
+ "instanceId": "3cc6c4256e2bbdec1b3708c49dc3889c7266357f3e239651c157c2de760e6c65"
+ },
+ "id": "bKlJd68Ba0ZWBnNS",
+ "tags": [
+ {
+ "updatedAt": "2025-12-20T20:03:34.739Z",
+ "createdAt": "2025-12-20T20:03:34.739Z",
+ "id": "i5rtQijMRj2sx5Zj",
+ "name": "Heizung"
+ },
+ {
+ "updatedAt": "2025-12-20T19:56:59.512Z",
+ "createdAt": "2025-12-20T19:56:59.512Z",
+ "id": "9G8OthZJpXo6BPbV",
+ "name": "Smart Home"
+ }
+ ]
+}
\ No newline at end of file