Fix off-by-one bug in RTW protocol decoder.

The RTW decoder formula encKey - 133 was off by one versus the
RTW encoder (which maps command N to encKey N + 132). This caused
every non-My RTW command to decode as the wrong button (e.g. Up
decoded as My, Down as MyUp). Also adds rawCmd diagnostic field to
received frames for protocol debugging.
This commit is contained in:
cjkas 2026-04-19 11:07:53 +02:00
parent e82417475b
commit 26400c534f
5 changed files with 18 additions and 4 deletions

View file

@ -992,7 +992,7 @@
</div>
</div>
<div id="divFrameLog" class="subtab-content frame-log" style="display:none;margin:0px;padding:0px;">
<div class="frame-header"><span>Key</span><span>Address</span><span>Command</span><span>Code</span><span>RSSI</span><span>Bits</span><span style="text-align:center;width:77px;">Time</span></div>
<div class="frame-header"><span>Key</span><span>Address</span><span>Command</span><span>Code</span><span>RSSI</span><span>Bits</span><span style="text-align:center;width:77px;">Time</span><span>Raw</span></div>
<div id="divFrames" class="frame-list"></div>
<div class="button-container" style="text-align:center">
<button type="button" class="btnCopyFrame" style="display:inline-block;width:44%;" onclick="somfy.framesToClipboard();">Copy</button>

View file

@ -2934,7 +2934,8 @@ class Somfy {
proto = '-V';
break;
}
let html = `<span>${frame.encKey}</span><span>${frame.address}</span><span>${frame.command}<sup>${frame.stepSize ? frame.stepSize : ''}</sup></span><span>${frame.rcode}</span><span>${frame.rssi}dBm</span><span>${frame.bits}${proto}</span><span>${fnFmtTime(frame.time)}</span><div class="frame-pulses">`;
let rawCmdHex = (typeof frame.rawCmd === 'number') ? `0x${frame.rawCmd.toString(16).toUpperCase()}` : '';
let html = `<span>${frame.encKey}</span><span>${frame.address}</span><span>${frame.command}<sup>${frame.stepSize ? frame.stepSize : ''}</sup></span><span>${frame.rcode}</span><span>${frame.rssi}dBm</span><span>${frame.bits}${proto}</span><span>${fnFmtTime(frame.time)}</span><span>${rawCmdHex}</span><div class="frame-pulses">`;
for (let i = 0; i < frame.pulses.length; i++) {
if (i !== 0) html += ',';
html += `${frame.pulses[i]}`;

View file

@ -832,6 +832,11 @@ div.frame-header > span {
text-align: right;
white-space:nowrap;
}
div.frame-row > span:nth-child(8),
div.frame-header > span:nth-child(8) {
width: 40px;
text-align: center;
}
div.frame-list > div:nth-child(2n+1) {
background: beige;

View file

@ -153,7 +153,8 @@ void somfy_frame_t::decodeFrame(byte* frame) {
this->checksum = decoded[1] & 0b1111;
this->encKey = decoded[0];
// Lets first determine the protocol.
this->cmd = (somfy_commands)((decoded[1] >> 4));
this->rawCmd = decoded[1] >> 4;
this->cmd = (somfy_commands)(this->rawCmd);
if(this->cmd == somfy_commands::RTWProto) {
if(this->encKey >= 160) {
this->proto = radio_proto::RTS;
@ -165,7 +166,7 @@ void somfy_frame_t::decodeFrame(byte* frame) {
}
else if(this->encKey >= 133) {
this->proto = radio_proto::RTW;
this->cmd = this->encKey == 133 ? somfy_commands::My : (somfy_commands)(this->encKey - 133);
this->cmd = (somfy_commands)(this->encKey - 132);
}
}
else this->proto = radio_proto::RTS;
@ -4418,6 +4419,11 @@ bool Transceiver::receive(somfy_rx_t *rx) {
//Serial.printf("Processing receive %d\n", rx_queue.length);
rx_queue.pop(rx);
this->frame.decodeFrame(rx);
if(this->frame.valid) {
ESP_LOGI(TAG, "RX ADDR:%d CMD:%s RAW_CMD:0x%X KEY:0x%02X PROTO:%u",
this->frame.remoteAddress, translateSomfyCommand(this->frame.cmd).c_str(),
this->frame.rawCmd, this->frame.encKey, (uint8_t)this->frame.proto);
}
this->emitFrame(&this->frame, rx);
return this->frame.valid;
}
@ -4431,6 +4437,7 @@ void Transceiver::emitFrame(somfy_frame_t *frame, somfy_rx_t *rx) {
json->addElem("address", (uint32_t)frame->remoteAddress);
json->addElem("rcode", (uint32_t)frame->rollingCode);
json->addElem("command", translateSomfyCommand(frame->cmd).c_str());
json->addElem("rawCmd", frame->rawCmd);
json->addElem("rssi", (int32_t)frame->rssi);
json->addElem("bits", rx->bit_length);
json->addElem("proto", static_cast<uint8_t>(frame->proto));

View file

@ -189,6 +189,7 @@ struct somfy_frame_t {
uint8_t bitLength = 56;
uint16_t pulseCount = 0;
uint8_t stepSize = 0;
uint8_t rawCmd = 0;
void print();
void encode80BitFrame(byte *frame, uint8_t repeat);
byte calc80Checksum(byte b0, byte b1, byte b2);