Die Grundidee war die vielen vorhandenen Temperatursensoren mit in eine Feuerwarnung einzubinden. Dabei möchte ich explizit darauf hinweisen, das dies auf keinen Fall die Rauchmelder ersetzen kann. Jedoch habe ich persönlich nicht in jedem Raum bzw. Außen eine Rauchmelder und die Erweiterung kostet schließlich nix.
Test mit den Wandthermostaten vs. Feuer im Kamin haben gezeigt das durch die Auswertung der zeitlichen Differenz viel schneller ein sicherer Alarm ausgelöst werden kann. Beim Starten des Feuers kam die Meldung schon unter 45 Grad, runtergebrannt dagegen kam nichts. Test mit Shellys, die in Unterputzdosen verbaut sind, lösten jedoch beim Einschalten der Verbraucher zu früh aus. Bei denen klappt die Differenzberechnung nicht.
Testet es bitte, wenn dadurch auch nur ein Brand schneller erkannt wird, hat es sich gelohnt.
Code: Alles auswählen
[
{
"id": "2066ed3659d168e5",
"type": "subflow",
"name": "diff payload",
"info": "Berechnung der Differenz pro Zeit, aufgeteilt nach Topic und Datenpunkt.\r\nAusgabe von msg.diff",
"category": "",
"in": [
{
"x": 40,
"y": 80,
"wires": [
{
"id": "38433d81cca8bfc6"
}
]
}
],
"out": [
{
"x": 340,
"y": 80,
"wires": [
{
"id": "38433d81cca8bfc6",
"port": 0
}
]
}
],
"env": [
{
"name": "msg",
"type": "str",
"value": "payload",
"ui": {
"icon": "font-awesome/fa-angle-left",
"label": {
"de": "Datenpunkt msg."
},
"type": "input",
"opts": {
"types": [
"str",
"env"
]
}
}
}
],
"meta": {},
"color": "#FDD0A2",
"icon": "node-red/function.svg",
"status": {
"x": 340,
"y": 140,
"wires": [
{
"id": "1a2b3d68e0c03267",
"port": 0
}
]
}
},
{
"id": "38433d81cca8bfc6",
"type": "function",
"z": "2066ed3659d168e5",
"name": "diff payload",
"func": "// V 1.0 Copyleft M. Henke\n\nvar name = \"diffTime\";\nvar lastFL = context.get(name) || {};\n\nconst msgName = env.get(\"msg\") || {};\nvar pp = RED.util.getObjectProperty(msg, msgName);\nif (!pp) {\n node.error(\"unbekannt: msg.\" + msgName, msg);\n return;\n}\n\nif (!msg.ts) {\n node.warn(\"msg.ts fehlt\");\n return;\n}\nif (!msg.topic) {\n node.warn(\"msg.topic fehlt\");\n return;\n}\nif (typeof pp != 'number') {\n node.warn(\"msg.\" + msgName + \" keine Zahl \" + pp);\n return;\n}\nvar nSet = {};\nnSet.payload = pp;\nnSet.time = new Date(msg.ts);\nlet sDP = msg.topic + \".\" + msgName;\n\nvar nFlow = {};\nnFlow.Akt = nSet;\n\nvar last = lastFL[sDP];\nif (last) {\n // newMsg.ssss = last.Start.payload;\n nFlow.Start = last.Start;\n}\nelse {\n nFlow.Start = nSet;\n lastFL[sDP] = nFlow;\n context.set(name, lastFL);\n return;\n}\n\nvar tDiff = (nSet.time.getTime() - last.Akt.time.getTime());\nif (tDiff < 1000)\n return;\nlastFL[sDP] = nFlow;\ncontext.set(name, lastFL);\n\nvar newMsg = msg;\nnewMsg.diff = {};\n\nvar out = {};\nvar diff = nSet.payload - last.Akt.payload;\n\nout.plLast = last.Akt.payload;\nout.pl = diff;\nout.time = tDiff;\nif (tDiff) {\n out.Sec = diff * 1000 / tDiff;\n out.Min = diff * 60 * 1000 / tDiff;\n out.h = diff * 60 * 60 * 1000 / tDiff;\n}\nnewMsg.diff.Akt = out;\n\nvar out2 = {};\ndiff = pp - last.Start.payload;\ntDiff = (nSet.time.getTime() - last.Start.time.getTime());\nout2.plLast = last.Start.payload;\nout2.pl = diff;\nout2.time = tDiff;\nif (tDiff) {\n out2.Sec = diff * 1000 / tDiff;\n out2.Min = diff * 60 * 1000 / tDiff;\n out2.h = diff * 60 * 60 * 1000 / tDiff;\n}\nnewMsg.diff.Start = out2;\n\nconst text = sDP + \" \" + pp + \" diff: \" + (Math.round(msg.diff.Akt.Min * 1000) / 1000);\nnode.status({ fill: \"blue\", shape: \"dot\", text: text });\nreturn newMsg;\n",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 190,
"y": 80,
"wires": [
[]
]
},
{
"id": "1a2b3d68e0c03267",
"type": "status",
"z": "2066ed3659d168e5",
"name": "",
"scope": [
"38433d81cca8bfc6"
],
"x": 180,
"y": 140,
"wires": [
[]
]
},
{
"id": "a76412665ae32774",
"type": "subflow:2066ed3659d168e5",
"z": "d85b59ff755cd0af",
"name": "",
"x": 490,
"y": 1460,
"wires": [
[
"3040f728f81e7dc0"
]
]
},
{
"id": "a9ea5444b9af1635",
"type": "switch",
"z": "d85b59ff755cd0af",
"name": ">= 21",
"property": "payload",
"propertyType": "msg",
"rules": [
{
"t": "gte",
"v": "21",
"vt": "num"
}
],
"checkall": "true",
"repair": false,
"outputs": 1,
"x": 470,
"y": 1420,
"wires": [
[
"a76412665ae32774"
]
]
},
{
"id": "3040f728f81e7dc0",
"type": "switch",
"z": "d85b59ff755cd0af",
"name": ">= 3.5 Grad pro Minute",
"property": "diff.Akt.Min",
"propertyType": "msg",
"rules": [
{
"t": "gte",
"v": "3.5",
"vt": "num"
}
],
"checkall": "true",
"repair": false,
"outputs": 1,
"x": 690,
"y": 1460,
"wires": [
[
"bc45b4ac007dc6db"
]
]
},
{
"id": "bc45b4ac007dc6db",
"type": "debug",
"z": "d85b59ff755cd0af",
"name": "Feuer Diff",
"active": true,
"tosidebar": true,
"console": true,
"tostatus": false,
"complete": "channelName & \": \" & payload",
"targetType": "jsonata",
"statusVal": "",
"statusType": "auto",
"x": 910,
"y": 1460,
"wires": []
},
{
"id": "9ab0c56a62e6650f",
"type": "switch",
"z": "d85b59ff755cd0af",
"name": ">= 54",
"property": "payload",
"propertyType": "msg",
"rules": [
{
"t": "gte",
"v": "54",
"vt": "num"
}
],
"checkall": "true",
"repair": false,
"outputs": 1,
"x": 470,
"y": 1380,
"wires": [
[
"e8a03ae7d3c3ad28"
]
]
},
{
"id": "e8a03ae7d3c3ad28",
"type": "debug",
"z": "d85b59ff755cd0af",
"name": "Feuer > 54 Grad",
"active": true,
"tosidebar": true,
"console": true,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 930,
"y": 1380,
"wires": []
},
{
"id": "b3dbdd5f7937246b",
"type": "ccu-rpc-event",
"z": "d85b59ff755cd0af",
"name": "",
"iface": "",
"ccuConfig": "89acb508b5dc9002",
"rooms": "",
"roomsRx": "str",
"functions": "",
"functionsRx": "str",
"device": "",
"deviceRx": "str",
"deviceName": "",
"deviceNameRx": "str",
"deviceType": "",
"deviceTypeRx": "str",
"channel": "",
"channelRx": "str",
"channelName": "",
"channelNameRx": "str",
"channelType": "",
"channelTypeRx": "str",
"channelIndex": "",
"channelIndexRx": "str",
"datapoint": "ACTUAL_TEMPERATURE",
"datapointRx": "str",
"change": false,
"working": true,
"cache": true,
"topic": "${CCU}/${Interface}/${channelName}/${datapoint}",
"x": 220,
"y": 1380,
"wires": [
[
"a9ea5444b9af1635",
"7b59d7ec7f5b9135",
"9ab0c56a62e6650f"
]
]
},
{
"id": "7b59d7ec7f5b9135",
"type": "debug",
"z": "d85b59ff755cd0af",
"name": "debug 3",
"active": false,
"tosidebar": true,
"console": false,
"tostatus": true,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "counter",
"x": 220,
"y": 1440,
"wires": []
},
{
"id": "ecb068e08784b823",
"type": "comment",
"z": "d85b59ff755cd0af",
"name": "Die beiden Ausgänge dann weiterleiten an die Rauchmelder oder Handy",
"info": "",
"x": 1090,
"y": 1420,
"wires": []
},
{
"id": "89acb508b5dc9002",
"type": "ccu-connection",
"name": "CCU Export - durch eigene ersetzen",
"host": "192.168.0.0",
"regaEnabled": true,
"bcrfEnabled": true,
"iprfEnabled": true,
"virtEnabled": true,
"bcwiEnabled": false,
"jackEnabled": false,
"cuxdEnabled": false,
"regaPoll": true,
"regaInterval": "30",
"rpcPingTimeout": "60",
"rpcInitAddress": "",
"rpcServerHost": "0.0.0.0",
"rpcBinPort": "2085",
"rpcXmlPort": "2086",
"tls": false,
"inSecure": false,
"authentication": false,
"username": "",
"password": "",
"queueTimeout": "5000",
"queuePause": "250",
"contextStore": ""
}
]
Michael