Question: Synchronize or mirror state of 2 devices

I am using Node Red for Smarthome automation and have decided that I want to have logical or virtual devices for everyplace I expect to automate with those devices tied to nodes for the physical device serving that role. For Example:

  • Virtual Device: Desk Lamp
  • Physical Device: Ikea Zigbee bulb

I am doing this so that if I replace the Ikea bulb with a Philips Hue bulb, then all I have to do is update the linkage between the Virtual and Physical. All of my normal automation only ever interacts with the Virtual Device.

One thing that I am trying to accomplish is to allow most interactions to be with the Virtual device, but to allow changes that happen via the Physical devices app or other control to both change the physical device and then update the state of the Virtual device to reflect that change.

I have used MQTT for a variety of situations and can imagine building the linkages that way, but because time counts in Smarthome responsiveness, I am hoping to not have to do MQTT roundtrips.

Does anyone have an existing flow that keeps two devices in synch?

I do this with most of my interactions. It also lets you build standard MQTT topic structures even when using multiple different interface types (e.g. Zigbee2MQTT, Tasmota and 433MHz LightwaveRF).

The additional lag, even with some quite complex processing is below human threshold. As long as you aren't overloading your Node-RED server.

I use MQTT as a bus between NodeRed and my HomeSeer hub (and other control/status connectors for non ZWave devices) where I setup a standard taxonomy for all my devices /home/{room}/{device}. Then to add more complexity to it, I feed all of the MQTT topics in NodeRed into NORA so I can use Google Assistant to control everything. For some of my devices I feed their status into Global Variables as well to have them available for key flows (for example knowing that a door is open/closed prior to allowing they system to try to lock it).

Key is to be careful of creating infinite loops in any of your flows that respond to a status report from an MQTT topic.

Thanks for the feedback. I have put together an example of what I was trying to do.

I have a Credenza with a built in light that I control by turning on or off an IKEA outlet. The Outlet is controlled by a Hubitat hub. That Hub is linked to Node Red. I also have a virtual outlet controlled by a separate Hubitat hub. This virtual item is also linked to Amazon Alexa using Hubitat's Alexa skill.

I am looking to have a lot of flexibility in controlling my smart devices. Here are all the ways this outlet will be controllable once I am done:

  1. Node Red Dashboard
  2. Node Red connected UIBuilder based Dashboard
  3. Hubitat UI from actual device hub
  4. Hubitat UI from virtual device hub
  5. Alexa Voice
  6. Alexa App (pc + phone)
  7. Google Home Voice
  8. Google Home App (phone)
  9. Google Nest Hub Max
  10. Home Assistant UI
  11. Apple Homekit via Node Red to Home Assistant to Homekit

Key to making this work is to update the status of the outlet on all UIs regardless of which one it was last changed on. So based on this I have now put together the following flow:

This is already working and synchronizing for the following:

  • Node Red Dashboard
  • Hubitat UI from actual device hub
  • Hubitat UI from virtual device hub
  • Alexa Voice
  • Alexa App (pc + phone)
  • Google Home Voice
  • Google Home App (phone)
  • Google Nest Hub Max

All of the function nodes could be replaced with standard nodes, but I just find it easier to think in code. I am using the following non-built in pallets:

  • node-red-contrib-noop
  • node-red-contrib-hubitat
  • node-red-contrib-smartnora
  • node-red-dashboard

All in all I find it amazing that Node Red can with a fairly small flow knit together and synchronize them. Of course it helps that Hubitat talks to Alexa and Home Assistant talks to Homekit, but still amazing.

The key reason for jumping through all of these hoops up front is to allow me to easily swap out an Ikea outlet controlled by Hubitat for a random zigbee outlet controlled by Zigbee2MQTT if the IKEA outlet ever dies. Under a circumstance like that all I would have to change is the control shown on the bottom row of the flow.

2 Likes

t thought i had a lot of moving pieces :wink: Since most end points don't care if they receive a state update that is the same as their current state, you could potentially simplify this by using a single MQTT topic that all of your end points update to / are controlled by. You could use RBE nodes to prevent any circular logic loops.

I have largely implemented the equivalent of your MQTT topic suggestion. The link in/link out nodes on either end are the equivalent of the MQTT topic. The complexity really comes from the fact that different items can require different formats to communicate the same thing. So the center is each of the interfaces, the right side is translating them to the common format, then it is linked to the left side where the input is sent to all of the interfaces except the one it came from and then translates (when necessary) to the format needed by the interface.

An example of the need for this translation is for an outlet most just want a msg.payload = "on" or "off", while an outlet controlled via Zigbee2MQTT wants msg.payload.state = "ON" or "OFF". Translations get more complicated the more complicated the device. For instance, I have started to do this for a bulb with brightness control. Most interfaces take either an on or an off or a brightness number. Some of them want a brightness on 1-254, some 0-253, some 0-99, some 1-100, and smart nora seems to want 0-100 with 0 being off, 1-100 being brightness levels and not accepting on/off if brightness is an option.

1 Like

Totally get that. I have that on a few of my devices as well (though not nearly as many)

One trick I use to make it a bit more scalable that might help is using sub-flows to do the translations. Not a ton, but a little bit easier than copy/paste of function nodes.

I have used subflows in the past, but have now written enough JavaScript in function nodes that I find them more efficient to develop/debug/test/use. I even have a handful of subflows I am wondering if it would be better to convert to function nodes.

I don't generally use subflows either. I'd rather use link nodes or MQTT topic listeners. They can be useful of course, but my coding style tends to minimise them.

The way I do it is that I have the device type in the mqtt topic, like: zigbee2mqtt/outside/light. This way you can have a single mqtt in node on zigbe2mqtt/+/light.
I then have a single map function node that maps it for nora and preserves the topic.
From this I feed into all the smart nora nodes (which will have a filter by topic name in the next release).
The output of all the nora nodes go back into a single map function node that also adjusts the topic accordingly and it goes back into a single mqtt out node.

The idea is that the mqtt in node needs a map to all the things you need to keep in sync (dashboard/nora/alexa/etc.) and a map from them. If all the things support filter by topic (or a switch by topic node), you can have 2 map functions for each system you want to keep in sync (one in, one out) as long as you preserve the topic each time.

So is the map function node using a specific node or did you just build your mapping inside a function node?

Just a function node.
This is, for example, how I map from Tasmota devices to nora:

This is how I map from zigbee2mqtt to nora (with storing the current state in the flow):
image

And back (from nora to zigbee2mqtt):
image

Thanks for the insight and examples