Opentherm Thermostat

Hi guys,
I want to share my implementation of Opentherm Tasmota and its integration with a template node in Node Red Dashboard.
I use it to remotely command the central heating boiler into my holiday house.
The hardware is based on a Wemos D1 ESP8266, with just an Opentherm Shield for levels compensation and a DS18B20 digital temperature sensor.

This is the Dashboard Template i made (with some CSS involved):

  • on the left panel the measured temperature (DS18B20 sensor)
  • at its right, the temperature setpoint
  • at the far right, on top the power button which has three state, off (greyed out), auto (blue), heating on (red) ... this is a clickable / status button
  • at its bottom, the flame status (greyed = off, red = on)
  • under temp set point the two buttons to increase the temp set point or decrease it (clickable buttons with icons)
  • at the very bottom, a string with all the most important datas coming from Opentherm communication with boiler

Here with heating turned off, ambient temperature = 17,3 C and setpoint ad 19,5 C

Heating turned on (auto) but setpoint lower than ambient temperature

Heater turned on but flame not yet on.

Heating turned on and boiler flame on

In the opentherm message status row some informations are displayed, such as:
connection status
Flame modulation
Boiler temperature (measured)
Water temperature (measured)
Central heating status (1 / 0)
Flame status (1 / 0)
Boiler temperature (setpoint)
Water temperature (setpoint)
Water pressure
Fault status

I hope someone enjoy, feel free to ask for more information!

8 Likes

Would you perhaps share you code?

1 Like

Sure,
here it is.

Screenshot

Code

[
    {
        "id": "7bd28316dc37d295",
        "type": "tab",
        "label": "Thermo2",
        "disabled": true,
        "info": "",
        "env": []
    },
    {
        "id": "d721b34520a32a61",
        "type": "change",
        "z": "7bd28316dc37d295",
        "name": "temp_set",
        "rules": [
            {
                "t": "set",
                "p": "temp_set",
                "pt": "flow",
                "to": "19.5",
                "tot": "num"
            },
            {
                "t": "set",
                "p": "temp_set",
                "pt": "msg",
                "to": "temp_set",
                "tot": "flow"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 300,
        "y": 280,
        "wires": [
            [
                "fbd7edfb9e617ee1"
            ]
        ]
    },
    {
        "id": "fbd7edfb9e617ee1",
        "type": "change",
        "z": "7bd28316dc37d295",
        "name": "temp_amb",
        "rules": [
            {
                "t": "set",
                "p": "temp_amb",
                "pt": "flow",
                "to": "20.0",
                "tot": "num"
            },
            {
                "t": "set",
                "p": "temp_amb",
                "pt": "msg",
                "to": "temp_amb",
                "tot": "flow"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 450,
        "y": 280,
        "wires": [
            [
                "5e92c010cbf93331"
            ]
        ]
    },
    {
        "id": "ae894b52eb94ae0b",
        "type": "ui_template",
        "z": "7bd28316dc37d295",
        "group": "e15b980fd008f6a8",
        "name": "Thermostat Template",
        "order": 4,
        "width": "6",
        "height": "4",
        "format": "<style>\n    . {\n        box-sizing: border-box;\n        font-family: \"Roboto\",\"Helvetica Neue\", sans-serif ;\n    }\n\n    .container {\n        display: flex;\n        width: 100%;\n        height: 100%;\n        background-color: #303030;\n    }\n\n\n    .centerme {\n        display: flex;\n        text-align: center;\n        justify-content: center;\n        align-items: center;\n        margin: 4px;\n    }\n\n    .roundme {\n        border: 2px solid black;\n        border-radius: 8px;\n        background-color: #222222;\n        box-shadow: inset 2px 2px 3px 4px rgba(0, 0, 0, 0.1);\n        background: rgb(5, 5, 5);\n        background: linear-gradient(135deg, rgba(5, 5, 5, 1) 0%, rgba(42, 42, 42, 1) 100%);\n        margin: 3px;\n    }\n    \n    .roundme2 {\n        border: 2px solid black;\n        border-radius: 8px;\n        background-color: #222222;\n        box-shadow: inset 2px 2px 3px 4px rgba(0, 0, 0, 0.1);\n        background: rgb(5, 5, 5);\n        margin: 3px;\n    }\n\n    .a1 {\n        /*    background-color:red; */\n        height: 25px;\n        margin-bottom: 1px;\n        font-size: 16px;\n        color: #6689A1;\n        padding-bottom: 4px;\n        border-bottom: 2px solid #DD7F00;\n\n    }\n\n    .a2 {\n        /*    background-color:red; */\n        height: 100%;\n        margin-top: 1px;\n        font-size: 60px;\n        color: #D7DBDD;\n\n    }\n\n    .b1 {\n        color: #6689A1;\n        height: 25px;\n        margin-bottom: 1px;\n        font-size: 16px;\n        padding-bottom: 4px;\n        border-bottom: 2px solid #DD7F00;\n    }\n\n    .b2 {\n        height: 100%;\n        margin-top: 1px;  \n        font-size: 28px;\n        color: #D7DBDD;\n    }\n\n    .gradient-2 {\n    background: linear-gradient(135deg, rgba(5, 5, 5, 1) 0%, rgba(42, 42, 42, 1) 100%) padding-box,\n    linear-gradient(to right, #F16F0F, #F43700) border-box;\n    margin-top:14px;\n    border-radius: 20px;\n    border: 6px solid transparent;\n    }\n    \n    .red_color {\n        color: #FF0000;\n    }\n    \n    .grey_color {\n        color: #444444;\n    }\n\n    .blue_color {\n        color: #00DAF4;\n    }\n    \n    \n    .otstatus {\n        padding-left: 6px;\n        padding-top: 2px;\n        font-size: 14px;\n\n    }\n\n@keyframes fire {\n  from {color: #FF5B33;}\n  50% {color: #FFAC33;}\n  to {color: #FF5B33;}\n}\n\n.on_fire {\n  animation-name: fire;\n  animation-duration: 2000ms;\n  animation-iteration-count:infinite;\n}\n\n\n\n</style>\n\n<div class=\"container\" layout=\"column\">\n    <div layout=\"row\" flex=\"80\">\n        <div layout=\"column\" flex=\"50\" class=\"roundme\">\n            <div class=\"a1 centerme\">Temp Ambiente</div>\n            <div class=\"a2 centerme\" ng-class=\"temp_amb_status\" ng-model=\"temp_amb_status\" ng-bind-html=\"temp_amb_ | number: 1\"></div>\n        </div>\n    \n        <div flex=\"50\" layout=\"column\">\n            <div flex=\"70\" layout=\"row\">\n    \n                <div layout=\"column\" flex=\"60\" class=\"roundme\">\n                    <div class=\"b1 centerme\">Temp Set</div>\n                    <div class=\"b2 centerme\"  ng-bind-html=\"temp_set_ | number: 1\" ></div>\n                </div>\n    \n                <div flex=\"40\" layout=\"column\">\n                    <div flex=\"50\" class=\"centerme roundme\" ng-click=\"click_power();\">\n                        <md-icon md-font-icon=\"power_settings_new\" style=\"font-size:32px\" ng-class=\"power_status_icon\"></md-icon>\n                    </div>\n                    <div flex=\"50\" class=\"centerme roundme\">\n                        <md-icon md-font-icon=\"local_fire_department\" style=\"font-size:32px\" ng-class=\"heating_status_icon\"></md-icon>\n                    </div>\n                </div>\n    \n            </div>\n            <div flex=\"30\">\n                <div layout=\"row\" style=\"height:100%\">\n                    <md-button flex=\"50\" class=\"centerme roundme\" ng-click=\"click_temp_minus()\">\n                        <md-icon md-font-icon=\"remove\" style=\"font-size:32px\"></md-icon>\n                    </md-button>\n                    <md-button flex=\"50\" class=\"centerme roundme\"  ng-click=\"click_temp_plus()\">\n                        <md-icon md-font-icon=\"add\" style=\"font-size:32px\"></md-icon>\n                    </md-button>\n                </div>\n            </div>\n        </div>\n    </div>\n\n    <div layout=\"row\" flex=\"20\" class=\"roundme2 otstatus\">\n        <div layout=\"column\">    \n            <div flex=\"50\" ng-bind-html=\"ot_status1\"></div>\n            <div flex=\"50\" ng-bind-html=\"ot_status2\"></div>\n        </div>\n    </div>\n</div>\n\n<script>\n    (function(scope) {\n\n  scope.$watch('msg', function(msg) \n    {\n\n        if(msg.hasOwnProperty('temp_set')) {\n        scope.temp_set_ = msg.temp_set;\n        }\n\n        if(msg.hasOwnProperty('temp_amb')) {\n                scope.temp_amb_ = msg.temp_amb;\n        }\n\n        if(msg.hasOwnProperty('heating')) {\n            if(msg.heating==\"on\") {\n                scope.temp_amb_status=\"gradient-2\";\n            }\n            if(msg.heating==\"off\") {\n                scope.temp_amb_status=\"\";\n            }     \n        }\n    \n        // Opentherm status\n        if(msg.hasOwnProperty('ot_status1')) {\n            scope.ot_status1 = msg.ot_status1;\n            scope.ot_status2 = msg.ot_status2;\n        }\n\n        // Power status check    \n        if(msg.hasOwnProperty('power_status')) {\n            if(msg.power_status==true) {\n                scope.power_status_icon=\"blue_color\";\n            }\n            if(msg.power_status==false) {\n                scope.power_status_icon=\"grey_color\";\n            }     \n        }\n\n        // Heating status check\n        if(msg.hasOwnProperty('heating_status')) {\n            if(msg.heating_status==1) {\n                scope.power_status_icon=\"red_color\";\n            }\n        }\n    \n        // Flame status check\n        if(msg.hasOwnProperty('flame_status')) {\n            if(msg.flame_status==true) {\n//                scope.heating_status_icon=\"red_color\";\n                scope.heating_status_icon=\"on_fire\";\n\n            }\n            if(msg.flame_status==false) {\n                scope.heating_status_icon=\"grey_color\";\n            }\n        }\n        // End flame status check //\n\n        return;\n    });  \n\n    scope.click_power = function() {\n        scope.send({ \"payload\": \"power\"});\n    }\n\n    scope.click_temp_plus = function() {\n        scope.send({ \"payload\": \"temp_plus\"});\n    }\n\n    scope.click_temp_minus = function() {\n        scope.send({ \"payload\": \"temp_minus\"});\n    }\n  \n})(scope);\n\n</script>\n\n",
        "storeOutMessages": false,
        "fwdInMessages": false,
        "resendOnRefresh": false,
        "templateScope": "local",
        "className": "",
        "x": 920,
        "y": 380,
        "wires": [
            [
                "da16bc54c2ef5db2"
            ]
        ]
    },
    {
        "id": "da16bc54c2ef5db2",
        "type": "function",
        "z": "7bd28316dc37d295",
        "name": "Thermostat logic",
        "func": "var power_status = flow.get('power_status');\nvar temp_set = flow.get('temp_set'); \nvar temp_amb = flow.get('temp_amb');\nvar heating_status = flow.get('heating_status');\nvar ot_status1 =  flow.get('ot_status1');\nvar ot_status2 =  flow.get('ot_status2');\nvar flame_status =  flow.get('flame_status');\nvar ch_status =  flow.get('ch_status');\nvar msg2 = { payload: \"payload\", topic: \"topic\" }\n\nif(msg.hasOwnProperty('ot_status1')){\n    flow.set('ot_status1',msg.ot_status1);\n    flow.set('ot_status2',msg.ot_status2);\n}\n\nif(msg.hasOwnProperty('flame_status')){\n    flow.set('flame_status',msg.flame_status);\n}\n\nif(msg.hasOwnProperty('ch_status')){\n    flow.set('ch_status',msg.ch_status);\n}\n\nif(msg.payload==\"power\"){\n    power_status = !power_status;\n    flow.set('power_status',power_status);\n}\n\nif(msg.payload==\"temp_plus\"){\n    temp_set = temp_set + 0.5;\n    flow.set('temp_set',temp_set);\n}\n\nif(msg.payload==\"temp_minus\"){\n    temp_set = temp_set - 0.5;\n    flow.set('temp_set',temp_set);\n}\n\nif(power_status){\n    if(heating_status)\n    {\n\n        // riscaldamento acceso e temperatura set minore o uguale di temp ambiente\n        if (temp_set <= temp_amb+0.2) {\n            heating_status = false;\n        }\n    }\n    else\n    {\n        // riscaldamento spento e temperatura set maggiore di temp ambiente\n        if (temp_set > temp_amb+0.2) {\n            heating_status = true;\n        }\n\n    } \n\n    flow.set('heating_status', heating_status);\n}\nelse{\n    heating_status = false;\n    flow.set('heating_status', heating_status); \n}\n\nmsg.power_status = flow.get('power_status');\nmsg.temp_amb = flow.get('temp_amb');\nmsg.temp_set = flow.get('temp_set');\nmsg.ot_status1 = flow.get('ot_status1');\nmsg.ot_status2 = flow.get('ot_status2');\nmsg.flame_status = flow.get('flame_status');\nmsg.ch_status = flow.get('ch_status');\nmsg.heating_status = flow.get('heating_status');\n\nif (flow.get('heating_status')) {\n msg2.payload = 1;\n} else {\n msg2.payload = 0;\n}\n\nreturn [msg, msg2];",
        "outputs": 2,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 910,
        "y": 440,
        "wires": [
            [
                "ae894b52eb94ae0b"
            ],
            [
                "9733bb3381da8ff6"
            ]
        ]
    },
    {
        "id": "a9865b0db96580e8",
        "type": "change",
        "z": "7bd28316dc37d295",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "true",
                "tot": "bool"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 660,
        "y": 600,
        "wires": [
            [
                "da16bc54c2ef5db2"
            ]
        ]
    },
    {
        "id": "3293b42b8867bdb3",
        "type": "switch",
        "z": "7bd28316dc37d295",
        "name": "",
        "property": "payload",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "connect",
                "vt": "str"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 1,
        "x": 510,
        "y": 600,
        "wires": [
            [
                "a9865b0db96580e8"
            ]
        ]
    },
    {
        "id": "820176597df91726",
        "type": "ui_ui_control",
        "z": "7bd28316dc37d295",
        "name": "",
        "events": "connect",
        "x": 340,
        "y": 600,
        "wires": [
            [
                "3293b42b8867bdb3"
            ]
        ]
    },
    {
        "id": "5c6643565e2ddab2",
        "type": "inject",
        "z": "7bd28316dc37d295",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": true,
        "onceDelay": "0.2",
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 370,
        "y": 640,
        "wires": [
            [
                "3293b42b8867bdb3"
            ]
        ]
    },
    {
        "id": "5e92c010cbf93331",
        "type": "change",
        "z": "7bd28316dc37d295",
        "name": "power_status",
        "rules": [
            {
                "t": "set",
                "p": "power_status",
                "pt": "flow",
                "to": "false",
                "tot": "bool"
            },
            {
                "t": "set",
                "p": "power_status",
                "pt": "msg",
                "to": "power_status",
                "tot": "flow"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 620,
        "y": 280,
        "wires": [
            [
                "c98ab4ede699f7b7"
            ]
        ]
    },
    {
        "id": "c98ab4ede699f7b7",
        "type": "change",
        "z": "7bd28316dc37d295",
        "name": "heating_status",
        "rules": [
            {
                "t": "set",
                "p": "heating_status",
                "pt": "flow",
                "to": "false",
                "tot": "bool"
            },
            {
                "t": "set",
                "p": "heating_status",
                "pt": "msg",
                "to": "heating_status",
                "tot": "flow"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 180,
        "y": 340,
        "wires": [
            [
                "60021c373e8cdb53"
            ]
        ]
    },
    {
        "id": "5cb475e23794806d",
        "type": "inject",
        "z": "7bd28316dc37d295",
        "name": "",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": true,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "true",
        "payloadType": "bool",
        "x": 150,
        "y": 280,
        "wires": [
            [
                "d721b34520a32a61"
            ]
        ]
    },
    {
        "id": "5c63f60ed55988e0",
        "type": "mqtt in",
        "z": "7bd28316dc37d295",
        "name": "",
        "topic": "tele/thermostat/SENSOR",
        "qos": "1",
        "datatype": "auto-detect",
        "broker": "51912773f7db93ee",
        "nl": false,
        "rap": true,
        "rh": 0,
        "inputs": 0,
        "x": 170,
        "y": 420,
        "wires": [
            [
                "191edada74781373",
                "d3347086d32027ca",
                "d321e94ddc708b4a",
                "5624399ecc1ccfc9"
            ]
        ]
    },
    {
        "id": "191edada74781373",
        "type": "change",
        "z": "7bd28316dc37d295",
        "name": "payload.DS18B20.Temperature",
        "rules": [
            {
                "t": "set",
                "p": "temp_amb",
                "pt": "flow",
                "to": "payload.DS18B20.Temperature",
                "tot": "msg"
            },
            {
                "t": "set",
                "p": "temp_amb",
                "pt": "msg",
                "to": "temp_amb",
                "tot": "flow"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 530,
        "y": 420,
        "wires": [
            [
                "da16bc54c2ef5db2"
            ]
        ]
    },
    {
        "id": "ae60fe1eeac4218f",
        "type": "mqtt out",
        "z": "7bd28316dc37d295",
        "name": "",
        "topic": "cmnd/thermostat/ot_tboiler",
        "qos": "1",
        "retain": "",
        "respTopic": "",
        "contentType": "",
        "userProps": "",
        "correl": "",
        "expiry": "",
        "broker": "51912773f7db93ee",
        "x": 400,
        "y": 100,
        "wires": []
    },
    {
        "id": "8af3775d92279529",
        "type": "inject",
        "z": "7bd28316dc37d295",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "3600",
        "crontab": "",
        "once": true,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "60",
        "payloadType": "num",
        "x": 150,
        "y": 100,
        "wires": [
            [
                "ae60fe1eeac4218f"
            ]
        ]
    },
    {
        "id": "d3347086d32027ca",
        "type": "switch",
        "z": "7bd28316dc37d295",
        "name": "OPENTHERM",
        "property": "payload.OPENTHERM",
        "propertyType": "msg",
        "rules": [
            {
                "t": "hask",
                "v": "conn",
                "vt": "str"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 1,
        "x": 460,
        "y": 480,
        "wires": [
            [
                "9925554e77622b21"
            ]
        ]
    },
    {
        "id": "9925554e77622b21",
        "type": "function",
        "z": "7bd28316dc37d295",
        "name": "OT MESSAGE",
        "func": "msg.ot_status1 = msg.payload.OPENTHERM.conn +\n    \"&nbsp&nbsp&nbsp&nbspFLM:\" + msg.payload.OPENTHERM.FLM +\n    \"&nbsp&nbsp&nbsp&nbspTB:\" + msg.payload.OPENTHERM.TB + \n    \"&nbsp&nbsp&nbsp&nbspTW:\" + msg.payload.OPENTHERM.TDHW + \n    \"&nbsp&nbsp&nbsp&nbspCH:\" + msg.payload.OPENTHERM.SLAVE.CH + \n    \"&nbsp&nbsp&nbsp&nbspFL:\" + msg.payload.OPENTHERM.SLAVE.FL;\n    \nmsg.ot_status2 = \"TBS:\" + msg.payload.OPENTHERM.BTMP.REQ +\n    \"&nbsp&nbsp&nbsp&nbspTWS:\" + msg.payload.OPENTHERM.HWTMP.REQ + \n    \"&nbsp&nbsp&nbsp&nbspWP:\" + msg.payload.OPENTHERM.OT18 +\n    \"&nbsp&nbsp&nbsp&nbspFAULT:\" + msg.payload.OPENTHERM.SLAVE.FAULT;\n    \nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 660,
        "y": 480,
        "wires": [
            [
                "da16bc54c2ef5db2"
            ]
        ]
    },
    {
        "id": "60021c373e8cdb53",
        "type": "change",
        "z": "7bd28316dc37d295",
        "name": "ot_status",
        "rules": [
            {
                "t": "set",
                "p": "ot_status1",
                "pt": "flow",
                "to": "**********************************************",
                "tot": "str"
            },
            {
                "t": "set",
                "p": "ot_status1",
                "pt": "msg",
                "to": "ot_status1",
                "tot": "flow"
            },
            {
                "t": "set",
                "p": "ot_status2",
                "pt": "flow",
                "to": "**********************************************",
                "tot": "str"
            },
            {
                "t": "set",
                "p": "ot_status2",
                "pt": "msg",
                "to": "ot_status2",
                "tot": "flow"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 360,
        "y": 340,
        "wires": [
            [
                "bf555a791259f82e"
            ]
        ]
    },
    {
        "id": "9733bb3381da8ff6",
        "type": "mqtt out",
        "z": "7bd28316dc37d295",
        "name": "",
        "topic": "cmnd/thermostat/ot_ch",
        "qos": "1",
        "retain": "",
        "respTopic": "",
        "contentType": "",
        "userProps": "",
        "correl": "",
        "expiry": "",
        "broker": "51912773f7db93ee",
        "x": 1170,
        "y": 440,
        "wires": []
    },
    {
        "id": "bf555a791259f82e",
        "type": "change",
        "z": "7bd28316dc37d295",
        "name": "flame_status",
        "rules": [
            {
                "t": "set",
                "p": "flame_status",
                "pt": "flow",
                "to": "false",
                "tot": "bool"
            },
            {
                "t": "set",
                "p": "flame_status",
                "pt": "msg",
                "to": "flame_status",
                "tot": "flow"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 510,
        "y": 340,
        "wires": [
            [
                "7a139d8a4e8c1df7"
            ]
        ]
    },
    {
        "id": "d321e94ddc708b4a",
        "type": "switch",
        "z": "7bd28316dc37d295",
        "name": "OPENTHERM CH",
        "property": "payload.OPENTHERM.SLAVE",
        "propertyType": "msg",
        "rules": [
            {
                "t": "hask",
                "v": "CH",
                "vt": "str"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 1,
        "x": 470,
        "y": 520,
        "wires": [
            [
                "8bddba416ec36bef"
            ]
        ]
    },
    {
        "id": "8bddba416ec36bef",
        "type": "change",
        "z": "7bd28316dc37d295",
        "name": "CH STATUS",
        "rules": [
            {
                "t": "set",
                "p": "ch_status",
                "pt": "msg",
                "to": "payload.OPENTHERM.SLAVE.CH",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 670,
        "y": 520,
        "wires": [
            [
                "da16bc54c2ef5db2"
            ]
        ]
    },
    {
        "id": "5624399ecc1ccfc9",
        "type": "switch",
        "z": "7bd28316dc37d295",
        "name": "OPENTHERM FL",
        "property": "payload.OPENTHERM.SLAVE",
        "propertyType": "msg",
        "rules": [
            {
                "t": "hask",
                "v": "FL",
                "vt": "str"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 1,
        "x": 470,
        "y": 560,
        "wires": [
            [
                "30909829b5045b31"
            ]
        ]
    },
    {
        "id": "30909829b5045b31",
        "type": "change",
        "z": "7bd28316dc37d295",
        "name": "FL STATUS",
        "rules": [
            {
                "t": "set",
                "p": "flame_status",
                "pt": "msg",
                "to": "payload.OPENTHERM.SLAVE.FL",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 670,
        "y": 560,
        "wires": [
            [
                "da16bc54c2ef5db2"
            ]
        ]
    },
    {
        "id": "e577dd9a20a8218f",
        "type": "mqtt out",
        "z": "7bd28316dc37d295",
        "name": "",
        "topic": "cmnd/thermostat/ot_twater",
        "qos": "1",
        "retain": "",
        "respTopic": "",
        "contentType": "",
        "userProps": "",
        "correl": "",
        "expiry": "",
        "broker": "51912773f7db93ee",
        "x": 400,
        "y": 60,
        "wires": []
    },
    {
        "id": "5fa6a6aae36ea2b0",
        "type": "inject",
        "z": "7bd28316dc37d295",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "3600",
        "crontab": "",
        "once": true,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "36",
        "payloadType": "num",
        "x": 150,
        "y": 60,
        "wires": [
            [
                "e577dd9a20a8218f"
            ]
        ]
    },
    {
        "id": "7a139d8a4e8c1df7",
        "type": "change",
        "z": "7bd28316dc37d295",
        "name": "ch_status",
        "rules": [
            {
                "t": "set",
                "p": "ch_status",
                "pt": "flow",
                "to": "false",
                "tot": "bool"
            },
            {
                "t": "set",
                "p": "ch_status",
                "pt": "msg",
                "to": "ch_status",
                "tot": "flow"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 680,
        "y": 340,
        "wires": [
            [
                "da16bc54c2ef5db2"
            ]
        ]
    },
    {
        "id": "f5aafa28f45bf19d",
        "type": "mqtt out",
        "z": "7bd28316dc37d295",
        "name": "",
        "topic": "cmnd/thermostat/Restart",
        "qos": "",
        "retain": "",
        "respTopic": "",
        "contentType": "",
        "userProps": "",
        "correl": "",
        "expiry": "",
        "broker": "51912773f7db93ee",
        "x": 390,
        "y": 160,
        "wires": []
    },
    {
        "id": "7204c37b7a3eaae0",
        "type": "inject",
        "z": "7bd28316dc37d295",
        "name": "05:00",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "00 05 * * *",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "1",
        "payloadType": "num",
        "x": 150,
        "y": 160,
        "wires": [
            [
                "f5aafa28f45bf19d"
            ]
        ]
    },
    {
        "id": "fd52ae383a8b0694",
        "type": "inject",
        "z": "7bd28316dc37d295",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "3600",
        "crontab": "",
        "once": true,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "10",
        "payloadType": "num",
        "x": 150,
        "y": 220,
        "wires": [
            [
                "6cfe3bed14aba2f3"
            ]
        ]
    },
    {
        "id": "6cfe3bed14aba2f3",
        "type": "mqtt out",
        "z": "7bd28316dc37d295",
        "name": "",
        "topic": "cmnd/thermostat/TelePeriod",
        "qos": "",
        "retain": "",
        "respTopic": "",
        "contentType": "",
        "userProps": "",
        "correl": "",
        "expiry": "",
        "broker": "51912773f7db93ee",
        "x": 380,
        "y": 220,
        "wires": []
    },
    {
        "id": "e15b980fd008f6a8",
        "type": "ui_group",
        "name": "Termostato Borghi",
        "tab": "d9d243d87692d13f",
        "order": 10,
        "disp": true,
        "width": "6",
        "collapse": false,
        "className": ""
    },
    {
        "id": "51912773f7db93ee",
        "type": "mqtt-broker",
        "name": "Dummy MQTT",
        "broker": "0.0.0.0",
        "port": "1883",
        "clientid": "",
        "autoConnect": true,
        "usetls": false,
        "protocolVersion": "4",
        "keepalive": "60",
        "cleansession": true,
        "birthTopic": "",
        "birthQos": "0",
        "birthPayload": "",
        "birthMsg": {},
        "closeTopic": "",
        "closeQos": "0",
        "closePayload": "",
        "closeMsg": {},
        "willTopic": "",
        "willQos": "0",
        "willPayload": "",
        "willMsg": {},
        "userProps": "",
        "sessionExpiry": ""
    },
    {
        "id": "d9d243d87692d13f",
        "type": "ui_tab",
        "name": "Dashboard",
        "icon": "dashboard",
        "order": 1,
        "disabled": false,
        "hidden": false
    }
]

Absolutely outstanding, thanks

1 Like

In case you didn't think about it I would set limits on how high or low you can set the temp. I use 10 as a low limit and 25 as a high limit. This is a personal just because for me.

1 Like

In case you didn't think about it I would set limits on how high or low you can set the temp. I use 10 as a low limit and 25 as a high limit. This is a personal just because for me.

You're absolutely right.
Thanks

You'd need to be rich to afford that in the UK right now. :frowning: My max is 20!

1 Like