# Computing stuff tied to the physical world

## Snooping with an Optocoupler

In Hardware on Nov 28, 2012 at 00:01

The thing with OpenTherm, is that the amount of current going through the wire is used by the boiler to send messages to the thermostat.

The reverse path, i.e. from thermostat to boiler, is signalled by voltage changes, which are considerably easier to detect. So let’s save that for later.

There is a small complication, in that the polarity of the wiring between boiler and thermostat is not defined, so either one of them could be “”+” and “-“, respectively. Of course once you’ve hooked things up, that polarity never changes again.

Can we measure the current going through a wire, without knowing in which direction it is flowing? We know it’ll be 5..7 mA for one signalling state and 20..25 mA for the other.

Here’s what I came up with:

There are two optocouplers in there, with the diodes connected in opposite ways. Depending on the direction of the current, one of them will block and the other one will light up – once the voltage over the 82 Ω resistor exceeds about 1V, i.e. at ≈ 12 mA.

For documentation purposes, the actual build:

The voltage drop over this circuit is at most just over 1V, which may or may not interfere with proper operation of the boiler and thermostat. Testing will be needed to find out.

The first advantage of this circuit is that it works with either polarity without needing a bridge rectifier (which would introduce yet another voltage drop). In addition, the output signal is galvanically isolated from the OpenTherm loop, i.e. “floating”. That means it can be connected in whatever way is needed.

The second part of an “OpenTherm snooper” – if it ever materialises – will be to measure the voltage between the wires and hopefully also to self-power the rest of the circuit. Note that the optocoupler LED lights up when a high current is passing through, and this is also the state where the photo transistor is drawing more current through the 10 kΩ resistor.

Here’s the diode voltage (yellow) and output (blue), using the same ± 10V @ 50 Hz signal as yesterday. The vertical zero axis is one division down from the centre, for both traces:

Note how the output triggers on both positive and negative excursions of the input signal due to the anti-parallel LEDs, which is why it ends up having twice as many pulses. So the first half is one LED turning on and off, and the second half is the other LED – both lead to the common OUT pin being pulled down. For OpenTherm use, there’d never be both polarities – only one LED would be active, depending on how the circuit is connected.

The pulse-width asymmetry you see is an artefact of the way the sine wave is applied (using a 150 Ω resistor). This will not happen with a 7..25 mA current toggle and 82 Ω. And while the MCT62 is not one of the fastest optocouplers, especially with a 10 kΩ collector pull-up, I expect that the resulting pulses will still be accurate enough.

So far so good. I haven’t built the rest yet – just doodling and trying to figure it all out.

## Sensing with an Optocoupler

In Hardware on Nov 27, 2012 at 00:01

The OpenTherm setup keeps me thinking…

I haven’t given up on the OpenTherm Gateway yet, but I’ve also been toying with related ideas for some time to try and just listen in on that current/voltage conversation using a self-powered JeeNode, which then reports what it sees as wireless packets.

It’s all based on Optocouplers, so here’s a first circuit to try things out:

A very simple test setup, which I’m going to feed a ±10V sine wave @ 50 Hz, just because the component tester on my oscilloscope happens to generate exactly such a signal. The 1 kΩ resistor is internal to the component tester, in fact. Here’s what comes out:

The yellow trace is the voltage over the IR LED inside the optocoupler, the blue trace is the voltage on the OUT pin. VCC is a 3x AA Eneloop battery pack @ 3.75V – what you can see is that the LED starts to conduct at ≈ 0.8V, and generates just enough light at 0.975V for the photo transistor to start conducting as well, pulling down the output voltage. With 1.01V over the LED, it already generates enough light for the output to drop to almost 0V.

In other words: within a range of just 41 mV at about 1V, the optocoupler “switches on”.

So much for the first part of this experiment. My hope is that this behavior will be just right to turn this MCT62 optocoupler into a little OpenTherm current “snooper” – stay tuned…

## Bi-directional signalling and power

In Hardware on Nov 25, 2012 at 00:01

It looks like the OpenTherm gateway is sensitive to noise and wiring lengths. All my attempts to move the gateway upstairs, next to the boiler/heater, failed. Somehow, this:

```  THERMOSTAT  <=>  GATEWAY  <=>  10 m wire  <=>  HEATER
```

… is not the same as this!

```  THERMOSTAT  <=>  10 m wire  <=>  GATEWAY  <=>  HEATER
```

The OpenTherm documentation (PDF) specifically allows up to 50 meters of untwisted wiring, but I’m clearly running into some issue here.

Time to drag the scope downstairs and hook it up between gateway and heater:

The yellow trace is the voltage between the two wires, while the blue trace is the current through those wires. I used a 1 Ω resistor and measured the voltage drop, but had to switch to the most sensitive scale (since I’m using the standard x10 probe), hence all that noise.

Still, you can see the magic of the way the OpenTherm protocol works:

• in rest, there’s 6V between the wires and about 6 mA of current flowing (a 1 kΩ load)
• this is used by the thermostat to power itself (by keeping a capacitor charged)
• when the thermostat sends data, it briefly reduces its current draw
• since the boiler (or gateway) is feeding a constant current, this makes voltage go up
• that voltage change is then detected and decoded by the boiler / gateway
• about 40 ms later, the boiler / gateway then sends a reply
• it does this by briefly forcing more current down the wire
• this in turn can be detected by the thermostat, which then decodes that reply
• there’s a small residual ripple, as the thermostat tries to maintain its 7V idle level

I was going to perform the same measurement on the other side of the gateway, i.e. the connection to the thermostat, but for some reason the gateway really doesn’t like me touching anything or connecting any wires to it (let alone a grounded scope probe). Maybe some noise is picked up and feeding back into one of the PIC’s I/O pins, and completely throwing it off. Luckily, the whole gateway always resets properly when left alone again.

I also sometimes see the thermostat indicating a fault (even just by touching the wire with the scope probe) – so it seems to be getting some power, but it’s definitely not happy.

Maybe the gateway’s output circuit is too sensitive, due to some high-impedance parts in the circuit? That would explain why even just using some long wires two floors down prevents the gateway from working.

Hm, not good – especially since I only wish to monitor the wire, not control it…

Update – these problems are caused by a floating ground. More on this once I get it all sorted out. With many thanks to Schelte Bron for dropping by and helping analyse this!

## Reducing the packet rate

In Software on Nov 22, 2012 at 00:01

One last optimisation, now that the OpenTherm relay sends nice and small 3-byte packets, is to reduce the number of packets sent.

The most obvious reduction would be to only send changed values:

This is a trivial change, but it has a major flaw: if packets are lost – which they will, once in a while – then the receiving node will never find out the new value until it changes again.

There are several ways to solve this. I opted for a very simple mechanism: in addition to sending all changes, also send out unchanged values every few minutes anyway. That way, if a packet gets lost, at least it will be resent within a few minutes later, allowing the receiver to resynchronise its state to the sender.

Here’s the main code, which was rewritten a bit to better match this new algorithm:

This still keeps the last value for each id in a “history” array, but now also adds a “resend” counter. The reason for this is that I only want to re-send id’s which have been set at least once, and not all 256 of them (of which many are never used). Also, I don’t really want to keep sending id’s for which nothing has been received for a long time. So I’m setting the re-send counter to 10 every time a new value is stored, and then counting them down for each actual re-send.

The final piece of the puzzle is to periodically perform those re-sends:

And in the main loop, we add this:

Here’s how it works: every second, we go to the next ID slot. Since there are 256 of them, this will repeat roughly every 4 minutes before starting over (resendCursor is 8 bits, so it’ll wrap from 255 back to 0).

When examining the id, we check whether its resend counter is non-zero, meaning it has to be sent (or re-sent). Then the counter is decremented, and the value is sent out. This means that each id value will be sent out at most 10 times, over a period of about 42 minutes. But only if it was ever set.

To summarise, as long as id values are coming in:

• if the value changed, it will be sent out immediately
• if it didn’t, it’ll be re-sent anyway, once every 4 minutes or so
• … but not more than 10 times, if it’s never received again

And indeed, this reduces the packet rate, yet sends and re-sends everything as intended:

```  L 13:48:48.073 usb-A40117UK OK 14 24 18 197
L 13:48:49.080 usb-A40117UK OK 14 25 51 0
L 13:48:50.072 usb-A40117UK OK 14 26 43 0
L 13:48:52.072 usb-A40117UK OK 14 28 51 0
L 13:49:20.075 usb-A40117UK OK 14 56 60 0
L 13:49:36.548 usb-A40117UK OK 14 20 238 51
L 13:50:37.549 usb-A40117UK OK 14 20 238 52
L 13:51:33.532 usb-A40117UK OK 14 24 18 186
L 13:51:37.563 usb-A40117UK OK 14 20 238 53
L 13:52:34.537 usb-A40117UK OK 14 24 18 188
L 13:52:38.553 usb-A40117UK OK 14 20 238 54
L 13:52:40.088 usb-A40117UK OK 14 0 2 0
L 13:52:41.096 usb-A40117UK OK 14 1 10 0
L 13:52:46.087 usb-A40117UK OK 14 6 3 1
L 13:52:54.101 usb-A40117UK OK 14 14 100 0
L 13:52:56.101 usb-A40117UK OK 14 16 18 0
L 13:53:00.100 usb-A40117UK OK 14 20 238 54
L 13:53:04.099 usb-A40117UK OK 14 24 18 188
L 13:53:05.090 usb-A40117UK OK 14 25 51 0
L 13:53:06.098 usb-A40117UK OK 14 26 43 0
L 13:53:08.098 usb-A40117UK OK 14 28 51 0
L 13:53:34.538 usb-A40117UK OK 14 24 18 192
```

Time to close that OpenTherm Gateway box and move it next to the heater. Onwards!

In Software on Nov 21, 2012 at 00:01

The OpenTherm relay sketch presented yesterday sends out 9-byte packets containing the raw ASCII text received from the gateway PIC. That’s a bit wasteful of bandwidth, so let’s reduce that to a 3-byte payload instead. Here is some extra code which does just that:

I’m using a very hacky way to convert hex to binary, and it doesn’t even check for anything. This should be ok, because the packet has already been verified to be of a certain kind:

• marked as coming from either the thermostat or the heater
• the packet type is either Write-Data or Read-Ack
• every other type of incoming packet will be ignored

Note the shouldSend() implementation “stub”, to be filled in later to send fewer packets.

Here are the results of this change, as received by the central node:

```L 11:29:26.651 usb-A40117UK OK 14 16 18 0
L 11:29:27.547 usb-A40117UK OK 14 20 236 30
L 11:29:28.635 usb-A40117UK OK 14 28 45 0
L 11:29:29.642 usb-A40117UK OK 14 0 2 0
L 11:29:30.650 usb-A40117UK OK 14 25 46 0
L 11:29:31.562 usb-A40117UK OK 14 1 10 0
L 11:29:31.658 usb-A40117UK OK 14 1 10 0
L 11:29:34.649 usb-A40117UK OK 14 25 46 0
```

Much better, although still a lot of duplication and far too many packets to send.

I’ll fix this tomorrow, in the final version of this otRelay.ino sketch.

## OpenTherm relay

In Software on Nov 20, 2012 at 00:01

Now that the OpenTherm Gateway has been verified to work, it’s time to think about a more permanent setup. My plan is to send things over wireless via an RFM12B on 868 MHz. And like the SMA solar inverter relay, the main task is to capture the incoming serial data and then send this out as wireless packets.

First, a little adapter – with 10 kΩ resistors in series as 5V -> 3.3V “level converters”:

(that’s an old JeeNode v2 – might as well re-use this stuff, eh?)

And here’s the first version of the otRelay.ino sketch I came up with:

The only tricky bit in here is how to identify each message coming in over the serial port. That’s fairly easy in this case, because all valid messages are known to consist of exactly one letter, then 8 hex digits, then a carriage return. We can simply ignore anything else:

• if there is a valid numeric or uppercase character, and there is room: store it
• if a carriage returns arrives at the end of the buffer: bingo, a complete packet!
• everything else causes the buffer to be cleared

This isn’t the packet format I intend to use in the final setup, but it’s a simple way to figure out what’s coming in in the first place.

It worked on first try. Some results from this node, as logged by the central JeeLink:

```  L 10:38:07.582 usb-A40117UK OK 14 84 56 48 49 65 48 48 48 48
L 10:38:07.678 usb-A40117UK OK 14 66 52 48 49 65 50 66 48 48
L 10:38:08.558 usb-A40117UK OK 14 84 56 48 49 57 48 48 48 48
L 10:38:08.654 usb-A40117UK OK 14 66 52 48 49 57 51 53 48 48
L 10:38:09.566 usb-A40117UK OK 14 84 49 48 48 49 48 65 48 48
L 10:38:09.678 usb-A40117UK OK 14 66 68 48 48 49 48 65 48 48
L 10:38:10.574 usb-A40117UK OK 14 84 48 48 49 66 48 48 48 48
L 10:38:10.686 usb-A40117UK OK 14 66 54 48 49 66 48 48 48 48
L 10:38:11.550 usb-A40117UK OK 14 84 48 48 48 70 48 48 48 48
L 10:38:11.646 usb-A40117UK OK 14 66 70 48 48 70 48 48 48 48
L 10:38:12.557 usb-A40117UK OK 14 84 48 48 49 50 48 48 48 48
```

One of the problems with just relaying everything, apart from the fact that it’s wasteful to send it all as hex characters, is that there’s quite a bit of info coming out of the gateway:

Not only that – a lot of it is in fact redundant. There’s really no need to send the request as well as the reply in each exchange. All I care about are the “Read-Ack” and “Write-Data” packets, which contain actual meaningful results.

Some smarts in this relay may reduce RF traffic without losing any vital information.

## OpenTherm data processing

In Software on Nov 19, 2012 at 00:01

Before going into processing the data from Schelte Bron’s OpenTherm Gateway, I’d like to point to OpenTherm Monitor, a multi-platform application he built and also makes freely available from his website.

It’s not provided for Mac OSX, but as it so happens, this software is written in Tcl and based on Tclkit, by yours truly. Since JeeMon is nothing but an extended version of Tclkit, I was able to extract the software and run it with my Mac version of JeeMon:

```  sdx unwrap otmonitor.exe
jeemon otmonitor.vfs/main.tcl
```
Heh – nothing beats “re-using” one’s own code in new and mysterious ways, eh?

Here’s the user interface which pops up, after setting up the serial port (it needed some hacking in the otmonitor.tcl script):

I left this app running for an hour (vertical lines are drawn every 5 minutes), while raising the room temperature in the beginning, and running the hot water tap a bit later on.

Note the high error count: looks like the loose wires are highly susceptible to noise and electrostatic fields. Even just moving my hand near the laptop (connected to the gateway via the USB cable) could cause the Gateway to reset (through its watchdog, no doubt).

Still, it looks like the whole setup works very nicely! There’s a lot of OpenTherm knowledge built into the otmonitor code, allowing it to extract and even control various parameters in both heater and thermostat. As the above window shows, all essential values are properly picked up, even though this heater is from a different vendor. That’s probably the point of OpenTherm: to allow a couple of vendors to make their products inter-operable.

But here’s the thing: neither the heater nor the thermostat are near any serial or USB ports over here, so for me it would be much more convenient to transmit this info wirelessly.

Using a JeeNode of course! (is there any other way?) – stay tuned…

PS. Control would be another matter, since then the issue of authentication will need to be addressed, but as I said: that’s not on the table here at the moment.

## Tackling OpenTherm

In Hardware on Nov 18, 2012 at 00:01

Another project I’ve been meaning to tackle for a very long time is to monitor the central heating and warm water system. Maybe – just as with electricity – knowing more about what’s going on will help us reduce our fairly substantial natural gas bill here at JeeLabs.

The gas heater is from Vaillant and it’s connected to a Honeywell ChronoTherm – this is a “modulating” thermostat which automatically chooses its set-points based on the time of day and the day of the week. It all works really well.

The heater upstairs and the thermostat in the living room are connected by a two-wire low-voltage connection, using the OpenTherm protocol. There’s not that much “open” about this protocol, but people have hacked their way in and have discovered all the basic information being exchanged between these units.

A while back, I got a free PCB (thx, Lennart!) of a circuit by Schelte Bron, called the OpenTherm Gateway, and since all the required components were listed and easily available from Conrad, I decided to give it a go. Here’s the whole thing assembled:

The documentation is very well done: schematics, parts list, troubleshooting, and more.

This is a “gateway” in that it sits between the heater and the thermostat, so it can not only listen in on the conversation but actually take over. Things you can do with it is to adjust the set-point (i.e. desired room temperature), feed in the temperature from an outside sensor, set the ChronoTherm’s clock, and probably more. I’m only interested in monitoring this stuff for now, i.e. reading what is being exchanged.

The gateway is based on an 8-bit PIC controller, and has some funky electronics to do its thing – because the way these signals are encoded is pretty clever: there are only two wires, yet the heater actually powers the thermostat through them, and supports bidirectional I/O (hint: it uses voltage and current modulation).

One little gotcha is that this gateway brings out its interface as an RS232-compatible serial port. And to my surprise, I found out that I don’t even have any laptops to read out these +/- 12V level signals anymore!

So the next task was to get things back into “normal” logic levels. Simple, although it’s a bit of a hack: remove the on-board MAX232 level converter chip, and insert wires to bring out the original 5V logic levels instead:

(bare wire + green clip = GND, read wire + yellow clip = RX, white wire + white clip = TX)

Step two: hook it up to a USB-BUB, set to handle 5V logic levels:

Step three: plug the USB cable into my laptop to pick up the data coming in at 9600 baud.

As you can see, this has wires dangling all over – just to check that the gateway works:

```  OpenTherm Gateway 3.2
T80190000
B40193900
T10010A00
BD0010A00
T80000200
B40000200
...
```

Yeay, looks like we’re getting something! Coming up next: making sense of this data…