Firmware for the OpenTherm Gateway
Even though the gateway was designed in such a way that OpenTherm messages
can be forwarded by the device using only hardware functions of the PIC
after very minimal initialization, this is not the normal operating mode of
the gateway. Simply passing on the OpenTherm messages unmodified would limit
the possibilities of the device to monitoring only. However, the almost
non-existing requirements for the code to be able to forward messages makes
it ideal as a safety net for when things go completely awry. If the device
ever resets as a result of a watchdog timeout, it falls back to this mode.
The gateway also takes advantage of this feature during
self-programming. So even when the firmware is being
updated, the thermostat will still be able to communicate with the boiler.
During normal operation the gateway collects the request from the thermostat
and possibly manipulates it before sending it on to the boiler. The full
message has to be received before it can be examined and passed on. This
delays the message to the boiler by the duration of a message. The same
thing happens with the response on the way back from the boiler to the
The complete round-trip of a request from the thermostat to the boiler with
a response back to the thermostat takes about 70ms longer than it would
without the gateway in between. Fortunately the OpenTherm specification
allows a response to take upto 800ms to be delivered to the thermostat. The
boiler generally answers within 200ms, so an additional 70ms does not cause
After power-up, each message that is received by the gateway is reported on
the serial interface. Such a report consists of a letter indicating whether
the message was received from the thermostat ('T') or the boiler ('B'),
followed by 8 hexadecimal digits representing the four data bytes of the
message. If the gateway changes the message before sending it on, the
changed message is also reported on the serial interface. In this case the
first letter indicates if the message is a request sent to the boiler ('R'),
or a response (answer) returned to the thermostat ('A'). In case of a parity
or stop-bit error, the received message is reported with an 'E' as the first
If desired the gateway can also be instructed to only report the collected
information upon demand. See the PS=1 command below for
If an error is detected while receiving an OpenTherm message, the error is
reported on the serial interface and the gateway waits for the OpenTherm
connection to become idle before resuming operation. A connection is
considered idle when no level change has occurred in at least 10 ms.
The following errors are defined:
- Error 01
- Level changes happen too rapidly (disabled by default)
- Error 02
- The stop bit was 0 while it should be 1
- Error 03
- A bit was not received when it was expected
- Error 04
- A parity error was detected on a received opentherm message
Special Data IDs
The firmware of the gateway was designed to treat several Data IDs specially:
- Read-Data Status (ID=0)
- The gateway may manipulate bits 0, 1, and 4 in the master status byte
depending on the setting of the CH,
HW, and H2 commands before
forwarding the request to the boiler.
The original value of the master status byte is restored before sending the
response to the thermostat.
- Write-Data Control Setpoint (ID=1)
- If a setpoint override value has been configured,
the gateway will send the configured setpoint instead of the one received
from the thermostat.
- Write-Data Master configuration (ID=2)
- If the thermostat specifies Smart Power support the gateway will
acknowledge it, regardless of the boiler response.
- Read-Data RBP-flags (ID=6)
- If the boiler doesn't support the DHW Setpoint or Max CH Setpoint
parameters, the gateway will simulate read access.
- Write-Data Control Setpoint 2 (ID=8)
- If a setpoint override value has been configured
for the 2nd heating circuit, the gateway will send the configured setpoint
instead of the one received from the thermostat.
- Read-Data SetPointOverride (ID=9)
- The gateway sends a Read-Ack message with the last configured override
setpoint value. Initially the override room setpoint is 0.0, meaning "no
override". The gateway will continue to send a setpoint override value until
it detects that the thermostat no longer honors the change (probably because
it was canceled by a manual action or by the thermostat schedule). When
that happens the override room setpoint resets itself to 0.0.
- Write-Data Maximum relative modulation level (ID=14)
- If a maximum relative modulation level value has
been configured, the gateway will send the configured setpoint instead of
the one received from the thermostat.
- Write-Data DayTime (ID=20)
- Normally the gateway will acknowledge the time and day by returning the
received data to the thermostat.
After the gateway receives a Set Clock serial command,
the information specified in the command will be returned in the Write-Ack
OpenTherm response instead. The time and day information from a serial
command will only be retained for a maximum of about 61 seconds after the
command was received because the gateway doesn't have the ability to
accurately keep track of time, so it leaves that up to the thermostat.
- Read-Data OutsideTemperature (ID=27)
- Initially the gateway will pass on the value received from the boiler,
or return a Data-Invalid message if the boiler doesn't provide an outside
temperature value. If an outside temperature sensor is connected to the GPIO
pins of the gateway, or an outside temperature has been configured using the
OT serial command, the gateway sends a Read-Ack message
with the measured or configured outside temperature value.
- Read-Data Return water temperature (ID=28)
- If the boiler doesn't provide a return water temperature, a temperature
sensor can be connected to the GPIO pins of the gateway to provide this
If the boiler does provide a return water temperature in a ReadAck, it will
override the value from the temperature sensor. If that is not desired,
message ID 28 can be marked as an unknown data ID:
Note: Only a single temperature sensor is supported. It is not possible to
get both the outside temperature and the return water temperature from
- Read/Write-Data DHW Setpoint (ID=56)
- If a hot water setpoint value has been configured,
the gateway will send the configured setpoint instead of the one received
from the thermostat.
- Read/Write-Data Max CH water Setpoint (ID=57)
- If a max cetral heating setpoint value has been
configured, the gateway will send the configured setpoint instead of the one
received from the thermostat.
- Write-Data Relative ventilation (ID=71)
- If a relative ventilation value has been
configured, the gateway will send the configured value instead of the one
received from the thermostat.
- Read-Data FunctionOverride (ID=100)
- The gateway sends a Read-Ack message with a value depending on the type
of the last override setpoint configuration command. If a continuous
temperature change was specified the returned value will be 0. For a
temporary temperature change the value is 2 (enable overruling remote
setpoint by program setpoint change).
- Read-Data OpenTherm version Slave (ID=125)
- The gateway implements OpenTherm protocol specification version 3.0.
Obtaining additional information
When the device is powered up, the gateway initially passes on most
messages unmodified. If the boiler replies to a certain message with an
Unknown-DataId response, this is recorded. After three consecutive
Unknown-DataId responses for a specific Data ID, the gateway concludes that
the boiler doesn't support that Data ID. The next time the thermostat
sends a requests for the same Data ID, the gateway selects an alternative
Data ID from an internal table and sends that to the boiler instead. This
way the gateway can obtain information from the boiler that the thermostat
doesn't normally request. When the response for the substituted Data ID
comes back from the boiler, the gateway sends an Unknown-DataId response for
the original request to the thermostat.
Indicators and GPIO
Since the PIC had some unused I/O pins, I decided to use a couple of those
to allow LEDs to be connected for indicating certain situations.
The function of the LEDs can be configured using the LA,
LB, LC, and LD serial commands. The initial assignment is:
Two more I/O pins of the PIC are used a GPIO pins. The function of these
pins can also be selected via the GA and GB serial
commands. The initial assignment is:
- RB3 (pin 9) - Flame (F)
- Low when the flame of the boiler is burning.
- RB4 (pin 10) - Transmit (X)
- Low while an OpenTherm message is being transmitted to either the
thermostat or the boiler.
- RB6 (pin 12) - Temperature override (O)
- Low during a remote temperature override state.
- RB7 (pin 13) - Boiler trouble (M)
- The boiler is reporting a problem condition and requires maintenance.
The LED and GPIO port configuration is stored in EEPROM so they will survive
a power interruption.
- RA6 (pin 15) - GPIO A
- RA7 (pin 16) - GPIO B
Details on how to connect the LEDs and other components to the I/O ports are
described on a separate page.
The operation of the gateway can be influenced by sending commands over the
serial interface. All commands consist of a command code made up of two
uppercase letters, an equals sign, and a data value. Commands are terminated
by a carriage return character. A line feed character is optional. The
gateway returns a response for each command it receives. Each response ends
with a carriage return and a line feed character.
The serial interface uses 8-bit data words with no parity and 1 stop bit at
When a serial command is accepted by the gateway, it responds with the two
letters of the command code, a colon, and the interpreted data value.
If the gateway fails to parse the command, it produces one of the following
- Command: "TT=19.125"
- Response: "TT: 19.13"
- NG - No Good
- The command code is unknown.
- SE - Syntax Error
- The command contained an unexpected character or was incomplete.
- BV - Bad Value
- The command contained a data value that is not allowed.
- OR - Out of Range
- A number was specified outside of the allowed range.
- NS - No Space
- The alternative Data-ID could not be added because the table is full.
- NF - Not Found
- The specified alternative Data-ID could not be removed because it does
not exist in the table.
- OE - Overrun Error.
- The processor was busy and failed to process all received characters.
The following serial commands are currently available:
- TT=temperature [*]
- Temperature, Temporary - Temporarily change the thermostat setpoint. The
thermostat program will resume at the next programmed setpoint change.
Values between 0.0 and 30.0 are allowed. A value of 0 indicates no remote
override is to be applied.
Examples: TT=19.5, TT=0
- TC=temperature [*]
- Temperature, Constant - Change the thermostat setpoint. The thermostat
program will not change this setting. Values between 0.0 and 30.0 are
allowed. A value of 0 cancels the remote override.
Examples: TC=16.0, TC=0
- Outside temperature - Configures the outside temperature to send to the
thermostat. Allowed values are between -40.0 and +64.0, although thermostats
may not display the full range. Specify a value above 64 (suggestion: 99) to
clear a previously configured value.
Examples: OT=-3.5, OT=99
- SC=time/day [*]
- Set Clock - Change the time and day of the week of the thermostat. The
gateway will send the specified time and day of the week in response to the
next time and date message from the thermostat. The time must be specified
as HH:MM. The day of the week must be specified as a single digit between 1
(Monday) and 7 (Sunday).
Examples: SC=9:00/1, SC=23:59/4
- Hot Water - Control the domestic hot water enable option. If the boiler
has been configured to let the room unit control when to keep a small amount
of water preheated, this command can influence that. A state of 0 or
1 will tell the boiler whether or not to keep the water warm. Any other
single character causes the gateway to let the thermostat control the boiler.
Possible values are 0, 1, or any other single character.
Examples: HW=1, HW=T
- Print Report - Request the gateway to report some information item. The
following items are currently defined:
Examples: PR=L, PR=A
- About opentherm gateway (prints the welcome message)
- Build date and time
- The clock speed the code was compiled for (4 MHz)
- The DS18x20 temperature sensor function. O=Outsite temperature,
R=Return water temperature.
- Configured functions for the two GPIO pins. The response will
be 2 digits that represent the functions of GPIO A and GPIO B respectively.
- Current state of the two GPIO pins. The response will be 2
digits that represent the level (0 or 1) of GPIO A and GPIO B respectively.
- Configured functions for all 6 LEDS. The response consists of
6 letters representing the functions of LED A through LED F.
- Gateway mode. G=Gateway, M=Monitor.
- Report the setpoint override value
- Current Smart-Power mode (low/medium/high).
- Cause of the last reset. Possible return values:
- Brown out (supply voltage dropped below 4.35V on PIC16F88 or
2.7V on PIC16F1847)
- By command (GW=R)
- External reset (using the reset button)
- Stuck in a loop (same message received 64x)
- Stack overflow (PIC16F1847 only)
- Power on
- BREAK condition on the serial interface
- Stack underflow (PIC16F1847 only)
- Watch dog timer
- The state of the automatic Remeha thermostat detection.
- The configured setback temperature.
- Tweaks. Reports the state of the ignore transitions and
override in high byte settings.
- Report the reference voltage setting
- Report the domestic hot water setting
- Print Summary - The opentherm gateway normally prints every opentherm
message it receives, as well as the modified messages it transmits. In some
applications it may be more useful to only get a report of the latest values
received for the most interesting parameters on demand. Issuing a "PS=1"
command will stop the reports for each message and print one line with the
A new report can be requested by repeating the "PS=1" command.
- Status (MsgID=0) - Printed as two 8-bit bitfields
- Control setpoint (MsgID=1) - Printed as a floating point value
- Remote parameter flags (MsgID=6) - Printed as two 8-bit bitfields
- Cooling control signal (MsgID=7) - Printed as a floating point value
- Control setpoint 2 (MsgID=8) - Printed as a floating point value
- Maximum relative modulation level (MsgID=14) - Printed as a floating point
- Boiler capacity and modulation limits (MsgID=15) - Printed as two bytes
- Room setpoint (MsgID=16) - Printed as a floating point value
- Relative modulation level (MsgID=17) - Printed as a floating point value
- CH water pressure (MsgID=18) - Printed as a floating point value
- DHW flow rate (MsgID=19) - Printed as floating point value
- CH2 room setpoint (MsgID=23) - Printed as a floating point value
- Room temperature (MsgID=24) - Printed as a floating point value
- Boiler water temperature (MsgID=25) - Printed as a floating point value
- DHW temperature (MsgID=26) - Printed as a floating point value
- Outside temperature (MsgID=27) - Printed as a floating point value
- Return water temperature (MsgID=28) - Printed as a floating point value
- CH2 flow temperature (MsgID=31) - Printed as a floating point value
- Boiler exhaust temperature (MsgID=33) - Printed as a signed decimal value
- DHW setpoint boundaries (MsgID=48) - Printed as two bytes
- Max CH setpoint boundaries (MsgID=49) - Printed as two bytes
- DHW setpoint (MsgID=56) - Printed as a floating point value
- Max CH water setpoint (MsgID=57) - Printed as a floating point value
- V/H master status (MsgID=70) - Printed as two 8-bit bitfields
- V/H control setpoint (MsgID=71) - Printed as a byte
- Relative ventilation (MsgID=77) - Printed as a byte
- Burner starts (MsgID=116) - Printed as a decimal value
- CH pump starts (MsgID=117) - Printed as a decimal value
- DHW pump/valve starts (MsgID=118) - Printed as a decimal value
- DHW burner starts (MsgID=119) - Printed as a decimal value
- Burner operation hours (MsgID=120) - Printed as a decimal value
- CH pump operation hours (MsgID=121) - Printed as a decimal value
- DHW pump/valve operation hours (MsgID=122) - Printed as a decimal value
- DHW burner operation hours (MsgID=123) - Printed as a decimal value
Examples: PS=1, PS=0
- GateWay - The opentherm gateway starts up in back-to-back mode. While
this is the most useful mode of operation, it also means that the firmware
must be able to decode the requests received from the thermostat before it
can send them on to the boiler. The same is true for responses from the
boiler back to the thermostat. By changing this setting to "0" (monitor
mode), the received signal level is passed through to the output driver
without any processing. This can be a useful diagnostic tool when there are
communication problems immediately after the gateway has been built.
See the troubleshooting section for more
This command can also be used to reset the gateway by specifying "R" as the
Examples: GW=1, GW=R
- LED A / LED B / LED C / LED D / LED E / LED F - These commands can be
used to configure the functions of the six LEDs that can optionally be
connected to pins RB3/RB4/RB6/RB7 and the GPIO pins of the PIC. The
following functions are currently available:
Examples: LC=F, LD=M
- Receiving an Opentherm message from the thermostat or boiler
- Transmitting an Opentherm message to the thermostat or boiler
- Transmitting or receiving a message on the master interface
- Transmitting or receiving a message on the slave interface
- Remote setpoint override is active
- Flame is on
- Central heating is on
- Hot water is on
- Comfort mode (Domestic Hot Water Enable) is on
- Transmission error has been detected
- Boiler requires maintenance
- Raised power mode active on thermostat interface.
- GPIO A / GPIO B - These commands configure the functions of the two GPIO
pins of the gateway. The following functions are available:
Examples: GA=2, GB=7
- Input - A general digital input port. The state can be obtained using the
PR=I command. This is the default for both ports on a freshly flashed chip.
- Ground - A permanently low output (0V). Could be used for a power LED.
- Vcc - A permanently high output (5V). Can be used as a short-proof power
supply for some external circuitry used by the other GPIO port.
- LED E - An additional LED if you want to present more than 4 LED
- LED F - An additional LED if you want to present more than 5 LED
- Home - Set thermostat to setback temperature when pulled low.
- Away - Set thermostat to setback temperature when pulled high.
- DS1820 (GPIO port B only) - Data line for a DS18S20, DS18B20, or DS1822
temperature sensor used to measure the outside temperature or return
water temperature. A 4k7 resistor should be connected between GPIO port
B and Vcc.
- SetBack temperature - Configure the setback temperature to use in
combination with GPIO functions HOME (5) and AWAY (6). Note: The SB command
may need to store 2 bytes in EEPROM. This takes more time than it takes to
transfer a command over the serial interface. If you immediately follow the
SB command by more commands that store configuration data in EEPROM, the
gateway may not be able to handle all commands. To avoid any problems when
sending a sequence of configuration commands, send the SB command last.
Examples: SB=15, SB=16.5
- Temperature Sensor - Select the temperature sensor function.
The following functions are available:
Examples: TS=O, TS=R
- Outside temperature
- Return water temperature
- Add Alternative - Add the specified Data-ID to the list of alternative
commands to send to the boiler instead of a Data-ID that is known to be
unsupported by the boiler. Alternative Data-IDs will always be sent to the
boiler in a Read-Data request message with the data-value set to zero. The
table of alternative Data-IDs is stored in non-volatile memory so it will
persist even if the gateway has been powered off.
Data-ID values from 1 to 255 are allowed.
Examples: AA=33, AA=117
- Delete Alternative - Remove the specified Data-ID from the list of
alternative commands. Only one occurrence is deleted. If the Data-ID appears
multiple times in the list of alternative commands, this command must be
repeated to delete all occurrences. The table of alternative Data-IDs is
stored in non-volatile memory so it will persist even if the gateway has
been powered off.
Data-ID values from 1 to 255 are allowed.
Examples: DA=116, DA=123
- Unknown ID - Inform the gateway that the boiler doesn't support the
specified Data-ID, even if the boiler doesn't indicate that by returning an
Unknown-DataId response. Using this command allows the gateway to send an
alternative Data-ID to the boiler instead.
Examples: UI=18, UI=6
- Known ID - Start forwarding the specified Data-ID to the boiler again.
This command resets the counter used to determine if the specified Data-ID
is supported by the boiler.
Examples: KI=18, KI=123
- Priority Message - Specify a one-time priority message to be sent to the
boiler at the first opportunity. If the specified message returns the number
of Transparent Slave Parameters (TSPs) or Fault History Buffers (FHBs), the
gateway will proceed to request those TSPs or FHBs.
Example: PM=10, PM=72
- Set Response - Configure a response to send back to the thermostat
instead of the response produced by the boiler. The data argument is either
one or two bytes separated by a comma.
Example: SR=18:1,205, SR=70:14
- Clear Response - Clear a previously configured response to send back to
Example: CR=18, CR=70
- Setpoint Heating - Set the maximum central heating setpoint. This
command is only available with boilers that support this function.
Examples: SH=72.5, SH=+20
- Setpoint Water - Set the domestic hot water setpoint. This command is
only available with boilers that support this function.
Examples: SW=60, SW=+40.0
- Maximum Modulation - Override the maximum relative modulation from the
thermostat. Valid values are 0 through 100. Clear the setting by specifying
a non-numeric value.
Examples: MM=100, MM=T
- Control Setpoint - Manipulate the control setpoint being sent to the
boiler. Set to 0 to pass along the value specified by the thermostat.
To stop the boiler heating the house, set the control setpoint to some low
value and clear the CH enable bit using the CH command.
The CS command must be repeated at least every minute as long as adjustment
This is a vigilance check to prevent runaway heating in case the controlling
program loses its connection, or crashes.
Warning: manipulating these values may severely impact the control
algorithm of the thermostat, which may cause it to start heating much too
early or too aggressively when it is actually in control.
Example: CS=45.8, CS=0
- Control Setpoint for 2nd CH circuit - Manipulate the control
setpoint being sent to the boiler for the second CH circuit. Set to 0 to
pass along the value specified by the thermostat.
Example: C2=45.8, C2=0
- Central Heating - When using external control of the control setpoint
(via a CS command with a value other than 0), the gateway sends a CH enable
bit in MsgID 0 that is controlled using the CH command. Initially this bit
is set to 1.
When external control of the control setpoint is disabled (CS=0), the CH
enable bit is controlled by the thermostat.
Example: CH=0, CH=1
- Central Heating 2nd circuit - When using external control of
the control setpoint (via a C2 command with a value other than 0), the
gateway sends a CH2 enable bit in MsgID 0 that is controlled using the H2
command. Initially this bit is set to 1.
When external control of the control setpoint is disabled (C2=0), the CH2
enable bit is controlled by the thermostat.
Example: H2=0, H2=1
- Ventilation Setpoint - Configure a ventilation setpoint override value.
Example: VS=25, VS=100
- Reset - Clear boiler counter, if supported by the boiler.
Available counter names are:
|HBS||Central heating burner starts
|HBH||Central heating burner operation hours
|HPS||Central heating pump starts
|HPH||Central heating pump operation hours
|WBS||Domestic hot water burner starts
|WBH||Domestic hot water burner operation hours
|WPS||Domestic hot water pump starts
|WPH||Domestic hot water pump operation hours
- Ignore Transitions - If the opentherm signal doesn't cleanly transition
from one level to the other, the circuitry may detect multiple transitions
when there should only be one. When this setting is off (IT=0), the gateway
will report "Error 01" for those cases. With this setting on (IT=1), any
rapid bouncing of the signal is ignored. This is the default.
Examples: IT=0, IT=1
- Override in High byte - The Opentherm specification contains
contradicting information about which data byte of Data-ID 100 should hold
the override bits. When this setting is off (OH=0), the gateway will only
put the bits in the low byte. When the setting is on (OH=1), the bits are
copied to the high byte so they appear in both bytes. This is the
Examples: OH=0, OH=1
- Force Thermostat - To be able to apply special treatment required by
some thermostat models, the gateway will try to auto-detect which thermostat
is connected. In some cases it is unable to determine this correctly. This
configuration option can then be used to force the model. Valid models are:
'C' (Remeha Celcia 20) and 'I' (Remeha iSense). Any other letter restores
the default auto-detect functionality.
Examples: FT=C, FT=D
- Voltage Reference - Change the reference voltage used as a threshold for
the comparators. This configuration option is stored in non-volatile memory
so it will persist even if the gateway has been powered off.
The level must be specified as a single digit according to the following
The normal value is 4 on a PIC16F88 and 5 on a PIC16F1847.
Examples: VR=3, VR=4
- Debug Pointer - Set the debug pointer to a file register. If the debug
pointer has been set to a value other than 00, the contents of the selected
file register will be reported over the serial interface after each received
OpenTherm message. The address must be specified in hexadecimal, using 2
characters on a PIC16F88, 2 or 3 characters on a PIC16F1847.
Setting the pointer to 0 switches off the debug reports.
Examples: DP=1F, DP=1D0, DP=00
Both the PIC16F88 and PIC16F1847 are able to read and write their own flash
memory. The gateway takes advantage of this possibilty and allows the
firmware to be upgraded over the serial connection.
The method used to update the firmware is a slightly modified version of
Application Note AN851.
A new, blank PIC will need to be programmed initially using a PIC programmer.
But once it is loaded with firmware that includes the boot loader, any
subsequent firmware updates can be done via the self programming mechanism
implemented in OTmonitor.
There are three methods to enter self programming mode:
In response to either of these events, the firmware transmits an <ETX>
character. If no serial input is received within one second, or the first
received serial character is something other than <STX>, the device
does not enter self-programming mode and resumes normal operation.
- Power-up or reset the device.
- Send a break condition on the serial line.
- Issue a GW=R command.
Self-programming code upgrade
The self-programming code is part of the firmware, and modifying code while
it is being executed is not a good idea. So any self-programming tools must
make sure not to touch that part of the firmware during a normal upgrade.
The Firmware Upgrade feature of the Opentherm Monitor does indeed skip the
memory area containig the self-programming code when loading new firmware.
However, it may occasionally be desirable to upgrade the self-programming
code to fix a bug in that part. This is done using a special firmware image.
Such a self-programming upgrade firmware image contains a copy of the new
self-programming code in a different memory area, plus the code necessary to
move it into place. After the image has been loaded, the code that installs
the new self-programming code will run. This should only take about a second.
A message is printed when the process has completed.
The self-programming code upgrade firmware configures the comparators to
pass-through mode, which allows communication between the thermostat and the
boiler to take place. To restore the full functionality of the gateway, the
regular gateway firmware image must be reloaded.
The self-programming upgrade firmware has been designed in such a way that
the device is in an unbootable state for as little time as possible.
However there are a few microseconds in the upgrade process where it cannot
be guaranteed that the device will be able to boot if the power is removed
at that point. So, it is strongly advised to make sure the upgrade is
allowed to complete uninterrupted.
In the unlikely case that the device does become unbootable, a PIC
programmer will be needed to bring the gateway back to life.