Synchronizing Two Thermostats in One Room

I have two Shelly TRV Blu thermostats in one room. I want to synchronize them using Node-RED.

I can read the values ​​from both TRVs and control them via Node-RED.

The control works perfectly as "Master" and "Slave."

Thermostat "A" is the Master. Its temperature is read and transmitted to "B" - everything works perfectly!

Is there a way to synchronize the control using a node or function, regardless of which thermostat is activated?

I've already tried several approaches, but all I've managed to do is create a loop.

If a change is received from thermostat "A," no information from "B" should be accepted so that "B" adopts the value from "A." The same applies in reverse.

I've implemented time delays, but unfortunately, all without success.

Does anyone have any suggestions?

Thanks a lot,

Thoralf

That's a good one ;-). I love brain teasers like this, but I just can't work out the solution. It must somehow work applying a trigger node (which prevents the loop and then is resetted if required)... Looking forward to see the solution :upside_down_face:

What delay time frame are you proposing to use after an update from either A or B before resetting?. At the moment your description says that once either A or B has transmitted they are the source of further updates

515 / 5.000
Hello,

This needs to be tested. I think one minute is sufficient. If "A" changes, the temperature of "B" doesn't need to be queried or processed for one minute. During this time, the changed value is transferred from "A" to "B". I'm thinking perhaps of a gate that alternately queries "A" and sends it to "B" every minute. Then the whole process is reversed. That's the theory. Regardless of which thermostat is being controlled, the temperature is transferred to the second thermostat with a one-minute delay.

Thoralf

I found an approach based on a context status (which distinguishes which of the thermostats is master/slave). Let me know if there is a more better, more clever solution. Since this is also a situation which I need to solve for own purposes...
Regards from Berlin

[
    {
        "id": "1f2c27eef130dd63",
        "type": "inject",
        "z": "8c0dae24.8d305",
        "name": "TH1 15°C",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "15",
        "payloadType": "num",
        "x": 310,
        "y": 1500,
        "wires": [
            [
                "9d0ac5763610abec",
                "8d40c3fcb45a5738"
            ]
        ]
    },
    {
        "id": "3c3ab2fa498fc76d",
        "type": "change",
        "z": "8c0dae24.8d305",
        "name": "TH1",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "payload",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 750,
        "y": 1500,
        "wires": [
            [
                "9d3737f21517ac72",
                "f9792735685d4a84"
            ]
        ]
    },
    {
        "id": "d99210759eab716c",
        "type": "inject",
        "z": "8c0dae24.8d305",
        "name": "TH1 30°C",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "30",
        "payloadType": "num",
        "x": 310,
        "y": 1550,
        "wires": [
            [
                "9d0ac5763610abec",
                "8d40c3fcb45a5738"
            ]
        ]
    },
    {
        "id": "b852afadd8ce0bd7",
        "type": "debug",
        "z": "8c0dae24.8d305",
        "name": "debug 25",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 1180,
        "y": 1500,
        "wires": []
    },
    {
        "id": "9d3737f21517ac72",
        "type": "change",
        "z": "8c0dae24.8d305",
        "name": "generate string",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "\"TH1: \" & $round(payload,1) & \" °C\"",
                "tot": "jsonata"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 950,
        "y": 1500,
        "wires": [
            [
                "b852afadd8ce0bd7"
            ]
        ]
    },
    {
        "id": "e818830c7fbca9b7",
        "type": "inject",
        "z": "8c0dae24.8d305",
        "name": "TH2 18°C",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "18",
        "payloadType": "num",
        "x": 310,
        "y": 1700,
        "wires": [
            [
                "b1f590fcf544cce6",
                "bd0ce751311967b9"
            ]
        ]
    },
    {
        "id": "0b4f9dd898cc88a7",
        "type": "change",
        "z": "8c0dae24.8d305",
        "name": "TH2",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "payload",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 750,
        "y": 1700,
        "wires": [
            [
                "aad148b13af5092c",
                "1080d434363aa06f"
            ]
        ]
    },
    {
        "id": "6faa62222e7814dd",
        "type": "inject",
        "z": "8c0dae24.8d305",
        "name": "TH2 25°C",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "25",
        "payloadType": "num",
        "x": 310,
        "y": 1750,
        "wires": [
            [
                "b1f590fcf544cce6",
                "bd0ce751311967b9"
            ]
        ]
    },
    {
        "id": "ec52be26f0b9578e",
        "type": "debug",
        "z": "8c0dae24.8d305",
        "name": "debug 27",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 1180,
        "y": 1700,
        "wires": []
    },
    {
        "id": "aad148b13af5092c",
        "type": "change",
        "z": "8c0dae24.8d305",
        "name": "generate string",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "\"TH2: \" & $round(payload,1) & \" °C\"",
                "tot": "jsonata"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 950,
        "y": 1700,
        "wires": [
            [
                "ec52be26f0b9578e"
            ]
        ]
    },
    {
        "id": "9d0ac5763610abec",
        "type": "change",
        "z": "8c0dae24.8d305",
        "name": "set TH1 as master",
        "rules": [
            {
                "t": "set",
                "p": "TH1",
                "pt": "flow",
                "to": "master",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 550,
        "y": 1500,
        "wires": [
            [
                "3c3ab2fa498fc76d"
            ]
        ]
    },
    {
        "id": "bd0ce751311967b9",
        "type": "change",
        "z": "8c0dae24.8d305",
        "name": "set TH1 as slave",
        "rules": [
            {
                "t": "set",
                "p": "TH1",
                "pt": "flow",
                "to": "slave",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 550,
        "y": 1750,
        "wires": [
            []
        ]
    },
    {
        "id": "b1f590fcf544cce6",
        "type": "change",
        "z": "8c0dae24.8d305",
        "name": "set TH2 as master",
        "rules": [
            {
                "t": "set",
                "p": "TH2",
                "pt": "flow",
                "to": "master",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 550,
        "y": 1700,
        "wires": [
            [
                "0b4f9dd898cc88a7"
            ]
        ]
    },
    {
        "id": "8d40c3fcb45a5738",
        "type": "change",
        "z": "8c0dae24.8d305",
        "name": "set TH2 as slave",
        "rules": [
            {
                "t": "set",
                "p": "TH2",
                "pt": "flow",
                "to": "slave",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 550,
        "y": 1550,
        "wires": [
            []
        ]
    },
    {
        "id": "1080d434363aa06f",
        "type": "switch",
        "z": "8c0dae24.8d305",
        "name": "only if TH1 = slave",
        "property": "TH1",
        "propertyType": "flow",
        "rules": [
            {
                "t": "eq",
                "v": "slave",
                "vt": "str"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 1,
        "x": 960,
        "y": 1650,
        "wires": [
            [
                "3c3ab2fa498fc76d"
            ]
        ]
    },
    {
        "id": "f9792735685d4a84",
        "type": "switch",
        "z": "8c0dae24.8d305",
        "name": "only if TH2 = slave",
        "property": "TH2",
        "propertyType": "flow",
        "rules": [
            {
                "t": "eq",
                "v": "slave",
                "vt": "str"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 1,
        "x": 960,
        "y": 1550,
        "wires": [
            [
                "0b4f9dd898cc88a7"
            ]
        ]
    }
]

Hello,

It works for me!!!

I understand how it works.

My approach was two automatically switching gates that alternately open the query "A" and send it to "B" and then open the other gate. This was done with a time delay so that both thermostats have the same temperature.

I almost understand your solution. It works, and that's crucial. Thank you very much.

To explain my devices:

  • query the status of both TRV Shelly devices via MQTT

  • select the set temperature

  • then your control process kicks in

  • then the new value is transmitted to both TRV devices via MQTT

Thoralf


flows.json (11.7 KB)

1 Like

Not quite sure what the aim is here but would it not be better to have a room thermometer that was the master to update both TRV's?

Hello,

You can look at it however you want. Not everyone in the family understands the "master-slave" principle. I also use a Shelly wall display. With this setup, I only need to configure one TRV (Temperature Meter) on the display. Since all TRVs in our case have the same temperature, it's much simpler for "normal" people. Yes, it's definitely easier to program with a fixed master. The Shelly app doesn't handle it well. You can group TRVs together, but the temperature is then only transmitted to all TRVs via the app. However, if the temperature is adjusted mechanically directly on the TRV, this isn't displayed in the group.

Thanks for all the contributions!

Thoralf