Thursday, September 05, 2013

Raspberry Pi heating controller


Introduction



About six years ago I created and installed a proprietary system for controlling our central heating. The setup was client-server, where the server was C# software running on a Win32 box, using RS232 to control a VIOM unit, which in turn activated relays to turn the zones on and off. There is no thermostatic control in this software, it is simply time based on/off programs. The system has three zones, downstairs, upstairs and water.


The main aim was to make a piece of software that would allow easy setting of time programs. The controller that was initially installed in the house was a standard three zone controller (Horstmann), but the programs were fiddly to set, limited in number, and with those controllers people typically don’t change the heat programs soon enough when it comes to summer or winter, thus having a warm or cold house and wasting oil.

The system was installed and ran pretty much maintenance free for those years. However, as I wanted to add little features I realized that the architecture was over engineered, and some of the C# was outdated.

With the advent of the £30 raspberry pi, and the fact that I make a living writing Java, I decided to rewrite my software for the pi. I did a little research to make sure that the pi could do all I needed, which is basically a bit of I/O and run 24/7, reliably.

I began by re-writing the C# pretty much line for line in Java. Getting it working first in java was my main priority. It turned out to be easier than I thought, even the RS232 stuff was a lot easier in Java than C#. Once I got it working, I put it on the windows server in place of the C# to ensure that it worked reliably over the longer term. Stage 1 complete, it was time to order my pi.

RPi


The raspberry pi is a pretty cool little computer, I bought the starter kit from maplin, which meant I didn’t need to steal a keyboard, mouse, hub and SD card from elsewhere. I don’t have a HDMI monitor, so I used a TV for development. Once I had SSH up and running I was able to work remotely. I also installed samba which made it really easy to deploy from eclipse to the pi.

Raspberry Pi Board

Java install - I followed the instructions to install java here (http://www.oracle.com/technetwork/articles/java/raspberrypi-1704896.html) which includes setting up software floating point version of the OS. Follow the instructions there, it will work fine. Make sure and do the update and upgrade commands, as they will get a pile of stuff, and it seemed to help with some of the problems I had.
  • up to date packages will minimize problems
    • sudo apt-get update
    • sudo apt-get upgrade
  • ensure you select the option to expand the SD card, as 2GB will stop the java installation part way through, and this can be troublesome (setup can be run again at any time using the command sudo raspi-config)

Wireless configuration

Wireless configuration caused quite a lot of trouble. Initially it seemed to work fine, but then sometimes it dropped and wouldn’t reconnect. I tried different managers, but none really pleased me, so in the end I wrote a simple script that runs frequently, and reestablishes the connection if it is dropped.

cron entry:
 * *  *   *   *     /etc/network/wireless_check.pl >> /var/log/wireless_check.log

The script:
--
#!/usr/bin/perl

my $status = `/sbin/ifconfig wlan0`;

if($status =~ /inet addr:/)
{
       #do nothing
       #print localtime . " connection is up\n";
}
else
{
       print localtime . " connection is DOWN\n";
       print "status: " . $status;
       print `/sbin/ifup --force wlan0`;
}
--

The script is written in perl because it’s easy and quick, it very simply checks the ifconfig status for the wireless, and if it contains an ip address it does nothing, otherwise it runs the ifup command. It has been running now for many days, and no problems.

Hardware


I started development on a breadboard to make sure that I had my I/O working. My kids just don't understand the marvel of pressing a key and having an LED come on, or pressing a switch and having some text scroll up the console. It was very easy to get working using the instructions on the web (http://pi4j.com/example/control.html), and the java library provides lots of useful functionality, such as event driven callbacks for I/O changes.

Development with breadboard and relay board

I then swapped the LEDs for a uln2803 8 bit 4 relay Board (from eBay) which made a reassuring clunk when a GPIO line changes state. The 10A relays are also far more than necessary for switching the heating pumps and boiler.

I used a Slice Of Pi board to tidy the whole thing up. It just needed some pull-up resistors and terminals to connect my switches to. I know the pi is supposed to be configurable to not need pull up/down resistors, but I couldn’t get that to work reliably, and for the sake of a couple of resistors, that was an easy solution. I also wrote a little debounce code into my input class, so that multiple events within 100ms are ignored.

Slice of Pi Board


Slice of Pi board fitted and in place

Power

Both the pi and the relay board both require 5v from a USB connector (one mini and one micro). Initially I had hoped to use an old HTC charger as they are pretty tiny, but by the time I had remodelled it, it was no longer working. I used the maplin charger, which conveniently came with screws in the case, so it was easily taken apart. I taped it all up, so that there was only USB out and 240v in (via a connector block) showing out the ends of the package. I then cut cables to size and ran them to each of the boards.

Boxing it up

I had hoped to squeeze the whole thing into one deep double gang wall pattress, but after spending an evening I decided that was not possible. I ended up getting a box from maplin which was a much better solution. The pi is mounted in a cut out piece of antistatic foam, and the relay board pretty much stayed in place with the cable attached to the relays. Each wire goes out through the back of the box in individually drilled holes. The exposed end of the relay circuit board is at the bottom of the box to minimize the risks of anyone touching it, as it will be live all the time.

Power supply (left), Relay board (right bottom), and mounted pi

The switches for each zone fitted nicely into the front of the box, but the screw connectors for them are pretty huge for the box, something smaller would be more suitable.

LED’s and Push Switches for basic control


In Situ beside the isolator switch (no boost buttons for the water)

Software - server


The java server software ran first time on the pi. It is supposed to be write once, run anywhere, but seeing is really believing!

Once it was all running I worked in iterations to simplify the java server. There have been quite a few changes, added a couple of features. It’s a lot simpler now than it was, and a lot tidier, although it could still be improved.

In the beginning the server ran in a console window, but that is not acceptable for production.The server software must run reliably all the time, start automatically on boot and restart if it stopped. I spent a while figuring out how to write a service, and got it all working, but I was concerned about its ability to restart if it died. After a lot of experimenting there seems to be a million ways to crack this nut, but in the end I decided to use start-stop-daemon to control my process, and run that with some special args from inittab. The init line ended up looking like this

Heat:2345:respawn:start-stop-daemon --start -p /tmp/heating.pid -m --exec /usr/bin/java -v -d /home/pi/builds -- -jar heating_server.jar

Options explained:
  • --start - only one instance will ever exist.
  • -p file - specify the file in which to store the pid
  • -m - make the pid file if it doesn't already exist
  • --exec - specify the actual executable
  • -v - prints verbose messages - now unnecessary, but useful getting it up and running
  • -d - specifies the directory to run in
  • -- - other arguments are passed directly to the java process

This seems to work very reliably. To stop the server simply comment out the line in inittab and run init q (careful not to run init 1 though - just beside ‘q’ on the keyboard!)

The other significant change was to use log4j to simplify the logging. Using the XML configuration it can automatically gzip the files at the end of each month.








class="org.apache.log4j.rolling.TimeBasedRollingPolicy">







The other logging modification was to make the main method take an extra argument to enable logging to the console if it is running directly from the command line for debugging, for example. This is achieved by a simple bit of java in the main class:
if (args != null && args.length > 0
&& args[0].equalsIgnoreCase("console")) {
System.err.println("Enabling console logging");
BasicConfigurator.configure();
Logger.getRootLogger().setLevel(Level.INFO);
Logger.getLogger("com.").setLevel(Level.DEBUG);
}


Software - Clients



There are also quite a few changes to the C# winforms client. It was also a bit over engineered, but now it uses easier TCP code, has less layers, and is more configurable.


Windows Client - main screen



Windows Client - settings for zone (in 5 minute granularity)



Windows Client - Statistics Viewer - Year View



Windows Client - Statistics Viewer - Month and Day Views



The HTTP and SMS interfaces got a work over too, and they now work faster than ever. SMS is handled by an SMS to HTTP gateway (provided for very little cost from bulksms.co.uk). Previously the HTTP requests were handled by a C# CGI program, but now they are handled by a small perl script, which is far quicker and far easier to maintain.


HTTP Client running on iPad



The SMS client uses abbreviated notation to allow quick texting - all commands must start with On or Off and there is a special Status command which just returns the next programs to run. Zone names can be written in full or abbreviated 1=Downstairs, 2=Upstairs, 3=Water.
Examples:
On 1 - Turn downstairs on now for default boost time (10 minutes)
On 2 30 - Turn upstairs on now for 30 minutes
On 1 2200 - Turn downstairs on at 22:00 for default boost time (10 minutes)
On 1 1100 35 - Turn downstairs on at 11:00 for 35 minutes


Each message is replied with a list of the three next programs to run in each zone.


SMS Interface  -  Example Messages




As I now have an Android phone, and it is easy to write programs in Java for it I decided to give it a go. Communicating with the server and drawing simple widgets on the screen turned out to be pretty easy. It was all the other stuff that took a lot of time, the app lifecycle, screen rotation, and switching in and out of being the active program. However, in a simple form it works pretty well.


Android Controller App


Conclusion
The clients and server have been running reliably now for about a month, and it seems to be fine. There is still extra work to do, but it is only on the periphery, the main work is complete, and operating satisfactorily.

2 comments:

Heating Ontario said...

Great blog, I really like the content of your articles for sure I learn more from here.

Heating and Cooling Systems Vaughan

Anonymous said...

Thanks for sharing such a wonderful article! Can please tell me the best Bulk SMS service in Uk?