Created
December 18, 2025 23:39
-
-
Save fensoft/88175fe7c7230ee45c8171a488c70780 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| [ | |
| { | |
| "id": "fb5296f3c4de2a23", | |
| "type": "subflow", | |
| "name": "Create HA Helpers", | |
| "info": "", | |
| "category": "HA Actions", | |
| "in": [ | |
| { | |
| "x": 84, | |
| "y": 96, | |
| "wires": [ | |
| { | |
| "id": "fc18bdbb57e2fd63" | |
| } | |
| ] | |
| } | |
| ], | |
| "out": [], | |
| "env": [ | |
| { | |
| "name": "serverName", | |
| "type": "str", | |
| "value": "Home Assistant", | |
| "ui": { | |
| "label": { | |
| "en-US": "HA Server Name" | |
| }, | |
| "type": "input", | |
| "opts": { | |
| "types": [ | |
| "str" | |
| ] | |
| } | |
| } | |
| }, | |
| { | |
| "name": "helpers", | |
| "type": "json", | |
| "value": "[]", | |
| "ui": { | |
| "label": { | |
| "en-US": "Helpers" | |
| }, | |
| "type": "input", | |
| "opts": { | |
| "types": [ | |
| "json" | |
| ] | |
| } | |
| } | |
| } | |
| ], | |
| "meta": {}, | |
| "color": "#46B1EF", | |
| "status": { | |
| "x": 246, | |
| "y": 48, | |
| "wires": [ | |
| { | |
| "id": "ea6dc8ad6d9ece17", | |
| "port": 0 | |
| } | |
| ] | |
| } | |
| }, | |
| { | |
| "id": "fc18bdbb57e2fd63", | |
| "type": "function", | |
| "z": "fb5296f3c4de2a23", | |
| "name": "process helpers", | |
| "func": "const serverName = toCamelCase(env.get('serverName'));\nconst haServer = global.get(\"homeassistant\")[serverName];\nif(!haServer) {\n node.error(\"Invalid HA server name\");\n return;\n}\nconst states = haServer.states;\nconst helpers = env.get(\"helpers\");\n\nhelpers.forEach(h => {\n const entityId = `${h.type}.${h.id}`;\n if(!states[entityId]) {\n const {id, type, ...data} = h;\n const apiData = {\n entity: h,\n payload: { \n data \n }\n };\n apiData.payload.data.type = `${type}/create`;\n \n node.send(apiData);\n node.status({text: `Creating ${entityId}`});\n }\n});\n\nnode.done();\n\nfunction toCamelCase(str) {\n return str.replace(/(?:^\\w|[A-Z]|\\b\\w|\\s+)/g, (match, index) => {\n if (+match === 0) return '';\n return index === 0 ? match.toLowerCase() : match.toUpperCase();\n });\n}", | |
| "outputs": 1, | |
| "timeout": "", | |
| "noerr": 0, | |
| "initialize": "", | |
| "finalize": "", | |
| "libs": [], | |
| "x": 224, | |
| "y": 96, | |
| "wires": [ | |
| [ | |
| "2b8e82c6d93d38e5" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "2b8e82c6d93d38e5", | |
| "type": "ha-api", | |
| "z": "fb5296f3c4de2a23", | |
| "name": "create helper", | |
| "server": "e89e2dad.1bf6", | |
| "version": 1, | |
| "debugenabled": false, | |
| "protocol": "websocket", | |
| "method": "get", | |
| "path": "", | |
| "data": "", | |
| "dataType": "json", | |
| "responseType": "json", | |
| "outputProperties": [ | |
| { | |
| "property": "payload", | |
| "propertyType": "msg", | |
| "value": "", | |
| "valueType": "results" | |
| } | |
| ], | |
| "x": 390, | |
| "y": 96, | |
| "wires": [ | |
| [ | |
| "767624d22ee0c819" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "372232586f5e138f", | |
| "type": "ha-api", | |
| "z": "fb5296f3c4de2a23", | |
| "name": "rename helper entity id", | |
| "server": "e89e2dad.1bf6", | |
| "version": 1, | |
| "debugenabled": false, | |
| "protocol": "websocket", | |
| "method": "get", | |
| "path": "", | |
| "data": "{\t \"type\":\"config/entity_registry/update\",\t \"entity_id\": entity.type & \".\" & payload.id,\t \"new_entity_id\": entity.type & \".\" & entity.id\t}", | |
| "dataType": "jsonata", | |
| "responseType": "json", | |
| "outputProperties": [ | |
| { | |
| "property": "payload", | |
| "propertyType": "msg", | |
| "value": "", | |
| "valueType": "results" | |
| } | |
| ], | |
| "x": 788, | |
| "y": 96, | |
| "wires": [ | |
| [] | |
| ] | |
| }, | |
| { | |
| "id": "767624d22ee0c819", | |
| "type": "switch", | |
| "z": "fb5296f3c4de2a23", | |
| "name": "need to rename?", | |
| "property": "payload.id", | |
| "propertyType": "msg", | |
| "rules": [ | |
| { | |
| "t": "neq", | |
| "v": "entity.id", | |
| "vt": "msg" | |
| } | |
| ], | |
| "checkall": "true", | |
| "repair": false, | |
| "outputs": 1, | |
| "x": 570, | |
| "y": 96, | |
| "wires": [ | |
| [ | |
| "372232586f5e138f", | |
| "815fe31e9d239e53" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "ea6dc8ad6d9ece17", | |
| "type": "status", | |
| "z": "fb5296f3c4de2a23", | |
| "name": "", | |
| "scope": [ | |
| "fc18bdbb57e2fd63", | |
| "815fe31e9d239e53" | |
| ], | |
| "x": 124, | |
| "y": 48, | |
| "wires": [ | |
| [] | |
| ] | |
| }, | |
| { | |
| "id": "815fe31e9d239e53", | |
| "type": "function", | |
| "z": "fb5296f3c4de2a23", | |
| "name": "rename status", | |
| "func": "const oldEntityId = `${msg.entity.type}.${msg.payload.id}`;\nconst newEntityId = `${msg.entity.type}.${msg.entity.id}`;\n\nnode.status({text: `Renaming ${oldEntityId} to ${newEntityId}`});", | |
| "outputs": 1, | |
| "timeout": "", | |
| "noerr": 0, | |
| "initialize": "", | |
| "finalize": "", | |
| "libs": [], | |
| "x": 768, | |
| "y": 144, | |
| "wires": [ | |
| [] | |
| ] | |
| }, | |
| { | |
| "id": "bae136fa5a77790e", | |
| "type": "subflow", | |
| "name": "On Restart", | |
| "info": "", | |
| "category": "", | |
| "in": [], | |
| "out": [ | |
| { | |
| "x": 320, | |
| "y": 320, | |
| "wires": [ | |
| { | |
| "id": "c67631f89e6451f4", | |
| "port": 0 | |
| } | |
| ] | |
| } | |
| ], | |
| "env": [], | |
| "meta": {}, | |
| "color": "#DDAA99" | |
| }, | |
| { | |
| "id": "4a91394f75614da1", | |
| "type": "server-events", | |
| "z": "bae136fa5a77790e", | |
| "name": "", | |
| "server": "e89e2dad.1bf6", | |
| "version": 3, | |
| "exposeAsEntityConfig": "", | |
| "eventType": "home_assistant_client", | |
| "eventData": "", | |
| "waitForRunning": false, | |
| "outputProperties": [ | |
| { | |
| "property": "payload", | |
| "propertyType": "msg", | |
| "value": "", | |
| "valueType": "eventData" | |
| } | |
| ], | |
| "x": 140, | |
| "y": 220, | |
| "wires": [ | |
| [ | |
| "95e9d47ed2be5007" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "95e9d47ed2be5007", | |
| "type": "switch", | |
| "z": "bae136fa5a77790e", | |
| "name": "running?", | |
| "property": "payload", | |
| "propertyType": "msg", | |
| "rules": [ | |
| { | |
| "t": "eq", | |
| "v": "running", | |
| "vt": "str" | |
| } | |
| ], | |
| "checkall": "true", | |
| "repair": false, | |
| "outputs": 1, | |
| "x": 352, | |
| "y": 220, | |
| "wires": [ | |
| [ | |
| "4b7a32290de02cf7" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "648dd9ac108befdc", | |
| "type": "api-call-service", | |
| "z": "bae136fa5a77790e", | |
| "name": "", | |
| "server": "e89e2dad.1bf6", | |
| "version": 7, | |
| "debugenabled": false, | |
| "action": "input_boolean.turn_off", | |
| "floorId": [], | |
| "areaId": [], | |
| "deviceId": [], | |
| "entityId": [ | |
| "input_boolean.home_assistant_restarted" | |
| ], | |
| "labelId": [], | |
| "data": "", | |
| "dataType": "json", | |
| "mergeContext": "", | |
| "mustacheAltTags": false, | |
| "outputProperties": [], | |
| "queue": "none", | |
| "blockInputOverrides": false, | |
| "domain": "input_boolean", | |
| "service": "turn_off", | |
| "x": 758, | |
| "y": 220, | |
| "wires": [ | |
| [ | |
| "3754cbf709193071" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "4b7a32290de02cf7", | |
| "type": "api-current-state", | |
| "z": "bae136fa5a77790e", | |
| "name": "has restarted?", | |
| "server": "e89e2dad.1bf6", | |
| "version": 3, | |
| "outputs": 2, | |
| "halt_if": "on", | |
| "halt_if_type": "str", | |
| "halt_if_compare": "is", | |
| "entity_id": "input_boolean.home_assistant_restarted", | |
| "state_type": "str", | |
| "blockInputOverrides": false, | |
| "outputProperties": [], | |
| "for": 0, | |
| "forType": "num", | |
| "forUnits": "minutes", | |
| "x": 516, | |
| "y": 220, | |
| "wires": [ | |
| [ | |
| "648dd9ac108befdc" | |
| ], | |
| [] | |
| ] | |
| }, | |
| { | |
| "id": "f89ae68a99bb4e65", | |
| "type": "server-state-changed", | |
| "z": "bae136fa5a77790e", | |
| "name": "restarted?", | |
| "server": "e89e2dad.1bf6", | |
| "version": 6, | |
| "outputs": 2, | |
| "exposeAsEntityConfig": "", | |
| "entities": { | |
| "entity": [ | |
| "input_boolean.home_assistant_restarted" | |
| ], | |
| "substring": [], | |
| "regex": [] | |
| }, | |
| "outputInitially": false, | |
| "stateType": "str", | |
| "ifState": "on", | |
| "ifStateType": "str", | |
| "ifStateOperator": "is", | |
| "outputOnlyOnStateChange": false, | |
| "for": 0, | |
| "forType": "num", | |
| "forUnits": "minutes", | |
| "ignorePrevStateNull": false, | |
| "ignorePrevStateUnknown": false, | |
| "ignorePrevStateUnavailable": false, | |
| "ignoreCurrentStateUnknown": false, | |
| "ignoreCurrentStateUnavailable": false, | |
| "outputProperties": [], | |
| "x": 528, | |
| "y": 268, | |
| "wires": [ | |
| [ | |
| "648dd9ac108befdc" | |
| ], | |
| [] | |
| ] | |
| }, | |
| { | |
| "id": "b5993f580d9eb5b8", | |
| "type": "comment", | |
| "z": "bae136fa5a77790e", | |
| "name": "Home Assistant Restarted", | |
| "info": "", | |
| "x": 130, | |
| "y": 124, | |
| "wires": [] | |
| }, | |
| { | |
| "id": "3754cbf709193071", | |
| "type": "link out", | |
| "z": "bae136fa5a77790e", | |
| "name": "Home Assistant Restarted", | |
| "links": [ | |
| "c67631f89e6451f4" | |
| ], | |
| "x": 1010, | |
| "y": 220, | |
| "wires": [], | |
| "l": true | |
| }, | |
| { | |
| "id": "c67631f89e6451f4", | |
| "type": "link in", | |
| "z": "bae136fa5a77790e", | |
| "name": "Home Assistant Restarted", | |
| "links": [ | |
| "3754cbf709193071" | |
| ], | |
| "x": 130, | |
| "y": 316, | |
| "wires": [ | |
| [] | |
| ], | |
| "l": true | |
| }, | |
| { | |
| "id": "bcfea616e335904d", | |
| "type": "inject", | |
| "z": "bae136fa5a77790e", | |
| "name": "Click to create", | |
| "props": [ | |
| { | |
| "p": "payload" | |
| }, | |
| { | |
| "p": "topic", | |
| "vt": "str" | |
| } | |
| ], | |
| "repeat": "", | |
| "crontab": "", | |
| "once": false, | |
| "onceDelay": 0.1, | |
| "topic": "", | |
| "payload": "", | |
| "payloadType": "date", | |
| "x": 106, | |
| "y": 172, | |
| "wires": [ | |
| [ | |
| "447721875af4431a", | |
| "5a92fd8241edd308" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "447721875af4431a", | |
| "type": "ha-api", | |
| "z": "bae136fa5a77790e", | |
| "name": "HA automation", | |
| "server": "e89e2dad.1bf6", | |
| "version": 1, | |
| "debugenabled": false, | |
| "protocol": "http", | |
| "method": "post", | |
| "path": "/api/config/automation/config/nrrestartnotification", | |
| "data": "{\t \"alias\": \"Home Assistant Restart\",\t \"description\": \"\",\t \"trigger\": [\t {\t \"platform\": \"homeassistant\",\t \"event\": \"start\" \t } \t ],\t \"condition\": [],\t \"action\": [\t {\t \"service\": \"input_boolean.turn_on\",\t \"data\": {\t \"entity_id\": \"input_boolean.home_assistant_restarted\" \t }\t } \t ],\t \"mode\": \"single\" \t}", | |
| "dataType": "jsonata", | |
| "responseType": "json", | |
| "outputProperties": [], | |
| "x": 372, | |
| "y": 124, | |
| "wires": [ | |
| [] | |
| ] | |
| }, | |
| { | |
| "id": "5a92fd8241edd308", | |
| "type": "subflow:fb5296f3c4de2a23", | |
| "z": "bae136fa5a77790e", | |
| "name": "", | |
| "env": [ | |
| { | |
| "name": "serverName", | |
| "value": "Home Assistant Working", | |
| "type": "str" | |
| }, | |
| { | |
| "name": "helpers", | |
| "value": "[{\"id\":\"home_assistant_restarted\",\"type\":\"input_boolean\",\"name\":\"Home Assistant Restarted\",\"icon\":\"mdi:restart-alert\"}]", | |
| "type": "json" | |
| } | |
| ], | |
| "x": 382, | |
| "y": 172, | |
| "wires": [] | |
| }, | |
| { | |
| "id": "e89e2dad.1bf6", | |
| "type": "server", | |
| "name": "Home Assistant Working", | |
| "addon": true, | |
| "rejectUnauthorizedCerts": true, | |
| "ha_boolean": "", | |
| "connectionDelay": false, | |
| "cacheJson": false, | |
| "heartbeat": false, | |
| "heartbeatInterval": "", | |
| "entitySelector": "id", | |
| "statusSeparator": "", | |
| "enableGlobalContextStore": false | |
| }, | |
| { | |
| "id": "103b1fd4c70bd5ad", | |
| "type": "tab", | |
| "label": "Max! 2 MQTT", | |
| "disabled": false, | |
| "info": "", | |
| "env": [] | |
| }, | |
| { | |
| "id": "fd3ce805ed926c80", | |
| "type": "inject", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "timer", | |
| "props": [ | |
| { | |
| "p": "reason", | |
| "v": "repeat", | |
| "vt": "str" | |
| } | |
| ], | |
| "repeat": "120", | |
| "crontab": "", | |
| "once": true, | |
| "onceDelay": "1", | |
| "topic": "", | |
| "x": 90, | |
| "y": 540, | |
| "wires": [ | |
| [ | |
| "248a31587c7960fe" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "7b8330524ea2f4c4", | |
| "type": "mqtt out", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "mqtt boiler", | |
| "topic": "cmnd/tasmota_F4295B/POWER", | |
| "qos": "0", | |
| "retain": "false", | |
| "respTopic": "", | |
| "contentType": "", | |
| "userProps": "", | |
| "correl": "", | |
| "expiry": "", | |
| "broker": "d7efe4ef4af81eb9", | |
| "x": 770, | |
| "y": 320, | |
| "wires": [] | |
| }, | |
| { | |
| "id": "9fabcb15eb75a432", | |
| "type": "function", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "compute action", | |
| "func": "const rooms = Object.values(msg.payload).filter(v => v.device_type === 3);\n\n// calculate total temperature deficit (\"miss\")\nconst miss = rooms.reduce((sum, v) => {\n return sum + ((v.temp < v.setpoint && v.room_name !== 'WC') ? (v.setpoint - v.temp) : 0);\n}, 0);\n\n// determine desired action\nlet desiredAction = null;\nif (miss >= 1.2) desiredAction = 'ON';\nelse if (miss <= 0.5) desiredAction = 'OFF';\n\n// get last state and time from context\nconst lastAction = context.get('lastAction') || null;\nconst lastChange = context.get('lastChange') || 0;\nconst now = Date.now();\n\n// if less than 10 min since last change, keep same state\nif (lastAction && (now - lastChange < 5 * 60 * 1000)) {\n desiredAction = lastAction;\n} else if (desiredAction !== lastAction && desiredAction !== null) {\n // record new state and timestamp\n context.set('lastAction', desiredAction);\n context.set('lastChange', now);\n}\n\n// get current values after possible update\nconst currentAction = context.get('lastAction') || desiredAction;\nconst currentChange = context.get('lastChange') || now;\n\n// build per-room status\nconst res = Object.fromEntries(\n rooms.map(v => {\n const name = v.room_name.replace(\" \", \"_\");\n const status = (currentAction === 'ON' && v.temp < v.setpoint && v.room_name !== 'WC')\n ? 'heat'\n : 'off';\n return [name, { status }];\n })\n);\n\n// make readable timestamp\nconst readableTime = new Date(currentChange).toLocaleString();\n\nreturn [\n { payload: currentAction, heat: miss },\n { payload: res },\n { payload: { readableTime, lastAction: currentAction } }\n];\n\n// var res = {};\n// var miss = 0;\n// for (const [key, value] of Object.entries(msg.payload)) {\n// if (value.device_type == 3) {\n// name = value.room_name.replace(\" \", \"_\");// + \"_\" + value.device_name.replace(\" \", \"_\");\n// if (value.temp < value.setpoint) {\n// if (value.room_name != 'WC')\n// miss += value.setpoint - value.temp;\n// }\n// res[name] = { \"status\": \"off\" };\n// }\n// }\n\n// var action = null;\n// if (miss <= 0.5) {\n// action = 'OFF';\n// }\n// if (miss >= 1.2) {\n// action = 'ON';\n// for (const [key, value] of Object.entries(msg.payload)) {\n// if (value.device_type == 3) {\n// name = value.room_name.replace(\" \", \"_\");// + \"_\" + value.device_name.replace(\" \", \"_\")\n// if (value.temp < value.setpoint && value.room_name != 'WC') {\n// status = 'heat';\n// } else {\n// status = 'off';\n// }\n// res[name] = { \"status\": status };\n// }\n// }\n// }\n// return [ { 'payload': action, 'heat': miss }, { \"payload\": res } ];", | |
| "outputs": 3, | |
| "timeout": "", | |
| "noerr": 0, | |
| "initialize": "", | |
| "finalize": "", | |
| "libs": [], | |
| "x": 440, | |
| "y": 460, | |
| "wires": [ | |
| [ | |
| "7b8330524ea2f4c4", | |
| "87831a7d8384ba61", | |
| "eaa0ef6ec5828c4b", | |
| "91688cf578b02dfa" | |
| ], | |
| [ | |
| "f1d30ee021d42cf6" | |
| ], | |
| [] | |
| ] | |
| }, | |
| { | |
| "id": "3355f9d8134bb8d5", | |
| "type": "split", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "", | |
| "splt": "\\n", | |
| "spltType": "str", | |
| "arraySplt": 1, | |
| "arraySpltType": "len", | |
| "stream": false, | |
| "addname": "", | |
| "x": 630, | |
| "y": 580, | |
| "wires": [ | |
| [ | |
| "d09de1b4a1e90b50" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "2ebfae9701dd6b68", | |
| "type": "function", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "decode", | |
| "func": "var res = {};\nfor (const [key, value] of Object.entries(msg.payload)) {\n if (value.device_type) {\n name = value.room_name.replace(\" \", \"_\") + \"_\" + value.device_name.replace(\" \", \"_\");\n if (!(value.device_type in res))\n res[value.device_type] = {};\n res[value.device_type][name] = value;\n }\n}\nreturn [ { \"payload\": res[1] }, { \"payload\": res[3] }, { \"payload\": res[4] }, res ];", | |
| "outputs": 4, | |
| "noerr": 0, | |
| "initialize": "", | |
| "finalize": "", | |
| "libs": [], | |
| "x": 420, | |
| "y": 600, | |
| "wires": [ | |
| [ | |
| "f3a618cb9b217476" | |
| ], | |
| [ | |
| "3355f9d8134bb8d5" | |
| ], | |
| [ | |
| "da37c30786c72470" | |
| ], | |
| [] | |
| ] | |
| }, | |
| { | |
| "id": "f1d30ee021d42cf6", | |
| "type": "split", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "", | |
| "splt": "\\n", | |
| "spltType": "str", | |
| "arraySplt": 1, | |
| "arraySpltType": "len", | |
| "stream": false, | |
| "addname": "", | |
| "x": 630, | |
| "y": 480, | |
| "wires": [ | |
| [ | |
| "835b0a70c0092e13" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "835b0a70c0092e13", | |
| "type": "function", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "thermostat state", | |
| "func": "msg.topic = 'maxcube2mqtt/thermostat/' + msg.parts.key;\nreturn msg;", | |
| "outputs": 1, | |
| "timeout": "", | |
| "noerr": 0, | |
| "initialize": "", | |
| "finalize": "", | |
| "libs": [], | |
| "x": 780, | |
| "y": 480, | |
| "wires": [ | |
| [ | |
| "f855b4166b9fe922" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "f3a618cb9b217476", | |
| "type": "split", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "", | |
| "splt": "\\n", | |
| "spltType": "str", | |
| "arraySplt": 1, | |
| "arraySpltType": "len", | |
| "stream": false, | |
| "addname": "", | |
| "x": 630, | |
| "y": 540, | |
| "wires": [ | |
| [ | |
| "221d232e309d8974" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "da37c30786c72470", | |
| "type": "split", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "", | |
| "splt": "\\n", | |
| "spltType": "str", | |
| "arraySplt": 1, | |
| "arraySpltType": "len", | |
| "stream": false, | |
| "addname": "", | |
| "x": 630, | |
| "y": 620, | |
| "wires": [ | |
| [ | |
| "b64957542172ae46" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "87831a7d8384ba61", | |
| "type": "function", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "boiler total", | |
| "func": "var msgo = {};\nmsgo.payload = msg;\nmsgo.payload.heat = msgo.payload.heat.toFixed(1)\nmsgo.topic = 'homeassistant/sensor/maxcube_heat';\nmsgo.payload.config = {}\nmsgo.payload.config[\"~\"] = msgo.topic;\nmsgo.payload.config[\"uniq_id\"] = \"maxcube_heat\";\nmsgo.payload.config[\"name\"] = \"Chaudière Total\";\nmsgo.payload.config[\"state_topic\"] = \"~/heat\";\nmsgo.payload.config[\"unit_of_measurement\"] = \"°\";\nreturn msgo;", | |
| "outputs": 1, | |
| "timeout": "", | |
| "noerr": 0, | |
| "initialize": "", | |
| "finalize": "", | |
| "libs": [], | |
| "x": 770, | |
| "y": 440, | |
| "wires": [ | |
| [ | |
| "f855b4166b9fe922" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "9288a4f985382537", | |
| "type": "mqtt out", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "mqtt", | |
| "topic": "", | |
| "qos": "", | |
| "retain": "", | |
| "respTopic": "", | |
| "contentType": "", | |
| "userProps": "", | |
| "correl": "", | |
| "expiry": "", | |
| "broker": "d7efe4ef4af81eb9", | |
| "x": 1190, | |
| "y": 440, | |
| "wires": [] | |
| }, | |
| { | |
| "id": "f855b4166b9fe922", | |
| "type": "split", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "", | |
| "splt": "\\n", | |
| "spltType": "str", | |
| "arraySplt": 1, | |
| "arraySpltType": "len", | |
| "stream": false, | |
| "addname": "key", | |
| "x": 950, | |
| "y": 440, | |
| "wires": [ | |
| [ | |
| "9f45cc50a1240208" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "9f45cc50a1240208", | |
| "type": "function", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "suffix", | |
| "func": "msg.topic = msg.topic + '/' + msg.key;\ndelete msg.key;\nreturn msg;", | |
| "outputs": 1, | |
| "noerr": 0, | |
| "initialize": "", | |
| "finalize": "", | |
| "libs": [], | |
| "x": 1070, | |
| "y": 440, | |
| "wires": [ | |
| [ | |
| "9288a4f985382537" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "29949c9d2834f922", | |
| "type": "comment", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "boiler", | |
| "info": "boiler management.\nCompute total of missing degrees in each room and turn on the boiler if needed.", | |
| "x": 410, | |
| "y": 400, | |
| "wires": [] | |
| }, | |
| { | |
| "id": "af681e641dcfc3b7", | |
| "type": "comment", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "mqtt receive", | |
| "info": "send/receive to mqtt", | |
| "x": 430, | |
| "y": 540, | |
| "wires": [] | |
| }, | |
| { | |
| "id": "248a31587c7960fe", | |
| "type": "maxcube out", | |
| "z": "103b1fd4c70bd5ad", | |
| "server": "9a07e5adcaeb56f7", | |
| "singleMessage": true, | |
| "x": 220, | |
| "y": 540, | |
| "wires": [ | |
| [ | |
| "9fabcb15eb75a432", | |
| "2ebfae9701dd6b68" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "eaa0ef6ec5828c4b", | |
| "type": "function", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "boiler state", | |
| "func": "// msg.payload = 'OFF';\n// if (msg.payload == null)\n// return null;\nvar msgo = {};\nmsgo.payload = {};\nmsgo.topic = 'homeassistant/binary_sensor/maxcube_state';\nmsgo.payload.state = msg.payload;\nmsgo.payload.config = {}\nmsgo.payload.config[\"~\"] = msgo.topic;\nmsgo.payload.config[\"uniq_id\"] = \"maxcube_state\";\nmsgo.payload.config[\"name\"] = \"Chaudière État\";\nmsgo.payload.config[\"state_topic\"] = \"~/state\";\nreturn msgo;", | |
| "outputs": 1, | |
| "timeout": "", | |
| "noerr": 0, | |
| "initialize": "", | |
| "finalize": "", | |
| "libs": [], | |
| "x": 770, | |
| "y": 400, | |
| "wires": [ | |
| [ | |
| "f855b4166b9fe922" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "d09de1b4a1e90b50", | |
| "type": "function", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "thermostat", | |
| "func": "msg.topic = 'maxcube2mqtt/thermostat/' + msg.payload.room_name.replace(\" \", \"_\");\nreturn msg;", | |
| "outputs": 1, | |
| "timeout": "", | |
| "noerr": 0, | |
| "initialize": "", | |
| "finalize": "", | |
| "libs": [], | |
| "x": 770, | |
| "y": 580, | |
| "wires": [ | |
| [ | |
| "5ba40e51ea31021b" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "221d232e309d8974", | |
| "type": "function", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "valve", | |
| "func": "msg.topic = 'maxcube2mqtt/valve/' + msg.payload.room_name.replace(\" \", \"_\") + \"_\" + msg.payload.device_name.replace(\" \", \"_\");\nreturn msg;", | |
| "outputs": 1, | |
| "timeout": "", | |
| "noerr": 0, | |
| "initialize": "", | |
| "finalize": "", | |
| "libs": [], | |
| "x": 750, | |
| "y": 540, | |
| "wires": [ | |
| [ | |
| "5ba40e51ea31021b" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "5ba40e51ea31021b", | |
| "type": "split", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "", | |
| "splt": "\\n", | |
| "spltType": "str", | |
| "arraySplt": 1, | |
| "arraySpltType": "len", | |
| "stream": false, | |
| "addname": "key", | |
| "x": 910, | |
| "y": 580, | |
| "wires": [ | |
| [ | |
| "f834c4de1ba53a86" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "f834c4de1ba53a86", | |
| "type": "function", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "suffix", | |
| "func": "msg.topic = msg.topic + '/' + msg.key;\ndelete msg.key;\nreturn msg;", | |
| "outputs": 1, | |
| "noerr": 0, | |
| "initialize": "", | |
| "finalize": "", | |
| "libs": [], | |
| "x": 1030, | |
| "y": 580, | |
| "wires": [ | |
| [ | |
| "efcb1347e477233d" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "b64957542172ae46", | |
| "type": "function", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "window", | |
| "func": "msg.topic = 'maxcube2mqtt/window/' + msg.payload.room_name.replace(\" \", \"_\") + \" / \" + msg.payload.device_name.replace(\" \", \"_\");\nreturn msg;", | |
| "outputs": 1, | |
| "timeout": "", | |
| "noerr": 0, | |
| "initialize": "", | |
| "finalize": "", | |
| "libs": [], | |
| "x": 760, | |
| "y": 620, | |
| "wires": [ | |
| [ | |
| "5ba40e51ea31021b" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "3d2761b7773ae8d5", | |
| "type": "inject", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "on start", | |
| "props": [ | |
| { | |
| "p": "reason", | |
| "v": "start", | |
| "vt": "str" | |
| } | |
| ], | |
| "repeat": "3600", | |
| "crontab": "", | |
| "once": true, | |
| "onceDelay": "15", | |
| "topic": "", | |
| "x": 160, | |
| "y": 140, | |
| "wires": [ | |
| [ | |
| "554700ca0a7b0288" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "554700ca0a7b0288", | |
| "type": "maxcube out", | |
| "z": "103b1fd4c70bd5ad", | |
| "server": "9a07e5adcaeb56f7", | |
| "singleMessage": true, | |
| "x": 320, | |
| "y": 160, | |
| "wires": [ | |
| [ | |
| "262018a32e7e029b" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "262018a32e7e029b", | |
| "type": "function", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "decode", | |
| "func": "var res = {};\nfor (const [key, value] of Object.entries(msg.payload)) {\n if (value.device_type) {\n name = value.room_name.replace(\" \", \"_\") + \"_\" + value.device_name.replace(\" \", \"_\");\n if (!(value.device_type in res))\n res[value.device_type] = {};\n res[value.device_type][name] = value;\n }\n}\nreturn [ { \"payload\": res[1] }, { \"payload\": res[3] }, { \"payload\": res[4] }, res ];", | |
| "outputs": 4, | |
| "timeout": "", | |
| "noerr": 0, | |
| "initialize": "", | |
| "finalize": "", | |
| "libs": [], | |
| "x": 480, | |
| "y": 160, | |
| "wires": [ | |
| [ | |
| "45a48dfb50ec27a3" | |
| ], | |
| [ | |
| "cf5b45a47dc5be43" | |
| ], | |
| [ | |
| "1e0f3bbea406afcd" | |
| ], | |
| [] | |
| ], | |
| "outputLabels": [ | |
| "valve", | |
| "thermostat", | |
| "window", | |
| "" | |
| ] | |
| }, | |
| { | |
| "id": "45a48dfb50ec27a3", | |
| "type": "split", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "", | |
| "splt": "\\n", | |
| "spltType": "str", | |
| "arraySplt": 1, | |
| "arraySpltType": "len", | |
| "stream": false, | |
| "addname": "", | |
| "x": 650, | |
| "y": 100, | |
| "wires": [ | |
| [ | |
| "c4bef775bb3de4a4", | |
| "3ec8ad146c23b99e" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "c4bef775bb3de4a4", | |
| "type": "function", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "valve", | |
| "func": "var res = {}\nres.topic = 'homeassistant/climate/' + msg.payload.room_name.replace(\" \", \"_\") + \"-\" + msg.payload.device_name.replace(\" \", \"_\") + '/config';\nres.payload = {}\nres.payload[\"~\"] = 'maxcube2mqtt/valve/' + msg.payload.room_name.replace(\" \", \"_\") + \"_\" + msg.payload.device_name.replace(\" \", \"_\");\nres.payload[\"unique_id\"] = \"maxcube_valve_\" + msg.parts.key.replace(\" \", \"_\");\nres.payload[\"name\"] = \"Valve \" + msg.payload.room_name + \" / \" + msg.payload.device_name;\nres.payload[\"temp_cmd_t\"] = \"~/setpoint/set\";\nres.payload[\"temp_stat_t\"] = \"~/setpoint\";\nres.payload[\"curr_temp_t\"] = \"~/temp\";\nres.payload[\"min_temp\"] = \"12\";\nres.payload[\"max_temp\"] = \"25\";\nres.payload[\"temp_step\"] = \"0.5\";\nres.payload[\"availability_topic\"] = \"~/error\";\nres.payload[\"payload_available\"] = \"false\";\nres.payload[\"payload_not_available\"] = \"true\";\nres.payload[\"device\"] = {};\nres.payload.device[\"manufacturer\"] = \"ELV\";\nres.payload.device[\"model\"] = \"valve\";\nres.payload.device[\"name\"] = res.payload[\"name\"];\nres.payload.device[\"identifiers\"] = [ \"maxcube_\" + msg.payload.rf_address];\n// res.payload.device[\"connections\"] = [ [ \"mac\", msg.payload.rf_address ] ];\n// res.payload[\"origin\"] = {};\n// res.payload.origin[\"name\"] = \"maxcube\";\nreturn res;", | |
| "outputs": 1, | |
| "timeout": "", | |
| "noerr": 0, | |
| "initialize": "", | |
| "finalize": "", | |
| "libs": [], | |
| "x": 790, | |
| "y": 60, | |
| "wires": [ | |
| [ | |
| "3c3e46d6fee1be7b" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "3c3e46d6fee1be7b", | |
| "type": "mqtt out", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "mqtt", | |
| "topic": "", | |
| "qos": "", | |
| "retain": "", | |
| "respTopic": "", | |
| "contentType": "", | |
| "userProps": "", | |
| "correl": "", | |
| "expiry": "", | |
| "broker": "d7efe4ef4af81eb9", | |
| "x": 1010, | |
| "y": 160, | |
| "wires": [] | |
| }, | |
| { | |
| "id": "3ec8ad146c23b99e", | |
| "type": "function", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "valve bat", | |
| "func": "var res = {}\nres.topic = 'homeassistant/sensor/' + msg.payload.room_name.replace(\" \", \"_\") + \"-\" + msg.payload.device_name.replace(\" \", \"_\") + \"_battery/config\";\nres.payload = {}\nres.payload[\"~\"] = 'maxcube2mqtt/valve/' + msg.payload.room_name.replace(\" \", \"_\") + \"_\" + msg.payload.device_name.replace(\" \", \"_\");\nres.payload[\"uniq_id\"] = \"maxcube_\" + msg.parts.key.replace(\" \", \"_\") + \"_battery\";\nres.payload[\"name\"] = \"Valve \" + msg.payload.room_name + \" / \" + msg.payload.device_name + \" Battery\";\nres.payload[\"device_class\"] = \"battery\";\nres.payload[\"entity_category\"] = \"diagnostic\";\nres.payload[\"state_class\"] = \"measurement\";\nres.payload[\"state_topic\"] = \"~/battery_low\";\nres.payload[\"unit_of_measurement\"] = \"%\";\nres.payload[\"value_template\"] = '{{ 0 if value == \"true\" else 100 }}';\nres.payload[\"device\"] = {};\nres.payload.device[\"manufacturer\"] = \"ELV\";\nres.payload.device[\"model\"] = \"valve\";\nres.payload.device[\"name\"] = res.payload[\"name\"];\nres.payload.device[\"identifiers\"] = [ \"maxcube_\" + msg.payload.rf_address];\nreturn res;", | |
| "outputs": 1, | |
| "timeout": "", | |
| "noerr": 0, | |
| "initialize": "", | |
| "finalize": "", | |
| "libs": [], | |
| "x": 800, | |
| "y": 100, | |
| "wires": [ | |
| [ | |
| "3c3e46d6fee1be7b" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "6ad662a6b39283fa", | |
| "type": "function", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "thermostat ", | |
| "func": "var res = {};\nres.topic = 'homeassistant/climate/' + msg.payload.room_name.replace(\" \", \"_\") + '/config';\nres.payload = {};\nres.payload[\"~\"] = 'maxcube2mqtt/thermostat/' + msg.payload.room_name.replace(\" \", \"_\");\nres.payload[\"uniq_id\"] = 'maxcube_' + msg.payload.room_name.replace(\" \", \"_\");\nres.payload[\"name\"] = 'Thermostat ' + msg.payload.room_name;\n\n// HVAC modes\nres.payload[\"modes\"] = [\"heat\", \"off\"];\nres.payload[\"mode_state_topic\"] = '~/status'; // must publish \"heat\" or \"off\"\nres.payload[\"mode_command_topic\"] = '~/status/set';// must accept \"heat\" or \"off\"\n\n// Temperature control\nres.payload[\"temp_cmd_t\"] = '~/setpoint/set';\nres.payload[\"temp_stat_t\"] = '~/setpoint';\nres.payload[\"curr_temp_t\"] = '~/temp';\nres.payload[\"min_temp\"] = 12; // numbers, not strings\nres.payload[\"max_temp\"] = 25;\nres.payload[\"temp_step\"] = 0.5;\nres.payload[\"temperature_unit\"] = 'C';\n\n// Presets (AUTO/MANUAL/BOOST)\nres.payload[\"preset_modes\"] = [\"AUTO\", \"MANUAL\", \"BOOST\"];\nres.payload[\"preset_mode_command_topic\"] = '~/mode/set';\nres.payload[\"preset_mode_state_topic\"] = '~/mode';\n\n// Availability via error topic (false == OK)\n// res.payload[\"availability_topic\"] = '~/error';\n// res.payload[\"payload_available\"] = 'false';\n// res.payload[\"payload_not_available\"] = 'true';\n\nres.payload[\"device\"] = {\n manufacturer: 'ELV',\n model: 'thermostat',\n name: res.payload[\"name\"],\n identifiers: ['maxcube_' + msg.payload.rf_address]\n};\nreturn res;\n", | |
| "outputs": 1, | |
| "timeout": "", | |
| "noerr": 0, | |
| "initialize": "", | |
| "finalize": "", | |
| "libs": [], | |
| "x": 810, | |
| "y": 140, | |
| "wires": [ | |
| [ | |
| "3c3e46d6fee1be7b" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "794a0609769ac85c", | |
| "type": "function", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "thermostat bat ", | |
| "func": "// Battery \"percentage\" from low flag (0% or 100%), always available\nvar room = (msg.payload.room_name || '').replace(/\\s+/g, '_');\nvar key = (msg.parts.key || '').replace(/\\s+/g, '_');\n\nvar res = {};\nres.topic = 'homeassistant/sensor/' + key + '_battery/config';\nres.payload = {};\n\n// Base\nres.payload[\"~\"] = 'maxcube2mqtt/thermostat/' + room;\nres.payload[\"uniq_id\"] = 'maxcube_' + key + '_battery';\nres.payload[\"name\"] = 'Thermostat ' + msg.payload.room_name + ' / ' + msg.payload.device_name + ' Battery';\n\n// Sensor as 0%/100%\nres.payload[\"device_class\"] = 'battery';\nres.payload[\"entity_category\"] = 'diagnostic';\nres.payload[\"state_class\"] = 'measurement';\nres.payload[\"state_topic\"] = '~/battery_low';\nres.payload[\"unit_of_measurement\"] = '%';\nres.payload[\"value_template\"] = '{{ 0 if value == \"true\" else 100 }}';\nres.payload[\"suggested_display_precision\"] = 0;\n\n// No availability_topic => always available\n\n// Device info\nres.payload[\"device\"] = {\n manufacturer: 'ELV',\n model: 'thermostat',\n name: 'Thermostat ' + msg.payload.room_name + ' / ' + msg.payload.device_name,\n identifiers: ['maxcube_' + msg.payload.rf_address]\n};\n\nreturn res;\n", | |
| "outputs": 1, | |
| "timeout": "", | |
| "noerr": 0, | |
| "initialize": "", | |
| "finalize": "", | |
| "libs": [], | |
| "x": 820, | |
| "y": 180, | |
| "wires": [ | |
| [ | |
| "3c3e46d6fee1be7b" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "cf5b45a47dc5be43", | |
| "type": "split", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "", | |
| "splt": "\\n", | |
| "spltType": "str", | |
| "arraySplt": 1, | |
| "arraySpltType": "len", | |
| "stream": false, | |
| "addname": "", | |
| "x": 650, | |
| "y": 160, | |
| "wires": [ | |
| [ | |
| "6ad662a6b39283fa", | |
| "794a0609769ac85c" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "1e3df1f548625467", | |
| "type": "comment", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "HA discovery", | |
| "info": "boiler management.\nCompute total of missing degrees in each room and turn on the boiler if needed.", | |
| "x": 310, | |
| "y": 100, | |
| "wires": [] | |
| }, | |
| { | |
| "id": "b215271d477e76a1", | |
| "type": "function", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "window", | |
| "func": "var res = {};\nres.topic = 'homeassistant/binary_sensor/' + msg.parts.key.replace(\" \", \"_\") + '/config';\nres.payload = {}\nres.payload[\"~\"] = 'maxcube2mqtt/window/' + msg.payload.room_name.replace(\" \", \"_\");\nres.payload[\"uniq_id\"] = \"maxcube_\" + msg.parts.key.replace(\" \", \"_\");\nres.payload[\"name\"] = \"Contact \" + msg.payload.room_name + \" / \" + msg.payload.device_name;\nres.payload[\"state_topic\"] = \"~/open\";\nres.payload[\"device_class\"] = \"window\";\nres.payload[\"payload_off\"] = \"false\";\nres.payload[\"payload_on\"] = \"true\";\nres.payload[\"availability_topic\"] = \"~/error\";\nres.payload[\"payload_available\"] = \"false\";\nres.payload[\"payload_not_available\"] = \"true\";\nreturn res;", | |
| "outputs": 1, | |
| "timeout": "", | |
| "noerr": 0, | |
| "initialize": "", | |
| "finalize": "", | |
| "libs": [], | |
| "x": 800, | |
| "y": 220, | |
| "wires": [ | |
| [ | |
| "3c3e46d6fee1be7b" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "b022f80ec1f025d0", | |
| "type": "function", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "window bat", | |
| "func": "var res = {}\nres.topic = 'homeassistant/sensor/' + msg.parts.key.replace(\" \", \"_\") + \"_battery/config\";\nres.payload = {}\nres.payload[\"~\"] = 'maxcube2mqtt/window/' + msg.payload.room_name.replace(\" \", \"_\");\nres.payload[\"uniq_id\"] = \"maxcube_\" + msg.parts.key.replace(\" \", \"_\") + \"_battery\";\nres.payload[\"name\"] = \"Contact \" + msg.payload.room_name + \" / \" + msg.payload.device_name + \" Battery\";\nres.payload[\"device_class\"] = \"battery\";\nres.payload[\"entity_category\"] = \"diagnostic\";\nres.payload[\"state_class\"] = \"measurement\";\nres.payload[\"state_topic\"] = \"~/battery_low\";\nres.payload[\"unit_of_measurement\"] = \"%\";\nres.payload[\"value_template\"] = '{{ 0 if value == \"true\" else 100 }}';\nreturn res;", | |
| "outputs": 1, | |
| "timeout": "", | |
| "noerr": 0, | |
| "initialize": "", | |
| "finalize": "", | |
| "libs": [], | |
| "x": 810, | |
| "y": 260, | |
| "wires": [ | |
| [ | |
| "3c3e46d6fee1be7b" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "1e0f3bbea406afcd", | |
| "type": "split", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "", | |
| "splt": "\\n", | |
| "spltType": "str", | |
| "arraySplt": 1, | |
| "arraySpltType": "len", | |
| "stream": false, | |
| "addname": "", | |
| "x": 650, | |
| "y": 220, | |
| "wires": [ | |
| [ | |
| "b215271d477e76a1", | |
| "b022f80ec1f025d0" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "efcb1347e477233d", | |
| "type": "mqtt out", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "mqtt", | |
| "topic": "", | |
| "qos": "", | |
| "retain": "", | |
| "respTopic": "", | |
| "contentType": "", | |
| "userProps": "", | |
| "correl": "", | |
| "expiry": "", | |
| "broker": "d7efe4ef4af81eb9", | |
| "x": 1150, | |
| "y": 580, | |
| "wires": [] | |
| }, | |
| { | |
| "id": "3d3e1fea5d7df796", | |
| "type": "function", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "decode", | |
| "func": "var res = {};\nfor (const [key, value] of Object.entries(msg.payload)) {\n if (value.device_type) {\n name = value.room_name.replace(\" \", \"_\") + \"_\" + value.device_name.replace(\" \", \"_\");\n if (!(value.device_type in res))\n res[value.device_type] = {};\n res[value.device_type][name] = value;\n }\n}\nreturn [ { \"payload\": res[1] }, { \"payload\": res[3] }, { \"payload\": res[4] }, res ];", | |
| "outputs": 4, | |
| "noerr": 0, | |
| "initialize": "", | |
| "finalize": "", | |
| "libs": [], | |
| "x": 420, | |
| "y": 780, | |
| "wires": [ | |
| [], | |
| [ | |
| "f9b774ccf31a5c1f" | |
| ], | |
| [], | |
| [] | |
| ] | |
| }, | |
| { | |
| "id": "dca227a30d266fdf", | |
| "type": "comment", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "mqtt send", | |
| "info": "send/receive to mqtt", | |
| "x": 420, | |
| "y": 720, | |
| "wires": [] | |
| }, | |
| { | |
| "id": "f9b774ccf31a5c1f", | |
| "type": "split", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "", | |
| "splt": "\\n", | |
| "spltType": "str", | |
| "arraySplt": 1, | |
| "arraySpltType": "len", | |
| "stream": false, | |
| "addname": "", | |
| "x": 590, | |
| "y": 780, | |
| "wires": [ | |
| [ | |
| "8d6bf2e8cf66f9fb" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "4d772a73d166d0d8", | |
| "type": "mqtt in", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "", | |
| "topic": "", | |
| "qos": "2", | |
| "datatype": "auto", | |
| "broker": "d7efe4ef4af81eb9", | |
| "nl": false, | |
| "rap": true, | |
| "rh": 0, | |
| "inputs": 1, | |
| "x": 850, | |
| "y": 780, | |
| "wires": [ | |
| [ | |
| "b06952c575c8a5a6" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "8d6bf2e8cf66f9fb", | |
| "type": "function", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "subscribe", | |
| "func": "var msgo = {}\nmsgo.action = 'subscribe'\nmsgo.topic = 'maxcube2mqtt/thermostat/' + msg.payload.room_name.replace(\" \", \"_\") + \"/setpoint/set\";\nvar persist = flow.get('persist', 'file');\nif (typeof persist == 'undefined') {\n persist = {};\n}\npersist[msgo.topic] = msg.payload.rf_address;\nflow.set('persist', persist, 'file');\nreturn msgo;", | |
| "outputs": 1, | |
| "timeout": "", | |
| "noerr": 0, | |
| "initialize": "", | |
| "finalize": "", | |
| "libs": [], | |
| "x": 720, | |
| "y": 780, | |
| "wires": [ | |
| [ | |
| "4d772a73d166d0d8" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "b06952c575c8a5a6", | |
| "type": "function", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "get_rfaddress", | |
| "func": "var persist = flow.get('persist', 'file');\nreturn { \"payload\": { \"rf_address\": persist[msg.topic], \"degrees\": parseFloat(msg.payload), \"mode\": \"MANUAL\" } };", | |
| "outputs": 1, | |
| "noerr": 0, | |
| "initialize": "", | |
| "finalize": "", | |
| "libs": [], | |
| "x": 1000, | |
| "y": 780, | |
| "wires": [ | |
| [ | |
| "1b8a19e60d1941d5" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "b6d09b6a82b25db2", | |
| "type": "delay", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "", | |
| "pauseType": "delay", | |
| "timeout": "5", | |
| "timeoutUnits": "seconds", | |
| "rate": "1", | |
| "nbRateUnits": "1", | |
| "rateUnits": "second", | |
| "randomFirst": "1", | |
| "randomLast": "5", | |
| "randomUnits": "seconds", | |
| "drop": false, | |
| "allowrate": false, | |
| "outputs": 1, | |
| "x": 1300, | |
| "y": 780, | |
| "wires": [ | |
| [ | |
| "248a31587c7960fe" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "1b8a19e60d1941d5", | |
| "type": "maxcube in", | |
| "z": "103b1fd4c70bd5ad", | |
| "server": "9a07e5adcaeb56f7", | |
| "x": 1160, | |
| "y": 780, | |
| "wires": [ | |
| [ | |
| "b6d09b6a82b25db2" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "7897f3ffd2481dcc", | |
| "type": "inject", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "on start", | |
| "props": [], | |
| "repeat": "", | |
| "crontab": "", | |
| "once": true, | |
| "onceDelay": "1", | |
| "topic": "", | |
| "x": 120, | |
| "y": 780, | |
| "wires": [ | |
| [ | |
| "d0d37f63eb3c771c" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "d0d37f63eb3c771c", | |
| "type": "maxcube out", | |
| "z": "103b1fd4c70bd5ad", | |
| "server": "9a07e5adcaeb56f7", | |
| "singleMessage": true, | |
| "x": 260, | |
| "y": 780, | |
| "wires": [ | |
| [ | |
| "3d3e1fea5d7df796" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "1201580fe85fe424", | |
| "type": "subflow:bae136fa5a77790e", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "", | |
| "x": 160, | |
| "y": 180, | |
| "wires": [ | |
| [ | |
| "554700ca0a7b0288" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "91688cf578b02dfa", | |
| "type": "function", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "boiler state timer", | |
| "func": "if (msg.payload == 'ON') {\n msg.payload = 300;\n return msg;\n}\nreturn null;\n", | |
| "outputs": 1, | |
| "timeout": "", | |
| "noerr": 0, | |
| "initialize": "", | |
| "finalize": "", | |
| "libs": [], | |
| "x": 780, | |
| "y": 360, | |
| "wires": [ | |
| [ | |
| "add1600a8c24f3a4" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "add1600a8c24f3a4", | |
| "type": "mqtt out", | |
| "z": "103b1fd4c70bd5ad", | |
| "name": "mqtt boiler state", | |
| "topic": "cmnd/tasmota_F4295B/RuleTimer1", | |
| "qos": "0", | |
| "retain": "false", | |
| "respTopic": "", | |
| "contentType": "", | |
| "userProps": "", | |
| "correl": "", | |
| "expiry": "", | |
| "broker": "d7efe4ef4af81eb9", | |
| "x": 980, | |
| "y": 360, | |
| "wires": [] | |
| }, | |
| { | |
| "id": "d7efe4ef4af81eb9", | |
| "type": "mqtt-broker", | |
| "name": "MQTT", | |
| "broker": "10.68.69.5", | |
| "port": "1883", | |
| "clientid": "nodered", | |
| "autoConnect": true, | |
| "usetls": false, | |
| "protocolVersion": "4", | |
| "keepalive": "60", | |
| "cleansession": true, | |
| "autoUnsubscribe": true, | |
| "birthTopic": "nodered/status", | |
| "birthQos": "0", | |
| "birthRetain": "true", | |
| "birthPayload": "online", | |
| "birthMsg": {}, | |
| "closeTopic": "nodered/status", | |
| "closeQos": "0", | |
| "closeRetain": "true", | |
| "closePayload": "offline", | |
| "closeMsg": {}, | |
| "willTopic": "nodered/status", | |
| "willQos": "0", | |
| "willRetain": "true", | |
| "willPayload": "timeout", | |
| "willMsg": {}, | |
| "userProps": "", | |
| "sessionExpiry": "" | |
| }, | |
| { | |
| "id": "9a07e5adcaeb56f7", | |
| "type": "maxcube-server", | |
| "host": "10.68.69.120", | |
| "port": "62910", | |
| "disabled": false | |
| }, | |
| { | |
| "id": "3ef729ba23274c73", | |
| "type": "global-config", | |
| "env": [], | |
| "modules": { | |
| "node-red-contrib-home-assistant-websocket": "0.77.2", | |
| "node-red-contrib-maxcube2": "0.3.5" | |
| } | |
| } | |
| ] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment