Automated Heating Control
In 2004 we moved into our new home, which was built on a green field site, and largely designed by ourselves. As such I had included miles of cable and conduit to ensure as much future-proofing as possible.
One of my intentions had been to provide some form of automated central heating control, but at the time I couldn't get a design clear in my head. So I just went ahead and got the plumber to put in the standard system, with three zones, one for downstairs, one for upstairs, and a third for the hot water. I also left a spare STP CAT5 cable near the standard heating timer.
For me the main initial objectives of the system would be twofold:
- Higher degree of control over the system - the installed system only allowed 3 on/off programs per day, 10 minute resolution, and the boost function operated for an hour or two hours which was far too long.
- I wanted remote control. I like my heat, and I hate coming home late at night to a freezing house. I want the house to be warm when I get there.
Having done a lot of reading and research I decided to roll my own control solution, and I decided that a VIOM unit from Phaedrus Ltd was a good controller to use. This unit connects to the COM port of a PC and enables relays to be switched on and off using text commands.
In January of 2005 I managed to pick one up for a reasonable price from a member of the ukha_d mailing list. I quickly fired up my Visual Studio and managed to get the relays flicking on and off. Step 1 complete.
And there the work stopped. Other things took over my time, and so it went on the to-do list. In October of 2005 I decided to have another go, but quickly got bogged down in code relating to times/dates/repeats, how to represent programs in a versatile manner, and how the GUI program setting would look and work. After a while I lost heart, other projects took over, and it was again consigned to the shelf.
This October I started again. This time I decided on a design and worked from the ground up, and then from the inside out.
My design strategy is always simple. KISS - keep it simple stupid. I came up with a brief list of requirements:
- System must control 3 relays - one for each zone
- System must have hardware inputs (Push buttons)
- Must have visual hardware outputs (LEDs)
- System software must be componentised so that components are independent allowing their implementation to be changed if required
- The system should provide a number of remote control methods
- Windows based client - this would be the main client
- Web client - control should be possible across the internet
- SMS client - would be nice - text message the heating to be on when you get home
- Instant messenger client
My initial drawing of the system design actually turned out to be fairly true to the final implementation. Each block represents a component of the system, with several common sub-components reused in the main components.
Initial System Design
This design clearly depicted the separation of components I desired, and contained a minimum number of components I thought I would need for a complete system.
I started building test projects, firstly a nice wrapper around the VIOM code, then trying to get the comms working. I wanted a nice simple text protocol, and after some difficulties with synchronous method calls I decided to go for a completely asynchronous architecture.
Once I was happy with these building blocks I started to code up the proper Control Server. This really took the form of a Windows Forms application, which had a couple of buttons to start with. I checked that I could simply turn relays on and off from GUI button presses. Then it was time to start the calendar component, which would be used to store the program information for the system. I decided to have a separate instance for each zone. For simplicity I created a text configuration file, comma separated containing the information for a weeks on/off events.
Each event contains the following fields :
The day of the week this program is applied to
Time of the day this program starts at
The length in minutes of the program
Once or Weekly
Once for once only programs, like if downstairs should be on for 30 minutes starting at 6pm tonight. Once programs get deleted when they have run
On or Off
Normally programs are On, but if the heating is set for a Weekly On program, and it is overridden to turn it off, an "Off" "Once" program is inserted to override the current "On" program. Once programs always override Weekly programs
The calendar component is responsible for determining the state of the system, other components can simply ask it if the heating for that zone is on or off.
Having completed the initial implementation of the Calendar I moved to looking at the UI Library. I wanted to wrap comms messages suitably so that any of the clients could re-use the same UI Lib to talk transparently to the server. The UI Lib component was coded up providing methods like On(string zoneName, int timeInMinutes) and Off(string zoneName).
Each client could then be coded up to be purely presentation code, leaving any logic to the libraries, or server.
I tidied up my server application and gave a couple of debugging options, so that I could safely debug or add new features without the boiler going on and off constantly.
The first, and main client is a windows forms application. This is now deployed on each PC in the house, allowing control and visibility of the heating state from each machine. It is written to live in the system tray, with the main window only appearing when double-clicked.
It displays the current state of the three zones, and shows the next upcoming timed event.
Setting the times is performed graphically by right clicking on any of the three zones, and choosing the menu item to configure the zone. This displays the time setting dialog.
From this it is possible to set timed programs - either "Once" where they get deleted after being run, or "Weekly" programs that are saved to run every week. The granularity of the tool allows programs to be set in multiples of 5 minutes. Right clicking on the grid offers the option of "Quick Set" for the zone, where the user can quickly add 'once' programs to the system.
Programs are inserted beginning at the current time, and can be set for up to 6 hours. The hourly 'on' time can be selected, from 5 minutes to a full hour, and programs are added in a predefined pattern. For example if the user selects 30 minutes per hour for the next hour, the system will toggle on for 10 minutes, off for 10 minutes, three times. This could be easily reconfigured so that it was on for 15 minutes, off for 15 minutes, twice, but I prefer the 10 on / 10 off model. These patterns can be set in the XML configuration file.
The web client is an extremely small piece of C# code that is simply written as a Console application using a small CGI library to parse incoming name-value pairs for control input. It runs under Apache's cgi-bin directory, and access is controlled by a .htaccess file. This ensures that any user is fully authenticated before even viewing the system state.
It is designed to look and operate exactly like the Windows client for consistency, although it doesn't offer the complex program setting routines.
In my previous job we had made great use of the services of www.bulksms.co.uk for sending text notifications of events from our monitoring system. This was implemented via a HTTP request to one of their servers, and worked very reliably, and relatively cheaply. I had always noticed in their documentation that there was a reply option, but we had never used it. So I started to investigate, and very quickly had a little web application running that could reply to text messages. From here it was just a matter of deciding on a command format, and implementing a parser for that. For consistency this is implemented in the UI Library.
I wanted to be able to text short commands to control the system, and receive a reply to indicate the outcome of the request. Some example commands are shown in the screenshot below, although many more are available.
Again security and authentication is an issue on this platform. We don't want some random texter to be turning our heating on or off! It actually turned out to be trivial, as for the free bulksms reply service to work the reply must be exactly that - a reply. So for a phone to control our heating it needs to reply to a text sent from this specific bulksms account, and the user must locate that text and reply to it. This is not as big a headache as it may sound, as each text command sends a status reply, so there is usually a text from the server close to the top of the inbox. It is possible to reply to any text from the server
Yahoo Instant Messenger Client
I like Bots, especially interactive ones. So I decided that Instant Messenger would be another potential interface for the heating system control, plus I would have an extra contact on my short list of friends ;) . I couldn't find any Yahoo library for C# or .Net so I called upon the services of the open source java project jYMSG which is a java API interface to the Yahoo messaging system. The API does loads of stuff, but all I really want is send message to user, and receive message.
Rather than attempting to use J# or some other similar glue to access the API, I just wrote a small 'main' class around the API, which blocked on the console waiting for input, and prints any received messages to the console. The program takes input in the form "username:message text" and will attempt to send the message to the specified username. Incoming messages are prefixed too for easy parsing.
Starting a console application and redirecting its input and output is relatively easy in C#. It fits nicely into my message driven architecture. When I want to send a message I call a SendYahoo(username, text) method, and when an incoming message is received an event gets fired.
The next step was to glue that to the UIlib, and with that completed in another small windows application which runs on the server and minimises to the tray, I can now send/receive yahoo messages.
The client uses the same UI library as the text messaging client, so the same simple message format works in both places.
An aspect of this system which I hadn't really thought out beforehand was the ability to compile statistics of our heating usage. In my second production release I added functionality to write on/off events to a log file, which could then be analysed to generate statistics on our oil usage patterns. This I suppose has no real purpose, other than that it would be interesting to see how much the usage varies over the year. It may also be possible to figure out how long the next 900 litre fill will last. I created a simple GUI to display statistics, allowing a drill-down type approach to be used. The first graph presents the statistics for the year, then month, and finally per day.
The current implementation is not really intended to be very useful, more a proof of concept upon which I can build when there is more data to analyse
The system hardware is relatively simple. The outputs of the VIOM are connected through another set of power relays that switch the mains voltage zone pumps. The inputs are all momentary push switches.
To avoid interference with the VIOM power supply a second 12v PSU is used to drive the mains relays. This 12v signal is carried using CAT5 cable to the coils of the relays. The relays are located in a white panel box, which replaces the old heating controller in our utility room. There are LEDs across the coil of each relay to visually indicate the status of each zone.
Rather than the system being entirely computer controlled I have included switches on the relay box. A press on the upper switch for a zone will boost that zone, that is turn the zone on for the default boost time. Subsequent presses will extend that time. Pressing the lower switch for a zone will cancel any current program.
The switches are connected directly to the VIOM inputs, allowing multiple switches to be added in parallel. This means that a separate switching controller can be added to the system, and for us that means a bedside switch from which we can put the heat on/off upstairs or downstairs, which has proved very useful!
Reviewing my initial objectives I am pleased with the solution. The system allows precise control of the heating, with as many programs as desired. I can use it from work, home, phone or any internet connection.
One surprise has been that we actually have only a small number of preset programs, mainly in the morning. It is so easy to turn the heat on for 10 minutes when required in the evenings that this is what we do, rather than having it on from 5-6 pm and 8-9pm every day like the old system was set to. This was really another objective completed - trying to minimise wasted heating, so we weren't running the heating when we weren't there. We have certainly managed this.
You may have noticed that thermostatic control has not been mentioned in this article. We have two thermostats, one for upstairs and one for downstairs. They are useless. As I see it they contribute very little to the system. I have been able to control the system using timing much more effectively. For example last night we had guests, and I didn't want to be running out to the controls through the evening. Before they arrived I set up the heating to be on for 12 minutes each half hour for about 3 hours. This worked brilliantly, when the room started to get a little cold, the heat boosted on again.
Although there is still a lot of work to do on the software, there are as many whistles and bells as I can imagine, I am pleased with the current implementation. I will hopefully get to implementing some more user friendly features shortly, but it certainly is a complete and usable system as it is.
Apart from a few GUI tweeks, and fixing any issues that crop up, I really am very happy with the system as it is. The only thing I think would benefit in the short term would be weather based program control, this is currently implemented but not fully enabled. I have managed to scrape the windchill temperatures from a weather source and store that data. I have also modified the Calendar component to take an extra input to determine if the heating should be turned on a few minutes early, but I just haven't linked the two subsystems together yet.
If I was starting again, with the house build, I would ensure I had hardware to control each room as a zone, as I believe this would greatly increase the efficiency of the system. However, the thought of writing the control code for it would be a bit scary....