Add support for Ecowitt temperature sensor
This commit is contained in:
parent
2dc9eb216e
commit
f199d35d8e
8 changed files with 133 additions and 3 deletions
|
@ -312,6 +312,7 @@ stop_after_successful_events false
|
|||
protocol 124 # LaCrosse/ELV/Conrad WS7000/WS2500 weather sensors
|
||||
protocol 125 # TS-FT002 Wireless Ultrasonic Tank Liquid Level Meter With Temperature Sensor
|
||||
protocol 126 # Companion WTR001 Temperature Sensor
|
||||
protocol 127 # Ecowitt Wireless Outdoor Thermometer WH53/WH0280/WH0281A
|
||||
|
||||
## Flex devices (command line option "-X")
|
||||
|
||||
|
|
|
@ -21,13 +21,16 @@ enum modulation_types {
|
|||
FSK_PULSE_MANCHESTER_ZEROBIT = 18, ///< FSK, Manchester encoding.
|
||||
};
|
||||
|
||||
/** Decoders should return n>=0 for n packets successfully decoded,
|
||||
/** Decoders should return n>0 for n packets successfully decoded,
|
||||
an ABORT code if the bitbuffer is no applicable,
|
||||
or a FAIL code if the message is malformed. */
|
||||
enum decode_return_codes {
|
||||
DECODE_SUCCESS = 1,
|
||||
DECODE_FAIL_OTHER = 0, ///< legacy, do not use
|
||||
/** Bitbuffer row count or row length is wrong for this sensor. */
|
||||
DECODE_ABORT_LENGTH = -1,
|
||||
DECODE_ABORT_EARLY = -2,
|
||||
/** Message Integrity Check failed: e.g. checksum/CRC doesn't validate. */
|
||||
DECODE_FAIL_MIC = -3,
|
||||
DECODE_FAIL_SANITY = -4,
|
||||
};
|
||||
|
|
|
@ -134,6 +134,7 @@
|
|||
DECL(lacrosse_ws7000) \
|
||||
DECL(ts_ft002) \
|
||||
DECL(companion_wtr001) \
|
||||
DECL(ecowitt) \
|
||||
/* Add new decoders here. */
|
||||
|
||||
#define DECL(name) extern r_device name;
|
||||
|
|
|
@ -45,6 +45,7 @@ add_executable(rtl_433
|
|||
devices/digitech_xc0324.c
|
||||
devices/dish_remote_6_3.c
|
||||
devices/dsc.c
|
||||
devices/ecowitt.c
|
||||
devices/efergy_e2_classic.c
|
||||
devices/efergy_optical.c
|
||||
devices/elro_db286a.c
|
||||
|
|
|
@ -46,6 +46,7 @@ rtl_433_SOURCES = abuf.c \
|
|||
devices/digitech_xc0324.c \
|
||||
devices/dish_remote_6_3.c \
|
||||
devices/dsc.c \
|
||||
devices/ecowitt.c \
|
||||
devices/efergy_e2_classic.c \
|
||||
devices/efergy_optical.c \
|
||||
devices/elro_db286a.c \
|
||||
|
|
119
src/devices/ecowitt.c
Normal file
119
src/devices/ecowitt.c
Normal file
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* 55-bit one-row data packet format (inclusive ranges, 0-indexed):
|
||||
* | 0-6 | 7-bit header, ignored for checksum, always 1111111
|
||||
* | 7-14 | Always 01010011
|
||||
* | 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#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 sensorID = 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 < 1 || 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
|
||||
float tempC = -40.0; // Bias
|
||||
tempC += (float) b[3] / 10.0;
|
||||
tempC += (float) ((b[2] & 0x3) << 8) / 10.0;
|
||||
|
||||
// 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 wireCRC = b[5];
|
||||
int computedCRC = crc8(
|
||||
b,
|
||||
/* nBytes= */ sizeof(b)-1, // Exclude the CRC byte itself
|
||||
/* polynomial= */ 0x31,
|
||||
/* init= */ 0);
|
||||
if (wireCRC != computedCRC) {
|
||||
return DECODE_FAIL_MIC;
|
||||
}
|
||||
|
||||
data_t *data = data_make(
|
||||
"model", "", DATA_STRING, "Ecowitt-WH53",
|
||||
"id", "Id", DATA_INT, sensorID,
|
||||
"channel", "Channel", DATA_INT, channel,
|
||||
"temperature_C", "Temperature", DATA_FORMAT, "%.01f C", DATA_DOUBLE, tempC,
|
||||
"mic", "Integrity", DATA_STRING, "CRC",
|
||||
NULL);
|
||||
decoder_output_data(decoder, data);
|
||||
return DECODE_SUCCESS;
|
||||
}
|
||||
|
||||
static char *output_fields[] = {
|
||||
"model",
|
||||
"id",
|
||||
"channel",
|
||||
"temperature_C",
|
||||
"mic",
|
||||
NULL
|
||||
};
|
||||
|
||||
r_device ecowitt = {
|
||||
.name = "Ecowitt Temperature Sensor",
|
||||
.modulation = OOK_PULSE_PWM, // copied from output, OOK_PWM = OOK_PULSE_PWM
|
||||
.short_width = 504, // copied from output
|
||||
.long_width = 1480, // copied from output
|
||||
.gap_limit = 4800, // guessing, copied from generic_temperature_sensor
|
||||
.reset_limit = 968, // copied from output
|
||||
.sync_width = 0, // copied from output
|
||||
.decode_fn = &ecowitt_decode,
|
||||
.disabled = 0,
|
||||
.fields = output_fields,
|
||||
};
|
|
@ -158,6 +158,7 @@
|
|||
<ClCompile Include="..\src\devices\digitech_xc0324.c" />
|
||||
<ClCompile Include="..\src\devices\dish_remote_6_3.c" />
|
||||
<ClCompile Include="..\src\devices\dsc.c" />
|
||||
<ClCompile Include="..\src\devices\ecowitt.c" />
|
||||
<ClCompile Include="..\src\devices\efergy_e2_classic.c" />
|
||||
<ClCompile Include="..\src\devices\efergy_optical.c" />
|
||||
<ClCompile Include="..\src\devices\elro_db286a.c" />
|
||||
|
@ -249,4 +250,4 @@
|
|||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
@ -235,6 +235,9 @@
|
|||
<ClCompile Include="..\src\devices\dsc.c">
|
||||
<Filter>Source Files\devices</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\devices\ecowitt.c">
|
||||
<Filter>Source Files\devices</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\devices\efergy_e2_classic.c">
|
||||
<Filter>Source Files\devices</Filter>
|
||||
</ClCompile>
|
||||
|
@ -494,4 +497,4 @@
|
|||
<Filter>Source Files\devices</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue