Firmware for the OpenTherm Gateway

Fail-safe design

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.

Normal operation

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 thermostat. 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 a problem.

Reports

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 letter.

If desired the gateway can also be instructed to only report the collected information upon demand. See the PS=1 command below for more information.

Errors

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 and 1 in the master status byte depending on the setting of the CH and HW 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.
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/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:
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.
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:
RA6 (pin 15) - GPIO A
No function
RA7 (pin 16) - GPIO B
No function
The LED and GPIO port configuration is stored in EEPROM so they will survive a power interruption.

Details on how to connect the LEDs and other components to the I/O ports are described on a separate page.

Serial commands

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 9600 baud.

Responses

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.
Example:
Command: "TT=19.125"
Response: "TT: 19.13"
If the gateway fails to parse the command, it produces one of the following responses:
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.

Commands

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
OT=temperature
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
HW=state
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
PR=item
Print Report - Request the gateway to report some information item. The following items are currently defined:
  1. About opentherm gateway (prints the welcome message)
  2. Build date and time
  3. The clock speed the code was compiled for (4 MHz)
  4. Configured functions for the two GPIO pins. The response will be 2 digits that represent the functions of GPIO A and GPIO B respectively.
  5. 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.
  6. Configured functions for all 6 LEDS. The response consists of 6 letters representing the functions of LED A through LED F.
  7. Gateway mode. G=Gateway, M=Monitor.
  8. Report the setpoint override value
  9. Current Smart-Power mode (low/medium/high).
  10. The state of the automatic Remeha thermostat detection.
  11. The configured setback temperature.
  12. Tweaks. Reports the state of the ignore transitions and override in high byte settings.
  13. Report the reference voltage setting
  14. Report the domestic hot water setting
Examples: PR=L, PR=A
PS=state
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 following values:
  • 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
  • Maximum relative modulation level (MsgID=14) - Printed as a floating point value
  • 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
  • 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
  • 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
  • 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
A new report can be requested by repeating the "PS=1" command.
Examples: PS=1, PS=0
GW=state
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 information. This command can also be used to reset the gateway by specifying "R" as the state value.
Examples: GW=1, GW=R
LA=function
LB=function
LC=function
LD=function
LE=function
LF=function
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:
  1. Receiving an Opentherm message from the thermostat or boiler
  2. Transmitting an Opentherm message to the thermostat or boiler
  3. Transmitting or receiving a message on the master interface
  4. Transmitting or receiving a message on the slave interface
  5. Remote setpoint override is active
  6. Flame is on
  7. Central heating is on
  8. Hot water is on
  9. Comfort mode (Domestic Hot Water Enable) is on
  10. Transmission error has been detected
  11. Boiler requires maintenance
  12. Raised power mode active on thermostat interface.
Examples: LC=F, LD=M
GA=function
GB=function
GPIO A / GPIO B - These commands configure the functions of the two GPIO pins of the gateway. The following functions are available:
  1. No function, default for both ports on a freshly flashed chip.
  2. Ground - A permanently low output (0V). Could be used for a power LED.
  3. 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.
  4. LED E - An additional LED if you want to present more than 4 LED functions.
  5. LED F - An additional LED if you want to present more than 5 LED functions.
  6. Home - Set thermostat to setback temperature when pulled low.
  7. Away - Set thermostat to setback temperature when pulled high.
  8. DS1820 (GPIO port B only) - Data line for a DS18S20 or DS18B20 temperature sensor used to measure the outside temperature. A 4k7 resistor should be connected between GPIO port B and Vcc.
Examples: GA=2, GB=7
SB=Data-ID
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
AA=Data-ID
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
DA=Data-ID
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
UI=Data-ID
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
KI=Data-ID
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
PM=Data-ID
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
SR=Data-ID:data
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
CR=Data-ID
Clear Response - Clear a previously configured response to send back to the thermostat.
Example: CR=18, CR=70
SH=temperature
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
SW=temperature
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
MM=percentage
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
CS=temperature
Control Setpoint - Manipulate the control setpoint being sent to the boiler. Set to 0 to pass along the value specified by the thermostat.
Example: CS=45.8, CS=0
CH=state
Central Heating - Control the CH enable status bit when overriding the control setpoint. By default the CH enable bit is set after a CS command with a value other than 0. With the CH=0 and CH=1 commands, the bit can be manipulated.
Example: CH=0, CH=1
VS=percentage
Ventilation Setpoint - Configure a ventilation setpoint override value.
Example: VS=25, VS=100
RS=counter
Reset - Clear boiler counter, if supported by the boiler. Available counter names are:
HBSCentral heating burner starts
HBHCentral heating burner operation hours
HPSCentral heating pump starts
HPHCentral heating pump operation hours
WBSDomestic hot water burner starts
WBHDomestic hot water burner operation hours
WPSDomestic hot water pump starts
WPHDomestic hot water pump operation hours
IT=state
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
OH=state
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 default.
Examples: OH=0, OH=1
FT=model
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
VR=level
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 table:
0 1 2 3 4 5 6 7 8 9
0.625V 0.833V 1.042V 1.250V 1.458V 1.667V 1.875V 2.083V 2.292V 2.500V
The normal value is 3.
Examples: VR=3, VR=4
DP=address
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 as two hexadecimal digits. Setting the pointer to 00 switches off the debug reports.
Examples: DP=1F, DP=00

Self Programming

A PIC16F88 is able to read and write its 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 Microchip Application Note AN851.

There are two methods to enter self programming mode:

  1. Power-up or reset the device.
  2. Send a break condition on the serial line.
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.

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.