rtl_433/src/devices/ecowitt.c
obones 88ae8f8473
Change literals to string const for strict discarded-qualifiers warnings ()
- Change hard coded strings are "const" so any variable pointing to them must also have the const specifier to avoid a warning (from -Wdiscarded-qualifiers)
- Change local variables manipulating constant strings must also have the const qualifier
- Change hostport_param, fix remaining hostport_param args

Co-authored-by: Christian W. Zuckschwerdt <christian@zuckschwerdt.org>
2023-02-15 22:12:18 +01:00

128 lines
4.1 KiB
C

/** @file
Ecowitt Wireless Outdoor Thermometer WH53/WH0280/WH0281A.
Copyright 2019 Google LLC.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
*/
/**
Ecowitt Wireless Outdoor Thermometer WH53/WH0280/WH0281A.
55-bit one-row data packet format (inclusive ranges, 0-indexed):
| 0-6 | 7-bit header, ignored for checksum, always 1111111
| 7-14 | Model code, 0x53
| 15-22 | Sensor ID, randomly reinitialized on boot
| 23-24 | Always 00
| 25-26 | 2-bit sensor channel, selectable on back of sensor {00=1, 01=2, 10=3}
| 27-28 | Always 00
| 29-38 | 10-bit temperature in tenths of degrees C, starting from -40C. e.g. 0=-40C
| 39-46 | Trailer, always 1111 1111
| 47-54 | CRC-8 checksum poly 0x31 init 0x00 skipping first 7 bits
*/
#include "decoder.h"
static int ecowitt_decode(r_device *decoder, bitbuffer_t *bitbuffer)
{
// All Ecowitt packets have one row.
if (bitbuffer->num_rows != 1) {
return DECODE_ABORT_LENGTH;
}
// All Ecowitt packets have 55 bits.
if (bitbuffer->bits_per_row[0] != 55) {
return DECODE_ABORT_LENGTH;
}
uint8_t *row = bitbuffer->bb[0];
// All Ecowitt packets have the first 7 bits set.
uint8_t first7bits = row[0] >> 1;
if (first7bits != 0x7F) {
return DECODE_ABORT_EARLY;
}
// Byte-align the rest of the message by skipping the first 7 bits.
uint8_t b[6];
bitbuffer_extract_bytes(bitbuffer, /* row= */ 0, /* pos= */ 7, b, sizeof(b) * 8); // Skip first 7 bits
// All Ecowitt packets continue with a fixed header
if (b[0] != 0x53) {
return DECODE_ABORT_EARLY;
}
// Randomly generated at boot time sensor ID.
int sensor_id = b[1];
int channel = b[2] >> 4; // First nybble.
channel++; // Convert 0-indexed wire protocol to 1-indexed channels on the device UI
if (channel > 3) {
return DECODE_FAIL_SANITY; // The switch only has 1-3.
}
// All Ecowitt packets have bits 27 and 28 set to 0
// Perhaps these are just an extra two high bits for temperature?
// The manual though says it only operates to 60C, which about matches 10 bits (1023/10-40C)=62.3C
// Above 60 is pretty hot - let's just check these are always zero.
if ((b[2] & (4 | 8)) != 0) {
return DECODE_ABORT_EARLY;
}
// Temperature is next 10 bits
int temp_raw = ((b[2] & 0x3) << 8) | b[3];
float temp_c = (temp_raw - 400) * 0.1f;
// All Ecowitt observed packets have bits 39-48 set.
if (b[4] != 0xFF) {
return DECODE_ABORT_EARLY;
}
// Compute checksum skipping first 7 bits
uint8_t wire_crc = b[5];
int computed_crc = crc8(
b,
/* nBytes= */ sizeof(b) - 1, // Exclude the CRC byte itself
/* polynomial= */ 0x31,
/* init= */ 0);
if (wire_crc != computed_crc) {
return DECODE_FAIL_MIC;
}
/* clang-format off */
data_t *data = data_make(
"model", "", DATA_STRING, "Ecowitt-WH53",
"id", "Id", DATA_INT, sensor_id,
"channel", "Channel", DATA_INT, channel,
"temperature_C", "Temperature", DATA_FORMAT, "%.01f C", DATA_DOUBLE, temp_c,
"mic", "Integrity", DATA_STRING, "CRC",
NULL);
/* clang-format on */
decoder_output_data(decoder, data);
return 1;
}
static char const *output_fields[] = {
"model",
"id",
"channel",
"temperature_C",
"mic",
NULL,
};
r_device const ecowitt = {
.name = "Ecowitt Wireless Outdoor Thermometer WH53/WH0280/WH0281A",
.modulation = OOK_PULSE_PWM,
.short_width = 500, // 500 us nominal short pulse
.long_width = 1480, // 1480 us nominal long pulse
.gap_limit = 1500, // 960 us nominal fixed gap
.reset_limit = 2000, // 31 ms packet distance (too far apart)
.sync_width = 0,
.decode_fn = &ecowitt_decode,
.fields = output_fields,
};