Skip to content

Commit

Permalink
Allow other lengths, fix checksum
Browse files Browse the repository at this point in the history
  • Loading branch information
zuckschwerdt committed Dec 28, 2024
1 parent 176d63a commit 452627f
Showing 1 changed file with 55 additions and 37 deletions.
92 changes: 55 additions & 37 deletions src/devices/revolt_zx7717.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ Raw data:
2ab0abe05a15603ae2c0e710ca20bb
2ab0abe05a15603a1ac0e710c12078
2ab0abe05a15603a7d007b104f00c7
2a88abe05a950026b880603af5c05710d9a018
2a48abe05a950026b880e000000040000000003e
2ab0abe05a15603a6ec0b7103f20dd
2a70abe05a05e08000001c80000000a4
Example messages:
Expand All @@ -53,12 +57,16 @@ Example messages:
0d d507 5aa8 06 5c 4703 e708 5304 dd
0d d507 5aa8 06 5c 5803 e708 8304 1e
0d d507 5aa8 06 5c be00 de08 f200 e3
11 d507 5aa9 00 64 1d01 065c af03 ea08 9b05 18
12 d507 5aa9 00 64 1d01 0700 0000 0200 0000 00 7c
0d d507 5aa8 06 5c 7603 ed08 fc04 bb
0e d507 5aa0 07 01 0000 3801 0000 00 25
Data layout:
LL IIII UUUU CC FF AAAA VVVV WWWW XX
- L: (8 bit) 0d : payload_length (13)
- L: (8 bit) 0d : payload_length (13), excluding the length byte, including checksum
- I: (16 bit) d507 : id
- U: (16 bit) 5aa8 : unknown1
- C: (8 bit) 06 : channel (6) // TODO
Expand All @@ -76,61 +84,71 @@ static int revolt_zx7717_decode(r_device *decoder, bitbuffer_t *bitbuffer)
if (bitbuffer->num_rows != 1) {
return DECODE_ABORT_EARLY;
}
// message length seen are 0d, 0e, 11, 12, i.e. 13, 14, 17, 18 plus sync and length byte
unsigned row_len = bitbuffer->bits_per_row[0];
if (row_len < 120 || row_len > 120) {
if (row_len < 15 * 8 || row_len > 31*8) {
return DECODE_ABORT_EARLY; // Unrecognized data
}

unsigned pos = bitbuffer_search(bitbuffer, 0, 0, preamble, 8);
pos += 8; // skip preamble

if (pos > 16) { // FIXME: needs better checks
return DECODE_ABORT_LENGTH; // short buffer or preamble not found
if (pos > 16) { // match only near the start
return DECODE_ABORT_LENGTH; // preamble not found
}
unsigned len = bitbuffer->bits_per_row[0] - pos;
int len = bitbuffer->bits_per_row[0] - pos;

// There are different length messages
// This handles the 14 bytes (112 bits) message only
if (len < 112) {
return DECODE_ABORT_LENGTH; // short buffer
}
len = 112; // FIXME: cuts the last pulse

uint8_t b[42];
uint8_t b[32];
bitbuffer_extract_bytes(bitbuffer, 0, pos, b, len);
reflect_bytes(b, (len + 7) / 8);

int sum = add_bytes(b, 12);
if (b[13] != (sum & 0xff)) {
int msg_len = b[0]; // expected: 0d, 0e, 11, 12, 1b?
if (msg_len < 1) {
return DECODE_FAIL_SANITY;
}

// Is there enough data for a given length of message?
if (len < (msg_len + 1) * 8) {
return DECODE_ABORT_LENGTH; // short buffer
}

int sum = add_bytes(b, msg_len);
if (b[msg_len] != (sum & 0xff)) {
return DECODE_FAIL_MIC; // bad checksum
}

decoder_log_bitrow(decoder, 1, __func__, b, len, "message");
if (msg_len != 13) {
decoder_log_bitrow(decoder, 1, __func__, b, len, "unhandled message");
return DECODE_FAIL_OTHER; // unhandled message
}

decoder_log_bitrow(decoder, 2, __func__, b, len, "message");

int id = (b[1] << 8) | (b[2]); // Big Endian?
int unknown1 = (b[3] << 8) | b[4]; // Big Endian?
int unknown2 = (b[5] << 8) | b[6]; // Big Endian?
int channel = (b[5]); // not sure yet
int channel = (b[5]); // just a guess
int current = (b[8] << 8) | b[7]; // Little Endian
int voltage = (b[10] << 8) | b[9]; // Little Endian
int power = (b[12] << 8) | b[11]; // Little Endian
// calculation for PF (Powerfactor) is invalid if current is < 0.02 A
// e.g. a standby device will show bad readings
double va = current * voltage * 0.001;
double powerf = va > 1.0 ? power / va : 1.0;
double va = current * voltage * 0.001; // computed value
double powerf = va > 1.0 ? power / va : 1.0; // computed value

/* clang-format off */
data_t *data = data_make(
"model", "", DATA_STRING, "Revolt-ZX7717",
"id", "Device ID", DATA_FORMAT, "%04x", DATA_INT, id,
"channel", "Channel", DATA_INT, channel,
"unknown", "UnknownB3", DATA_FORMAT, "%04x", DATA_INT, unknown1,
"unknown", "UnknownB5", DATA_FORMAT, "%04x", DATA_INT, unknown2,
"current_A", "Current", DATA_FORMAT, "%.3f A", DATA_DOUBLE, current * 0.001,
"voltage_V", "Voltage", DATA_FORMAT, "%.1f V", DATA_DOUBLE, voltage * 0.1,
"power_W", "Power", DATA_FORMAT, "%.1f W", DATA_DOUBLE, power * 0.1,
"pf", "PF(calc)", DATA_DOUBLE, powerf,
"mic", "Integrity", DATA_STRING, "CHECKSUM",
"model", "", DATA_STRING, "Revolt-ZX7717",
"id", "Device ID", DATA_FORMAT, "%04x", DATA_INT, id,
"channel", "Channel", DATA_INT, channel,
"unknown_1", "Unknown 1", DATA_FORMAT, "%04x", DATA_INT, unknown1,
"unknown_2", "Unknown 2", DATA_FORMAT, "%04x", DATA_INT, unknown2,
"current_A", "Current", DATA_FORMAT, "%.3f A", DATA_DOUBLE, current * 0.001,
"voltage_V", "Voltage", DATA_FORMAT, "%.1f V", DATA_DOUBLE, voltage * 0.1,
"power_W", "Power", DATA_FORMAT, "%.1f W", DATA_DOUBLE, power * 0.1,
"apparentpower_VA", "Apparent Power", DATA_FORMAT, "%.1f VA", DATA_DOUBLE, va * 0.1, // computed value
"powerfactor", "Power Factor", DATA_DOUBLE, powerf, // computed value
"mic", "Integrity", DATA_STRING, "CHECKSUM",
NULL);
/* clang-format on */

Expand All @@ -142,21 +160,21 @@ static char const *const output_fields[] = {
"model",
"id",
"channel",
"unknown1",
"unknown2",
"current",
"voltage",
"power",
"pf",
"code",
"unknown_1",
"unknown_2",
"current_A",
"voltage_V",
"power_W", // computed value
"apparentpower_VA", // computed value
"powerfactor",
"mic",
NULL,
};

r_device const revolt_zx7717 = {
.name = "Revolt ZX-7717 power meter",
.modulation = OOK_PULSE_MANCHESTER_ZEROBIT,
.short_width = 310, // Nominal width of clok half period [us]
.short_width = 310, // Nominal width of clock half period [us]
.long_width = 310,
.reset_limit = 900, // Maximum gap size before End Of Message [us]
.decode_fn = &revolt_zx7717_decode,
Expand Down

0 comments on commit 452627f

Please sign in to comment.