I’ve evolved my home automation solution (called Watchdog) to leverage a design that allows modules to be loosely coupled called ‘Publish-Subscribe’. This has many advantages, but also some draw-backs that I’ll describe in this post.
A Publish-Subscribe design is a messaging pattern where senders of messages (called Publishers), do not program the messages to be sent directly to specific receivers (called Subscribers). Instead, published messages are sent to a middleware layer (Commonly a message queue or database), without knowledge of what, if any, subscribers there may be. Similarly, subscribers interested in the message, have no knowledge of what, publishers there are.
My initial adoption of this design approach started when I first decided to add an HTML5 web interface for some of the home automation features in order to allow easy manual overrides from any connected device. It became clear that the peer-to-peer messaging design approach I was using would not easily allow me to add one or more new interfaces. By introducing a database middleware layer for some functions, I could very easily make changes to one or more module without impacting others. So, I went to work re-designing some functions, and creating a framework that I’ve used for more recently-added functions. The functions leveraging the Publish-Subscribe design include:
- Window Blind Control
- Insteon Light Control
- Irrigation Control
- Temperature Control
- Vent Control
- Water Usage
Below is an example of the database table I use as the middleware layer for the Publish-Subscribe design:
In this example, the Zone_Request_State is the column used by the Publisher to request a change. The Subscriber frequently polls the database table to find new requests and take action against them. Only when the action has been successfully completed, does the Subscriber update the table to reset the Zone_Request_State value to NULL.
The Publish-Subscribe approach has many important benefits including:
- Allows more than one Publisher to request state changes
- Allows more than one Subscriber to check the status
- Provides a stateful storage area for the Subscriber in the event the Publisher crashes or has problems communicating with the target peripheral and cannot immediately make the requested change.
- Allows the Subscriber to take action on a batch of one or more state change request in a single pass
The Publish-Subscribe does have one major drawback. Because I chose to use a database table instead of a Message Queue or other middleware product, there are limits on the frequency I should poll the database to check for new changes. I’ve made the mistake of checking too often (more than once per second), and it caused performance and timeout issues with other applications that also rely on the database. The database was so busy performing SELECT statements on the table looking for new requests that it gave up attempting to satisfy other requests. I’m limited in the horsepower I can dedicate to the database, so I opted to increase the interval between polls in order to reduce the overall workload on the server. The result is a minor delay between request and response. When an automated state change is requested, there is no impact, but when I am manually overriding the state of an item in the house, I find the system is not as responsive as I would like. This trade-off is a minor inconvenience, but is necessary for the overall health of the system.
Another minor drawback is that, in many cases, a single app acts as both a Publisher and a Subscriber. This was a necessary design in order to achieve the benefits outlined above, but has the drawback of being less efficient since no intra-app messaging would normally be required.