Vendor protocol reference
Note
This page covers boxes in their factory-default state, speaking the vendor’s own protocol rather than Modbus.
What we sell is Modbus — see that page. This page is for units obtained elsewhere, or when the Modbus page gets no reply.
Port settings
Value |
|
|---|---|
Baud rate |
9600 |
Data · stop · parity |
8 · 1 · none |
Works over |
RS232 and RS485 |
Frame format
Always 7 bytes, both directions.
0 1 2 3 4 5 6
┌────┬──────┬────────┬───────┬────────┬─────┬────┐
│ 01 │ 51 │ folder │ 00 │ volume │ XOR │ 02 │
└────┴──────┴────────┴───────┴────────┴─────┴────┘
│ │ │ │ │ │ │
│ │ │ │ │ │ └── end byte, fixed
│ │ │ │ │ └──────── XOR of bytes 0–4
│ │ │ │ └─────────────── 00–1C, i.e. 0–28
│ │ │ └──────────────────────── unused, send 00
│ │ └───────────────────────────────── 00–FF, i.e. 0–255
│ └────────────────────────────────────────── 51 command · 52 reply
└──────────────────────────────────────────────── start byte, fixed
Important
Folder and volume go in one frame, unlike Modbus which needs two. Shorter and faster.
Warning
🔴 There is no read command. This protocol is write-only. Your program must remember what it set.
After a restart there is no way to know what the box is playing, so send a stop as the first thing your program does, to reach a known state.
XOR
XOR bytes 0 through 4 together.
def xor8(data):
v = 0
for b in data:
v ^= b
return v
def frame(folder, volume):
body = [0x01, 0x51, folder & 0xFF, 0x00, volume & 0xFF]
return bytes(body + [xor8(body), 0x02])
Tip
XOR is much weaker than CRC16 — swap two bytes and the XOR is unchanged, so the error passes undetected.
On long or electrically noisy runs Modbus is more trustworthy. Order the Modbus variant if you have the choice.
Example frames
Generated by code, not typed. The first pair matches the manual byte for byte.
Action |
Send |
Box replies |
|---|---|---|
Play |
|
|
Play |
|
|
Stop |
|
|
🔴 The echo trap
Danger
Command and reply differ by a single byte — 51 versus 52.
Some RS485 wiring echoes what you transmit. Code that only checks “did anything come back?” will treat its own frame as a reply, even with no speaker connected.
Check that byte 1 is 52. If it is 51, that is an echo, not a reply.
def is_real_reply(frame, sent_folder):
if len(frame) != 7:
return False
if frame[1] != 0x52: # 51 is our own command, echoed back
return False
if frame[2] != sent_folder: # must match what we asked for
return False
return frame[5] == xor8(frame[:5])
Check before connecting hardware
Print the frames your code builds and compare them with the table above.
Warning
The wrong protocol gives total silence, with no error. If frames from this page get no reply, try the Modbus page before investigating the wiring.