Introduction
The main reason why I started my domotica project was to control my heating remotely. When I needed to overhaul my complete heating system some time ago, it seemed like a good time to realize this wish. So I started to look around for systems already on the market.

Here in The Netherlands we mostly use heating systems that transport their heat using water, where in other countries air is often used. A boiler is used to heat water and an internal pump forces the warm water through a network of pipes to radiators installed all over the house. Each radiator has a valve that enables the user to turn it off. A thermostat in the living room regulates the burner of the boiler, making the whole system closed loop regulated.

Modern boilers use 'modulating burners'. We techies just call that a proportional actuator, like we have been doing since long before boiler manufacturers even existed, but that's ok. The advantage of these boilers is clearly their much higher efficiency. Manufacturers specify this to be up to 109% (muwhahahaha), but the measurement method used was once normalized to what was thought to me the maximum feasible. Boy, where they wrong. Anyway, this high efficiency is achieved by squeezing out the last bit of heat even out of the condensing water and therefore this maximum efficiency is only achieved when the required water temperature is as low as possible, sometimes even down to 40 degrees. At higher water temperatures the efficiency of such a boiler is a lot lower.

Because of this, the communication protocol between boiler and thermostat is a little more demanding than just the two states 'on' and 'off. Of course these boilers can still be controlled using a simple on/off thermostat, but in such a setup it will regulate its burner according to the returning water temperature, making the whole system far less efficient.

Somehow every manufacturer has thought of his own proprietary solution for boiler/thermostat communication, probably to protect their market. A few manufacturers have decided to embrace the OpenTherm standard for this. And initially I thought this would be the way to go here, but 'OpenTherm' only appears to be a name: It's not 'Open' as 'Open Source', but far from that. In fact, if you want to get your hands on the protocol, you need to become a member of the OpenTherm-maffia, at a price that's way too high for hobbyists and still it's no guarrantee for getting your equiptment to work because manufacturers are still free to fill out a whole lot of blanks.

Why not to build your own thermostat
I didn't really want much from my system. I only needed to be able to set the setpoint (desired temperature) remotely. Reading back the setpoint and the and the measured temperature (actual room temperature) would be nice extras. I also wanted to be able to automatically change the setpoint to a predetermined low value, of for example 16 degrees, every night at 0:00 so I'd never have to worry about forgetting to turn off the heating anymore. This could be covered by integration/interfacing with my domotica system.

Since my demands were not very high, building my own thermostat has crossed my mind; A simple thermostat with little features appeared to be easy to build, but in fact it's not: Regulating a room's temperature is one of the most underestimated controlling task. It is often used as an example in education becuase its easy to relate to and analogies are easily understood. Therefore it seems very simple, but in order to do it right it's utterly difficult. Building a bad thermostat is dead-easy. Preventing over-shoot, avoiding oscillation making the regulator intelligent by learing the systems properties makes it a little more harder. But to make the system effecient is very hard: The thermostat must try to an equilibrium in which the burner setting exactly compensates the heat escaping from the house. Only this will make sure the system operates at the lowest possible water temperature and hence the highest efficiency. Developing all these algorythms would be a project on its own and doing so at home without any equipment seemed like madness, especially because it's not exactly something that hasn't been done before: The market is full of very good thermostats. So obviously I abandoned this idea.

Controlling the controller
So the only same way to go here seemed not to control the boiler, but to control the thermostat. After all it is the room temperature I wanted to control, not the water temperature of the boiler. There are a number of externally controllable thermostats on the market nowadays, but none of them are capable of proportional control. Some of the big brands, with their own proprietary protocol between boiler and theremostat, offer some external control. But that too is proprietary and they offer acces only through their server: Obviously they still think they can sell people a 10Euro/month subscription to control their own equipment.

So does Remeha; They sell a device they call the Remaha GateWay which acts as an extra node on the OpenThem bus and offers a serial port for a modem. This gateway could be used to control the Remeha Celcia 20 OpenThem thermostat. The specifications wrote this serial port can also be use for service purposes, which specifically attracted my attention. The modem could be used to connect to the Remeha server so the boiler can be controlled through their website, requiring the usual subscription. But it also offers the possibility to dial in directly to send commands using the key pad (DTMF) of a regular touch-tone telephone. This made me feel confident enought to purchase Remeha equipment: If it couldn't reverse-engineer the protocol, I could still emulate a Hayes compatible modem in my software to pretend an incoming phone call with according DTMF commands.

The protocol
After I already ordered all equipment, I discovered a small but very useful program on the Remeha professional internet site. This program appeared to use the service protocol to retrieve information from the thermostat. A closer look revealed it is also capable of selecting the setpoint for the room temperature and a whole lot of configuration options. An evening worth of reverse-engineering yielded quite some result

The gateway uses a serial port to communicate. It connects to a PC with a fully wired null-modem cable with two female DB9 connectors. It communicates at 9600 bits/second with 8 data bits, no parity bits and 1 stop bit.

The first level of is a quite simple Enq-Ack/NAck protocol. Before sending anything to the Gateway, the host needs to send an <ENQ> (0x05) character first. If the host receives an <ACK> (0x1A) in reply, it can continue. If it receives a <NACK> (0x15) it should try again after some time.
Note 1: After a datagram is sent to the Gateway, it normally replies the answering datagram directly. But instead of answering datagram, it could still reply a <NACK>. In that case the has to time-out briefly and go back to sending an <ENQ> again. It to resend its datagram upon reception of an <ACK>.
Note 2: By default the Gateway is configured to handle a modem on its serial port. This means that up until an <ACK> has been received from the Gateway, regular Hayes compatible commands should be expected as well. The host can simply discard those, but the implementation of the protocol should take this into concern. Of course this option can be switched off, but a good implementation of the protocol doesn't require that.

The layout of the datagram is as follows:
<STX><ADR><CHKa><STX><TYPE><DATA><CHKd><ETX>
Where:
<STX> = Start of text character (0x02)
<ADR> = Address, can be more than one byte, but I've only seen 1
0x00 = Gateway
0x0A = Host
<CHKa> = Checksum of address bytes
This is calculated by adding all address bytes in one byte, allowing for roll-over. In practice, this is equal to the address byte, because there's only one of those.
<STX> = Another start of text character (0x02)
<TYPE> = Type of datagram
<DATA> = The actual data, usually more 9 bytes, but may be abcent at all. The meaning of each byte differs per datagram type.
<CHKd> = Checksum of Type and Data bytes
This is calculated by adding the Type byte and all data bytes in one byte, allowing for roll-over.
<ETX> = End of text character (0x03)

Request 'Temperatures':
 02 00 00 02 50 50 03
              |
              +------------------------------------ Request 'Temperatures'-datagram
Answer from Gateway:
 02 0A 0A 02 50 14 D7 14 99 26 00 00 00 02 00 10 03
              |  |  |  |  |  |  |  |  |  |  |
              |  |  |  |  |  |  |  |  |  |  +------
              |  |  |  |  |  |  |  |  |  +--------- Status Celcia
              |  |  |  |  |  |  |  |  +------------
              |  |  |  |  |  |  |  +---------------
              |  |  |  |  |  |  +------------------
              |  |  |  |  |  +--------------------- T Boiler Set, hexadecimal: 38
              |  |  |  |  +------------------------ T Room Set, 1/256th degrees hexadecimal: 60
              |  |  |  +--------------------------- T Room Set, whole degrees hexadecimal: 20
              |  |  +------------------------------ T Room, 1/256th degrees hexadecimal: 84
              |  +--------------------------------- T Room, degrees hexadecimal: 20
              +------------------------------------ 'Temperatures'-datagram

Request 'Boiler status':
 02 00 00 02 51 51 03
              |
              +------------------------------------ Request 'Boiler status'-datagram
Answer from Gateway:
 02 0A 0A 02 51 32 39 0A 00 0D 00 00 00 00 00 D3 03
              |  |  |  |  |  |  |  |  |  |  |
              |  |  |  |  |  |  |  |  |  |  +------
              |  |  |  |  |  |  |  |  |  +---------
              |  |  |  |  |  |  |  |  +------------
              |  |  |  |  |  |  |  +---------------
              |  |  |  |  |  |  +------------------
              |  |  |  |  |  +---------------------
              |  |  |  |  +------------------------
              |  |  |  +--------------------------- Status Boiler, hexadecimal: 10
              |  |  +------------------------------ Modulation level, hexadecimal: 57
              |  +--------------------------------- T Boiler, hexadecimal: 50
              +------------------------------------ 'Boiler status'-datagram

Request 'Counters':
 02 00 00 02 52 52 03
              |
              +------------------------------------ Request 'Boiler status'-datagram
Answer from Gateway:
 02 0A 0A 02 52 78 00 07 44 03 06 01 63 05 07 8E 03
              |  |  |  |  |  |  |  |  |  |  |
              |  |  |  |  |  |  |  |  |  +--+------ StartDHW divided by 10, decimal: 507
              |  |  |  |  |  |  |  +--+------------ HoursDHW, decimal: 163
              |  |  |  |  |  +--+------------------ StartsCH divided by 10, decimal: 306
              |  |  |  +--+------------------------ HoursCH, decimal: 744
              |  |  +------------------------------
              |  +---------------------------------
              +------------------------------------ 'Counters'-datagram

Request 'version info':
 02 00 00 02 53 53 03
              |
              +------------------------------------ Request 'Version Answer from Gateway:
Answer from Gateway:
   02 0A 0A 02 53 03 04 14 24 01 0B 02 00 00 00 A0 03
              |  |  |  |  |  |  |  |  |  |  |
              |  |  |  |  |  |  |  |  |  |  +------
              |  |  |  |  |  |  |  |  |  +---------
              |  |  |  |  |  |  |  |  +------------
              |  |  |  |  |  |  |  +--------------- Slave Member ID
              |  |  |  |  |  |  +------------------ Master Member ID
              |  |  |  |  |  +--------------------- Slave Product Type
              |  |  |  |  +------------------------ Slave Product Version
              |  |  |  +--------------------------- Master Product Type
              |  |  +------------------------------ GateWay Version
              | +---------------------------------- Master Product Version
              +------------------------------------ 'Version info'-datagram