Central heating control on the cheap

The gas heating system in my flat is pretty rudimentary when it comes to features. Not only is there the absence of a proper billing system (yep, pre-paid gas causes me to wake up in a cold bedroom once or twice a month), but also in terms of heating control. Besides controlling how much water flows through each radior, there are two ways to control the heating centrally: a timer with 30min. resolution and a dial without a scale that sets something like the “heating level”. Now, the timer controls when the boiler is active at all, and that includes warm water. So what I would typically do is set the timer to always on and set the room temperature by controlling the heating dial once a day. With that method I’d still heat during the day, when I’m not at home which is highly suboptimal.
I’m also currently in the process of building a simple home automation system using busfarhn running on a RasperryPi. So it seemed like a natural fit to have some form of automated heating control, integrated into the home automation system. The solution is pretty more or less straight forward:heating control schema
The TP-MR3020 WiFi router gets signals via http, relays them to a serial port where it is received from an MSP430, which in turn bit bangs a signal for a servo motor controlling the central heating dial.

The WiFi part

For the whole thing to integrate with busfarhn, it has to somehow become part of the network – read, WiFi. As power consumption is not one of the primary concerns here (the whole setup is going to be close to a power outlet), I opted for the cheap WiFi solution. Embedded WiFi is still pretty expensive and complex, although the Electric Imp eases the complexity side and hopefully the TI CC300 modules will cut costs in the future. But were not there yet.
Another way to get WiFi for an embedded project is to appropriate existing hardware. A prime example of such appropriation is the TP MR3020 WiFi router (or its smaller brother, TP WR703 for that matter). This inexpensive piece of hardware can run OpenWRT, sports a USB port and is powered using a USB power supply itself.
Getting OpenWRT to run on this little white box is really easy, and described plenty elsewhere. Once the OS is setup, the only thing missing is the HTTP-to-Serial relay part.
First, we need to be able to control serial ports. Unfortunately, OpenWRT does not ship with stty support in its busybox build. Johan von Konnow has figured that out as well and provides a rebuilt busybox. After ungzipping it, I installed it with

mv busybox /bin/busybox.stty && ln -s /bin/busybox.stty /bin/stty

OpenWRT comes with uhttpd by default. uhttpd is a nifty little webserver that supports CGI. So placing a script much like the following one in /www/cgi-bin and one can send commands to the serial port via: http://<ip-of-the-router>/cgi-bin/servo?position=[0-9].

#!/bin/sh -ax

CMD=`echo "$QUERY_STRING" | grep -oE "(^|[?&])position=[0-9]+" | cut -f 2 -d "=" | head -n1`

echo "Content-type: application/json"
echo ""

if [ -z "$CMD" ]; then
    echo "{ 'status': 'error', 'msg': 'missing position' }"
elsif [ ! -f $SP ]
    echo "{ 'status': 'error', 'msg': 'missing servo controller' }"
    [ "$(stty -F $SP-a | grep speed | cut -d ' ' -f 2)" != "9600" ] && stty -F $SP raw speed 9600 -crtscts cs8 -parenb -cstopb

    echo $CMD > $SP
    echo "{ 'status' : 'success', 'msg' : 'done' }"

The business end

Sending commands alone will not turn that knob. To make that happen, one needs a servo motor. A typical RC servos works very well here, as their power requirements tend to be < 250mA so they can be powered straight from the USB bus. Connecting the servo with the actual knob was a bit harder than I anticipated. For one, I'm not allowed to permanently modify the boiler (it's not my property). And then there is that strange dial shape (see video below). So for the actuation part, two things had to be done: writing a bit of code for the MSP430 to control the servo and building a rig to hold everything in place and to connect the servo with the dial its supposed to turn.
Programming an MSP430 Launchpad is really straight forward thanks to an awesome project called Energia (if basic Wiring-style programming suffices and one doesn’t mind the overhead). The code for the MSP430 – which would also run on an Arduino – can be found in the source archive.
Mounting the whole system to the boiler was one the bigger challenges of this project. My first attempt with duckt tape held about 3 hours before it hit the floor. As it turns out, stick-on velcro bought from the local haberdashery does the job quite well. It allows me to easily remove and reposition the contraption from/on the boiler without leaving any permanent damage. And should the day come at which I move out of this place, I’ll hope that acetone will get easy the velcro removal.
Besides mounting the whole thing to the boiler, some form of adapter to fit the servo to the dial had to be created. It took me two attempts get the strange curvature of the dial right, but thanks to my trusty printrbot that was less done in less than two hours time.
Again, the outlines and models can be found in the source archive below.

Let’s see it

So far I’m pretty happy with the outcome. The machine sticks to the boiler and hasn’t come down yet. WiFi interface and servo work reliably. In case you want to build your own system like this, you might find the files uploaded here helpful.
Download the sources here.

Milling and drilling on a MendelMax

A few days ago, I’ve mounted a Dremel on my MendelMax using this thing. Such as setup allows for a few nice things: milling wood or drilling printed circuit boards – once you got the software down.
As the scripts are a bit hidden in this post, check them out on GitHub.

Milling wood

Once the Dremel is on the machine, milling wood is pretty much a matter of converting a 2D drawing (e.g. stored as DXF) to Marlin compatible GCode. The weapon of choice here seems to be a program called dxf2gcode. What that program outputs however, is not directly suited for feeding it into the MendelMax:

  • comments: comments are surrounded by parenthesis, whereas for this use they’re single-line comments starting with a semicolon.
  • feed rate: feed rate is set using an F command (e.g. F400), whereas for the RepRap it should be a G1 expression (more like G1 F400)
  • unsupported commands: As the generated GCode is designed for real CNC milling machines, several specific commands have to be issues such as starting the cooland flow or getting the spindle up to speed. As such commands could confuse the RepRap (not checked, just assumed) we should filter them out or replace them with more suited counterparts.
  • different movement commands: dxf2gcode produces G0 for initial positioning, whereas moving a RepRap works with G1 commands.
  • different use of whitespace: typically GCode seems to be written so that there is no whitespace between the code character and numeric data. dxf2gcode however, produces whitespace where they typically aren’t. That whitespace makes the output look nice, but again might not work so well with a RepRap.

All those steps are implemented in a little script on GitHub.

Drilling PCBs

Drilling PCBs is something easy to do at first glance. It turns out, however, that aligning the layer mask with the drilled holes is a delicate issue. So far I’ve achieved the best results using the following steps (in that order):

  1. Export an excellon drill list from EAGLE using the CAM Processor excellon.cam script
  2. Convert the exported Excellon file (probably ending with .drd) to GCode using this script from GitHub.
  3. Drill the holes using the generated GCode
  4. Print the mask, cut it out and align it with the drilled holes
  5. Transfer the mask (toner transfer, UV exposure) and etch the PCB
Converting the Excellon drill file is a key part in this process. The script linked above does just that, including mil to millimeter conversion, and starting point selection. Personally I tend to identify a certain point on the board with the starting point of the printer. See the help output from the script below for a list of what it can do.

Usage: gcodeutils/excellon2gcode.rb [options] drillfile.drd outfile.gcode
    -s, --start STARTPOINT           The start point of the printer, format [XX]x[YY] [mm]
    -f, --first FIRSTPOINT           First drill point to go for and equate to zero, format [XX]x[YY] [mm]
    -m, --mil2mm                     Translate units from MIL to MM
    -i, --invert-xX                  Inverts the x axis
    -t, --travel-height HEIGHT       The travel height in mm
    -d, --drill-height HEIGHT        The drill height in mm
    -r, --rotate ANGLE               Rotates the holes by ANGLE degrees
        --preamble FILE              Prepend the preamble from FILE
    -p, --postamble FILE             Append the postamble from FILE
    -v, --verbose                    Produce verbose output
    -g, --gnuplot                    Plot the drill holes on the console
    -h, --help                       Display this screen
On a side node, try not to move the PCB while the drill is still in the board – it will snap. Obviously -.-


These days I’m building a simple home automation system – turning lights and appliances on/off. Not only do I want to be able to switch appliances on and off, but I want the system to do it for me. Hence, some context inference is in order. The centerpiece of this effort is a bus system that would be used to transmit sensor information, infered high-level context and actuator commands. As it so happens, that bus system was a good opportunity to learn Node.JS.
The outcome of this effort are a few lines of JavaScript which I’ve come to call busfahrn (colloquial German for taking a bus ride). It’s basically a wrapper around EventEmitter, but with a ton of different IO support. Its main features are
  • A lot of IO modules to pass along messages. Out of the box support exists for HTTP(S), Redis, serial ports and the console.
  • A notion of message/state inference using redis and simple rules formulated in JavaScript
  • Clean and simple code, easy to extend and modify
  • Written entirely in Node.JS
If you want to give it a spin or read more, please checkout Github.
Fork me on GitHub