-
-
Notifications
You must be signed in to change notification settings - Fork 137
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding Inkbird ITH-20R decoder to contrib directory
- Loading branch information
Northern Man
authored and
Northern Man
committed
May 25, 2021
1 parent
ff57e8f
commit 36cc87f
Showing
1 changed file
with
164 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
/** @file | ||
Decoder for Inkbird ITH-20R. | ||
Copyright (C) 2018 Daniel Krueger | ||
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. | ||
*/ | ||
|
||
/** | ||
Decoder for Inkbird ITH-20R. | ||
https://www.ink-bird.com/products-data-logger-ith20r.html | ||
The compact 3-in-1 multifunction outdoor sensor transmits the data on 433.92 MHz. | ||
The device uses FSK-PCM encoding, | ||
The device sends a transmission every ~20 sec. | ||
Decoding borrowed from https://groups.google.com/forum/#!topic/rtl_433/oeExmwoBI0w | ||
Total packet length 14563 bits: | ||
Preamble: aa aa aa ... aa aa (14400 on-off sync bits) | ||
Sync Word (16 bits): 2DD4 | ||
Data (147 bits): | ||
Byte Sample Comment | ||
0-2 D3910F Always the same across devices, a device type? | ||
3 00 00 - normal work , 40 - unlink sensor (button pressed 5s), 80 - battery replaced | ||
4 01 Changes from 1 to 2 if external sensor present | ||
5-6 0301 Unknown (also seen 0201), sw version? | ||
7 58 Battery % 0-100 | ||
8-9 A221 Device id, always the same for a sensor but each sensor is different | ||
10-11 D600 Temperature in °C * 10, little endian, so 0xD200 is 210, 21.0°C or 69.8°F | ||
12-13 F400 Temperature °C * 10 for the external sensor, 0x1405 if not connected | ||
14-15 D301 Relative humidity % * 10, little endian, so 0xC501 is 453 or 45.3% | ||
16-17 38FB CRC16 | ||
18 0 Unknown 3 bits (seen 0 and 2) | ||
CRC16 (bytes 0-15), without sync word): | ||
poly=0x8005 init=0x2f61 refin=true refout=true xorout=0x0000 check=0x3583 residue=0x0000 | ||
To look at unknown data fields run with -vv key. | ||
Decoder written by Dmitriy Kozyrev, 2020 | ||
*/ | ||
|
||
#include "decoder.h" | ||
|
||
static const uint8_t preamble_pattern[] = { 0xaa, 0xaa, 0xaa, 0x2d, 0xd4 }; | ||
|
||
#define INKBIRD_ITH20R_CRC_POLY 0xA001 // reflected 0x8005 | ||
#define INKBIRD_ITH20R_CRC_INIT 0x86F4 // reflected 0x2f61 | ||
|
||
|
||
static int inkbird_ith20r_callback(r_device *decoder, bitbuffer_t *bitbuffer) | ||
{ | ||
data_t *data; | ||
uint8_t msg[19]; | ||
|
||
if ( (bitbuffer->num_rows != 1) | ||
|| (bitbuffer->bits_per_row[0] < 187) | ||
/*|| (bitbuffer->bits_per_row[0] > 14563)*/ ) { | ||
if (decoder->verbose > 1) { | ||
fprintf(stderr, "%s bit_per_row %u out of range\n", __func__, bitbuffer->bits_per_row[0]); | ||
} | ||
return DECODE_ABORT_LENGTH; // Unrecognized data | ||
} | ||
|
||
unsigned start_pos = bitbuffer_search(bitbuffer, 0, 0, | ||
preamble_pattern, sizeof (preamble_pattern) * 8); | ||
|
||
if (start_pos == bitbuffer->bits_per_row[0]) { | ||
return DECODE_FAIL_SANITY; // Not found preamble | ||
} | ||
|
||
start_pos += sizeof (preamble_pattern) * 8; | ||
unsigned len = bitbuffer->bits_per_row[0] - start_pos; | ||
|
||
if (decoder->verbose > 1) { | ||
fprintf(stderr, "%s start_pos=%u\n", __func__, start_pos); | ||
fprintf(stderr, "%s len=%u\n", __func__, len); | ||
} | ||
|
||
if (((len + 7) / 8) < sizeof (msg)) { | ||
if (decoder->verbose) { | ||
fprintf(stderr, "%s %u too short\n", __func__, len); | ||
} | ||
return DECODE_ABORT_LENGTH; // Message too short | ||
} | ||
// truncate any excessive bits | ||
len = MIN(len, sizeof (msg) * 8); | ||
|
||
bitbuffer_extract_bytes(bitbuffer, 0, start_pos, msg, len); | ||
|
||
// CRC check | ||
uint16_t crc_calculated = crc16lsb(msg, 16, INKBIRD_ITH20R_CRC_POLY, INKBIRD_ITH20R_CRC_INIT); | ||
uint16_t crc_received = msg[17] << 8 | msg[16]; | ||
|
||
if (decoder->verbose > 1) { | ||
fprintf(stderr, "%s CRC 0x%04X = 0x%04X\n", __func__, crc_calculated, crc_received); | ||
} | ||
|
||
if (crc_received != crc_calculated) { | ||
if (decoder->verbose) { | ||
fprintf(stderr, "%s CRC check failed (0x%04X != 0x%04X)\n", __func__, crc_calculated, crc_received); | ||
} | ||
return DECODE_FAIL_MIC; | ||
} | ||
|
||
uint32_t subtype = (msg[3] << 24 | msg[2] << 16 | msg[1] << 8 | msg[0]); | ||
int sensor_num = msg[4]; | ||
uint16_t word56 = (msg[6] << 8 | msg[5]); | ||
int battery = msg[7]; | ||
uint16_t sensor_id = (msg[9] << 8 | msg[8]); | ||
float temperature = (float)((int16_t)(msg[11] << 8 | msg[10])) / 10.0; | ||
float temperature_ext = (float)((int16_t)(msg[13] << 8 | msg[12])) / 10.0; | ||
float humidity = (float)(msg[15] << 8 | msg[14]) / 10.0; | ||
uint8_t word18 = msg[18]; | ||
|
||
if (decoder->verbose) { | ||
fprintf(stderr, "%s dword0-3= 0x%08X\n", __func__, subtype); | ||
fprintf(stderr, "%s word5-6= 0x%04X\n", __func__, word56); | ||
fprintf(stderr, "%s byte18= 0x%02X\n", __func__, word18); | ||
} | ||
|
||
data = data_make( | ||
"model", "", DATA_STRING, "Inkbird ITH-20R", | ||
"id", "", DATA_INT, sensor_id, | ||
"battery", "Battery", DATA_INT, battery, | ||
"sensor_num", "", DATA_INT, sensor_num, | ||
"mic", "Integrity", DATA_STRING, "CRC", | ||
"temperature_C", "Temperature", DATA_FORMAT, "%.1f C", DATA_DOUBLE, temperature, | ||
"temperature2_C", "Temperature2", DATA_FORMAT, "%.1f C", DATA_DOUBLE, temperature_ext, | ||
"humidity", "Humidity", DATA_FORMAT, "%.1f %%", DATA_DOUBLE, humidity, | ||
NULL); | ||
|
||
decoder_output_data(decoder, data); | ||
|
||
return 1; | ||
} | ||
|
||
static char *output_fields[] = { | ||
"model", | ||
"id", | ||
"battery", | ||
"sensor_num", | ||
"mic", | ||
"temperature_C", | ||
"temperature2_C", | ||
"humidity", | ||
NULL | ||
}; | ||
|
||
r_device inkbird_ith20r = { | ||
.name = "Inkbird ITH-20R temperature humidity sensor", | ||
.modulation = FSK_PULSE_PCM, | ||
.sync_width = 0, // No sync bit used | ||
.short_width = 100, // Width of a '0' gap | ||
.long_width = 100, // Width of a '1' gap | ||
.reset_limit = 4000, // Maximum gap size before End Of Message [us] | ||
.decode_fn = &inkbird_ith20r_callback, | ||
.disabled = 0, | ||
.fields = output_fields, | ||
}; |