Virtually every modern heater and thermostat will speak OpenTherm, but Remeha in their infinite wisdom created their own protocol called R-Bus. This protocol is to the best of my knowledge completely undocumented, so this is my attempt at doing that.
The monitor PCB arrived and works! So now I have a permanent way to access logs from R-Bus. I just don't have somewhere to log to yet.
I found a RE discord:
Fried Microcrisps
fa0001542e01 11ad 1a033701
These to me look like 1 byte integer part <.> 3byte decimal part
fa0001302300 9e29 2c658403483aff71
This I highlighted I think is most likely milliseconds Your time shown in screenshot is around 4.24pm or 1624H, for brevity it shall be 16.5 hours This is equal to 59400000 milliseconds, which in hex is 038A5F40 (be) Close enough
A few realizations
The room temperature and water setpoint will be in a request (thermostat) Outside temperature and water temperatures will be in replies (heat pump)
One request with a uint64 stands out to me:
Request flags=00000000 length=11 unknown=[F4 04 01] payload=34 23 01 00 00 00 00 00 00 4C 66
That's 19558 in decimal, possibly the room temperature in millidegrees?
In the ascii data we saw Zone1
, and it made me realise that there can be multiple zones.
But also that the boiler is daisy chained behind the heat pump.
Could it be that some of those unknown triplets indicate the device and zone?
The Zone1
messages appears to have a pretty regular structure, but it doesn't hold up with other messages
05 # number of fields
?? ?? typ key? len data
01 01 [34] [10 01 00 00] [05] [43 48 00 00 00]
01 01 [34] [63 01 00 00] [01] [00]
01 01 [34] [0F 01 00 00] [14] [5A 6F 6E 65 31 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00]
01 01 [34] [64 01 00 00] [04] [BF A9 00 00]
typ u16?
01 01 [5C] [18 44]
EHC-07
:
09 # not a length
tp key ln dat
01 01 30 0F 00 00 00 14 45 48 43 2D 30 37 00 00 00 00 00 00 00 00 00 00 00 00 00 00
01 01 20 01 04 00 00 02 07 01
01 01 20 01 03 00 00 02 03 03
??
02 01 20 01 10 00 00 04 11 00 09 06
01 01 30 18 00 00 E6 ??
7733242-06
:
02 0B 01 ???
# tp key ln data
01 01 20 01 0B 00 00 14 37 37 33 33 32 34 32 2D 30 36 00 00 00 00 00 00 00 00 00 00
01 01 50 3D 01 00 00 01 05
01 01 20 01 0A 00 00 04 61 01 0B 2E
01 01 20 01 02 00 00 02 07 02
13 ???
MK2.1
:
no header
?? tp key ln data
01 03 30 0F 00 00 00 14 4D 4B 32 2E 31 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
01 03 20 01 04 00 00 02 06 01
01 03 20 01 03 00 00 02 01 02
AD 09 ???
7711844-06
:
ln data
20 01 0B 37 37 31 31 38 34 34 2D 30 36 00
?? ?? ?? uint64? "GO"?
00 00 00 00 00 00 00 00 00 47 4F
I am trying to find the temperature in the data somewhere. I've tried to parse every right-alligned number type that fits in a payload, and the most promising candidates seem to be the numbers in the 20k range I saw last time, but they don't exactly match the temperature.
Could they be the water temperature? You might expect hot water to be around 50°C and the return temperature of the water to be slightly above ambient. Sadly I can't see those temperatures in the app to verify.
Working on the assumption that in cases where the first 3 bytes of the request and reply payload match they indicate some register, I wrote a script that groups messages by type and register to see how they change over time. Many of them are constant and uninteresting, and som vary seemingly at random. But some vary at a few distinct points in time, possibly in response to me messing with the settings.
I've collected these messages in registers.txt. For now they don't make much sense yet but it narrows down the search space. It also clearly shows that there are some bit errors that could explain some weirdness.
I've also had the idea to look for ascii data in the payloads.
That wont get us the temperature, but it might give some other insights.
I've collected these messages in ascii.txt.
You can see fun stuff like Zone1
for the heating zone, EHC-07
the model of the heat pump, 7733242-06
and 7711844-06
could be serial numbers, and MK2.1
could be a hardware revision, there are also heating modes like Home
and Sleep
. Other than that I'm not sure what we can learn here.
One thing it does seem to confirm is that the replies are coming from EHC-07
, the heat pump,
which suggests the requests are from the thermostat.
This also suggests that we should look for the thermostat set points in the requests.
I have started poking around with the message type.
I'm operating under the assumption that the first unknown byte is some kind of message type.
A particular interaction caught my eye where a FA
request was answered with an F3
reply.
In all FA
requests there is a 5 byte payload that seems to be roughly
byte | meaning |
---|---|
20 02 01 |
address? |
73 F0 |
unknown |
and a F3
reply of the form
byte | meaning |
---|---|
20 02 01 |
same address |
00 00 00 00 00 00 6C 4A |
uint_64? |
I counted the reply bytes and their length and there seem to be 4 very common Fx
replies with a common length. Most but not all follow the 3 byte "address" pattern.
Counter({'F7 7': 984,
'F5 9': 802,
'F8 6': 740,
'F3 11': 715,
'E6 24': 41,
'FE 1': 17,
'FA 5': 17,
'E5 25': 14,
'EF 15': 9,
'00 0': 5,
'2E 1': 3,
'2D 1': 1,
'F5 25': 1,
'7D 9': 1,
'2E 9': 1,
'01 100': 1,
'F9 5': 1,
'F3 43': 1,
'00 1': 1,
'0A 1': 1,
'A4 187': 1})
I tried parsing those supposed uint_64 with the following result. I was hoping it'd be something obvious like the temperature in millidegrees but while not miles off, not exactly. (recall it was 20°C at the time)
(48, 35, 0, 12151716762370106083)
(32, 2, 1, 16762457204505351945)
(52, 33, 1, 25079)
(32, 2, 1, 16762457204505351945)
(32, 2, 1, 27722)
(48, 35, 0, 13315615791068642237)
(32, 2, 1, 16762457204505351945)
(32, 2, 1, 27722)
(52, 35, 1, 47222)
(52, 34, 1, 29879)
(52, 33, 1, 25079)
(32, 2, 1, 16762457204505351945)
(32, 2, 1, 27722)
(48, 35, 0, 10876635117870837854)
(32, 2, 1, 27722)
(52, 35, 1, 47222)
(52, 34, 1, 29879)
(52, 33, 1, 25079)
(48, 35, 0, 3173792004718625437)
(32, 2, 1, 16762457204505351945)
(32, 2, 1, 27722)
One thing that is slightly concerning is that there are some parse errors after really long messages. Not sure if just a glitch in the serial data, or something funky like replacing certain bytes. I remember Pokemon has a whole thing where they replace 0xFE with something else and then send a whole mask array, because 0xFE is their handshake byte.
I have started building a parser that breaks a stream of bytes from the logger into messages. Turns out I was decoding the bit order wrong, and now some things are more obvious. The format seems to be
byte | meaning |
---|---|
01 00 |
header |
01 |
request/reply |
00 |
some bit flags? |
07 |
payload length |
F7 01 FE |
unknown |
10 03 01 FF FF 85 9C |
payload |
I have built a data logger with a comparator and an Arduino, and collected a good long chunk of messages in log.txt, while simultaneously collecting screenshots of the official app in screenshots and adjusting the temperature between 20°C and 22°C.
The schematic of the datalogger is in demodulator.pdf, and the Arduino sketch is in echo.ino.
Analysis of the new data tbd.
I have collected an oscilloscope capture of the wires between my Remeha Elga Ace heat pump and Remeha eTwist thermostat. This can be found as a compressed CSV file in RigolDS1.tar.xz
.
It appears to be a simple on-off keying scheme with a 500kHz carrier and a 10kHz bit rate.
To decode the capture, I first demodulate it with demodulate.py
, and then import demodulated_output.csv
in urh. Automated detection worked correctly, but I did set the pause threshold and message length divisor to 10. The analysis tab proved unhelpful so I just exported the data to protocol.proto.xml
.
My hunch is that it's regular old 8N1 UART data, but possibly inverted. In decode_bytes.py
I read the exported XML from urh, verify start and stop bits, and extract the data bits. The output is stored in messages.txt
, a sample is provided below:
80 00 00 00 A0 5F 00 80 2C C4 80 F9 95
80 00 80 00 D0 CF 80 7F 2C C4 80 00 00 00 00 00 00 1D 6E
80 00 00 00 A0 5F 00 80 2C 44 80 F0 15
80 00 80 00 D0 CF 80 7F 2C 44 80 00 00 00 00 00 00 2E ED
If you look at the raw capture you can see two slightly different magnitudes, so I think it is reasonable to assume this are the two devices in a request/response interaction. It seems like the first bytes are just some kind of addressing or synchronization, with the third byte being 00
in the request and 80
in the response. Possibly the fifth byte could be some message ID.
In some of the messages the last 8 bytes look like it could be an uint64 (00 00 00 00 00 00 2E ED
), hopefully representing some useful value. The request has two bytes in that place. (F9 95
) The three bytes before that match in the request and reply, and the byte before that is off by one. (80 2C 44 80
-> 7F 2C 44 80
) Maybe there is some register ID or message sequence number in there?