Contents

Reverse engineering the Hörmann UAP1-HCP protocol

Years ago I stumbled upon a blog by bouni reverse engineering the Hormann protocol used on the supramatic E3 and equivalent motors. I benefitted greatly from this data to talk directly to our garage door. I’m using an ESP32 based solution which implements the Apple HomeKit protocol natively (next to MQTT for other integration options). So when confronted with a new protocol Hormann used on the newer promatic/supramatic E4 motors I decided to return the favour to the community, perhaps others will find this information equally helpful as I did at the time.

The connectivity options for the E4 series are very similar to the prior versions:

  • potential free contacts, toggling the target states of the door between closed-open-stopped. Not very useful to automate since you lack feedback, unless you hook up sensors along the rail/door to learn in what state it currently is.
  • RF via BiSecur like the remote does, slightly better than the first option since you can now send distinct up/down commands, but you still don’t know in what state the door is.
  • Bluetooth / BlueSecur, a new option on the E4 which allows control of the motor via a paired android/ios app. I must say I didn’t even try going down this path after being used to our E3 homekit integration, the reach also seems to be very limited from what I read.
  • UAP1-HCP, the “Universal Adapter Platine” from Hormann allowing discrete external inputs/outputs, the successor of the UAP1 for the E3 series. It costs about 80 euro for this variant, and has discrete inputs/outputs for the door states. This was the candidate to reverse engineer the protocol and make our direct setup compatible with the E4.

With the E4’s still being fairly new I didn’t find prior data on it, so here’s what I cobbled up.

/posts/hoermann-uap-hcp1/images/uap-hcp1-front.jpg
UAP1-HCP front
At first glance a fairly similar conceptual setup as the E3 UAP1:

  • TI MC33063A buck converter to step down the voltage for the IC
  • ST 3485EB RS485 transceiver
  • STM32F030C6T6 microcontroller
  • ON Semiconductor BC846CMTF NPN transistors to connect all the inputs/outputs to the microcontroller
  • OMRON G6RN-1 8A 250V relais to steer the outputs

/posts/hoermann-uap-hcp1/images/uap-hcp1-back.jpg
UAP1-HCP back
The silkscreen on the back has the pinout printed for the 6P6C RJ12 connector, so that was already easy:

  1. GND
  2. unmarked (but also GND when measuring it)
  3. B / RS485 inverting input/output
  4. A / RS485 non-inverting input/output
  5. 24V DC
  6. unmarked (but also 24V when measuring it)

So already a different pinout as the E3, which was:

  1. unmarked / unused?
  2. 24V DC
  3. GND
  4. unmarked / unused?
  5. B / RS485 inverting input/output
  6. A / RS485 non-inverting input/output

I hooked up GND and the RO/RE, DE/DI pins to a logic analyser and started capturing. Initially without much luck, the led on the board blinked for a second without any sign of life afterwards (great .. thought I already fried the board somehow at the time ;-)). But when going through the manual it appears you have to initiate a device scan which will power the bus during the discovery run, if no slave device was found the bus is powered down again. On a supramatic E4 this discovery can be initiated via menu 37, option 01.

Greeted with already a burst of data we see a discovery run which takes about ~13 seconds, where the UAP1-HCP responded once; And afterwards a reply on every second payload from the motor.

/posts/hoermann-uap-hcp1/images/discovery-start.png
UAP1 discovery start

Closer inspection on the first message revealed a baud rate of 57600

/posts/hoermann-uap-hcp1/images/baud-rate.png
UAP1 baud rate

Then it was a matter of seeing what serial flavour it was, default of 8 data bits / no stop bits / no parity revealed framing errors on some packets, so I tried 8 data bits / no stop bits / even parity which seemed OK.

/posts/hoermann-uap-hcp1/images/discovery-first-message.png
UAP1 discovery first message

The motor seems to go through an entire range starting with 0x00 (0) all the way up to 0xF3 (243), every message 19 bytes long. Where the UAP responded on the message starting with 0x02, responding with a message of 15 bytes long.

query: 0x02 0x17 0x9C 0xB9 0x00 0x05 0x9C 0x41 0x00 0x03 0x06 0x00 0x02 0x21 0x0E 0x01 0x02 0x93 0xCA

response: 0x02 0x17 0x0A 0x00 0x00 0x02 0x05 0x04 0x30 0x10 0x00 0x00 0x00 0x80 0xDC

Since it was RS485 with 8E1, which is common for modbus, I tried the modbus decoder once:

/posts/hoermann-uap-hcp1/images/modbus.png
modbus?
Although it seems to partially decode as a modbus payload, it didn’t seem to me that it was “just” modbus.

after the scan was completed the motor sends 2 alternating payloads:

  • a 27 byte payload starting by 0x00
  • a 17 byte payload starting by 0x02, where ~4ms later the UAP replies with a 21 byte payload starting equally with 0x02

The initial discovery was performed a few times to see if there was any difference in sent/received payloads, but it was always identical, so that didn’t need much further investigation. I then captured about 90 seconds worth of data, where I didn’t trigger any actions on the motor to establish a baseline. Armed with this data I exported it in hex format to a CSV file for some post-processing with python. I started by splitting the messages based on idle time between subsequent bytes as delimiter; and started printing them back to the console to see what patterns would be visible

--> 00 10 9D 31 00 09 12 11 00 00 00 40 60 08 00 00 00 00 00 00 14 00 01 00 00 11 E8
--> 02 17 9C B9 00 08 9C 41 00 02 04 02 03 00 00 E7 9C
<-- 02 17 10 02 00 03 01 00 00 00 00 00 00 00 00 00 00 00 00 65 0A
--> 00 10 9D 31 00 09 12 12 00 00 00 40 60 08 00 00 00 00 00 00 14 00 01 00 00 E1 AC
--> 02 17 9C B9 00 08 9C 41 00 02 04 03 03 00 00 E6 60
<-- 02 17 10 03 00 03 01 00 00 00 00 00 00 00 00 00 00 00 00 A4 9A
--> 00 10 9D 31 00 09 12 13 00 00 00 40 60 08 00 00 00 00 00 00 14 00 01 00 00 B0 50
--> 02 17 9C B9 00 08 9C 41 00 02 04 04 03 00 00 E7 14
<-- 02 17 10 04 00 03 01 00 00 00 00 00 00 00 00 00 00 00 00 E6 A8

on the 0x00 messages the varying bytes were:

  • byte 8, which incremented by 1 at every exchange, a counter?
  • byte 26 and 27, without visible pattern, a checksum?

on the 0x02 messages from motor:

  • byte 12, which incremented by 1 at every exchange, a counter?
  • byte 16 and 17, without visible pattern, a checksum?

on the 0x2 messages from UAP1:

  • byte 3, which incremented by 1 at every exchange, a counter?
  • byte 20 and 21, without visible pattern, a checksum?

I started with the last 2 bytes, to see if that could be a checksum which could be expected at the end of a message. A few lines were fed to an On-line CRC calculator, which revealed it to be CRC-16 modbus. I integrated the modbus crc-16 function in the same script to see if it would match on all messages, which it did, so far so good!

Other patterns visible:

  • no correlation between the counter in the 0x00 payloads and the 0x02 payloads
  • the counter in the 0x02 messages from the motor at byte 12 is the same one as in the 0x02 message from UAP1 on byte 3

Then I began going sequentially through the various inputs on the UAP1 to see what data got exchanged

--> 00 10 9D 31 00 09 12 63 00 00 00 40 60 08 00 00 00 00 00 00 14 00 01 00 00 AA 8B
--> 02 17 9C B9 00 08 9C 41 00 02 04 23 03 00 00 ED A0
<-- 02 17 10 23 00 03 01 01 10 00 00 00 00 00 00 00 00 00 00 14 41
               --- byte 9 changed to 01
               --- byte 10 changed to 10
--> 00 10 9D 31 00 09 12 64 00 00 00 40 60 08 00 00 00 00 00 00 14 00 01 00 00 1B FE
--> 02 17 9C B9 00 08 9C 41 00 02 04 24 03 00 00 EC D4
<-- 02 17 10 24 00 03 01 00 00 00 00 00 00 00 00 00 00 00 00 FF 70
--> 00 10 9D 31 00 09 12 65 00 00 00 40 60 08 00 00 00 00 00 00 14 00 01 00 00 4A 02
--> 02 17 9C B9 00 08 9C 41 00 02 04 25 03 00 00 ED 28
<-- 02 17 10 25 00 03 01 00 00 00 00 00 00 00 00 00 00 00 00 3E E0
--> 00 10 9D 31 00 09 12 66 00 00 00 40 60 08 00 00 00 00 00 00 14 00 01 00 00 BA 46
--> 02 17 9C B9 00 08 9C 41 00 02 04 26 03 00 00 ED 6C
<-- 02 17 10 26 00 03 01 00 00 00 00 00 00 00 00 00 00 00 00 7E 11
--> 00 10 9D 31 00 09 12 67 00 00 00 40 60 08 00 00 00 00 00 00 14 00 01 00 00 EB BA
--> 02 17 9C B9 00 08 9C 41 00 02 04 27 03 00 00 EC 90
<-- 02 17 10 27 00 03 01 00 00 00 00 00 00 00 00 00 00 00 00 BF 81
--> 00 10 9D 31 00 09 12 68 00 00 00 40 60 08 00 00 00 00 00 00 14 00 01 00 00 D8 AD
--> 02 17 9C B9 00 08 9C 41 00 02 04 28 03 00 00 EF 84
<-- 02 17 10 28 00 03 01 02 10 00 00 00 00 00 00 00 00 00 00 57 72
               --- byte 9 changed to 02
               --- byte 10 changed to 10
--> 00 10 9D 31 00 09 12 69 00 C8 00 01 60 08 00 00 00 00 00 00 14 00 01 00 00 9F 86
               --- byte 10 changed to C8
               --- byte 12 changed to 01
.... once the gate was completely open
--> 00 10 9D 31 00 09 12 19 00 C8 C8 20 60 08 00 00 00 00 00 00 14 00 01 00 00 6C 2A
               --- byte 11 changed to C8
               --- byte 12 changed to 20

So the 0x02 messages seem to be the command queries, since that’s what the UAP1 used to sent the signals. Here for open it altered bytes 9 and 10 for a single transmission. But to my surprise it triggered another change 4 “iterations” further on the same bytes, whereafter on the 0x00 messages byte changes started to appear. In total 4 bytes were changed.

I repeated the same workflow for all other commands. The “downtime” between 2 command responses varied, which led me to believe it was dependent on how long I actually triggered the input pin.

0x02 replies from UAP1, bytes 9 -> 11 written in compact format:

  • OPEN: 011000; followed by 021000
  • CLOSE: 012000; followed by 022000
  • STOP: 024000; followed by 014000
  • VENTING: 010040; followed by 020040
  • HALF OPEN: 010004; followed by 020004
  • TOGGLE LIGHT: 080002; followed by 100002

0x00 messages from motor, byte 12:

  • STOPPED: 00
  • OPENING: 01
  • CLOSING: 02
  • VENTING: 0A
  • OPEN: 20
  • CLOSED: 40
  • HALF OPENED: 80

bytes 10 and 11 also seem to be some sort of requested vs target states at first glance, but for the ventilation mode byte 11 kept decreasing. I didn’t wait yet till it reached 0, but is the ventilation mode perhaps on a timer? So almost all commands have an equal status response from the motor, apart from toggling the light (but that was also the case on the E3 actually).

Every so often there is a different payload sent by the motor, it doesn’t seem to follow any pattern. And apart from a counter the response from the UAP1 was always identical.

--> 02 17 9C B9 00 02 9C 41 00 02 04 4E 04 17 00 6F 1D
<-- 02 17 04 4E 00 04 FD 1E 4E
--> 02 17 9C B9 00 02 9C 41 00 02 04 6F 04 17 00 65 21
<-- 02 17 04 6F 00 04 FD 14 72
--> 02 17 9C B9 00 02 9C 41 00 02 04 2D 04 17 01 B0 99
<-- 02 17 04 2D 00 04 FD 00 0A

There is a counter on byte 12 in the message sent from the motor, which gets returned on byte 4 on the UAP1 response. The last 2 bytes follow the same CRC-16 modbus calculation as a checksum. The 15th byte in the message from the motor was either 00 or 01, but I wasn’t able to deduce yet what it would signify.

With the above data I started implementing it in code. Some useful tips if you want to do it as well:

  • at least on a SupraMatic E4 it seems that second “inverted” command reply from the UAP1 is not needed, the motor responds already with the first command alone, even if you keep doing it in a loop. So I left out the second part. I didn’t try it yet on a ProMatic E4 to see if that one might need it.
  • if you don’t respond to a command from the motor it goes into 07 error mode

And this is where it all led to. PCB’s got produced and the above protocol got implemented in C

/posts/hoermann-uap-hcp1/images/finished_pcbs.jpg
Finished PCB’s

In the end it’s the same PCB’s as used for the E3 motor for the moment, but with a different pinout on the RJ12 cables (and different code running on the uC’s) The code is split over 2 different uC’s since communication timing with the motor is very delicate and other tasks/interrupts on the same uC tend to disrupt this. The ESP32 runs homekit natively via the espressif SDK.

A new “dedicated” E4 PCB is in the making together with some other things I wanted to have changed on the current version.

It fits nicely in the cable compartiment of the motor

/posts/hoermann-uap-hcp1/images/pcb_in_motor.jpg
PCB attached to motor

I can share the raw traces as well if anyone would be interested