X-Git-Url: https://git.rvb.name/rtl-433.git/blobdiff_plain/ca13278b24eb61443559bcb61e64627fba3d8823..6d15c6f967221af825cf84e3ed12b96c763b127b:/src/devices/tfa_twin_plus_30.3049.c diff --git a/src/devices/tfa_twin_plus_30.3049.c b/src/devices/tfa_twin_plus_30.3049.c new file mode 100644 index 0000000..29990ec --- /dev/null +++ b/src/devices/tfa_twin_plus_30.3049.c @@ -0,0 +1,390 @@ +#include "rtl_433.h" +#include "util.h" +#include "data.h" + +/* + * TFA-Twin-Plus-30.3049 + * + * Copyright (C) 2015 Paul Ortyl + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + */ + +/* + * Protocol as reverse engineered by https://github.com/iotzo + * + * 36 Bits (9 nibbles) + * + * Type: IIIICCII B???TTTT TTTTTSSS HHHHHHH1 XXXX + * BIT/8 76543210 76543210 76543210 76543210 7654 + * BIT/A 01234567 89012345 57890123 45678901 2345 + * 0 1 2 3 + * I: sensor ID (changes on battery change) + * C: Channel number + * B: low battery + * T: temperature + * S: sign + * X: checksum + * ?: unknown meaning + * all values are LSB-first, so need to be reversed before presentation + * + * + * [04] {36} e4 4b 70 73 00 : 111001000100 101101110 000 0111001 10000 ---> temp/hum:23.7/50 + * temp num-->13-21bit(9bits) in reverse order in this case "011101101"=237 + * positive temps ( with 000 in bits 22-24) : temp=num/10 (in this case 23.7 C) + * negative temps (with 111 in bits 22-24) : temp=(512-num)/10 + * negative temps example: + * [03] {36} e4 4c 1f 73 f0 : 111001000100 110000011 111 0111001 11111 temp: -12.4 + * + * Humidity: + * hum num-->25-32bit(7bits) in reverse order : in this case "1001110"=78 + * humidity=num-28 --> 78-28=50 + * + * I have channel number bits(5,6 in reverse order) and low battery bit(9) + * It seems that the 1,2,3,4,7,8 bits changes randomly on every reset/battery change. + * + */ + +inline static uint8_t reverse_byte(uint8_t byte) +{ + byte = (byte & 0xF0) >> 4 | (byte & 0x0F) << 4; + byte = (byte & 0xCC) >> 2 | (byte & 0x33) << 2; + byte = (byte & 0xAA) >> 1 | (byte & 0x55) << 1; + return byte; +} + +static int tfa_twin_plus_303049_process_row(int row, const bitbuffer_t *bitbuffer) +{ + data_t *data; + const uint8_t *b = bitbuffer->bb[row]; + const uint16_t length = bitbuffer->bits_per_row[row]; + + if ((36 != length) + || !(b[0] || b[1] || b[2] || b[3] || b[4])) /* exclude all zeros */ + return 0; + + //fprintf(stderr, "TFA-Twin-Plus-30.3049: %02x %02x %02x %02x %02x\n", b[0], b[1], b[2], b[3], b[4]); + // reverse bit order + const uint8_t rb[5] = { reverse_byte(b[0]), reverse_byte(b[1]), reverse_byte(b[2]) + , reverse_byte(b[3]), reverse_byte(b[4]) }; + + const int sum_nibbles = + (rb[0] >> 4) + (rb[0] & 0xF) + + (rb[1] >> 4) + (rb[1] & 0xF) + + (rb[2] >> 4) + (rb[2] & 0xF) + + (rb[3] >> 4) + (rb[3] & 0xF); + + const int checksum = rb[4] & 0x0F; // just make sure the 10th nibble does not contain junk + if (checksum != (sum_nibbles & 0xF)) + return 0; // wrong checksum + + /* IIIICCII B???TTTT TTTTTSSS HHHHHHH1 XXXX */ + const int negative_sign = (b[2] & 7); + const int temp = ((rb[2]&0x1F) << 4) | (rb[1]>> 4); + const int humidity = (rb[3] & 0x7F) - 28; + const int sensor_id = (rb[0] & 0x0F) | ((rb[0] & 0xC0)>>2); + const int battery_low = b[1] >> 7; + const int channel = (b[0]>>2) & 3; + + float tempC = (negative_sign ? -( (1<<9) - temp ) : temp ) * 0.1F; + { + /* @todo: remove timestamp printing as soon as the controller takes this task */ + char time_str[LOCAL_TIME_BUFLEN]; + local_time_str(0, time_str); + + data = data_make("time", "", DATA_STRING, time_str, + "model", "", DATA_STRING, "TFA-Twin-Plus-30.3049", + "id", "", DATA_INT, sensor_id, + "channel", "", DATA_INT, channel, + "battery", "Battery", DATA_STRING, battery_low ? "LOW" : "OK", + "temperature_C", "Temperature", DATA_FORMAT, "%.1f C", DATA_DOUBLE, tempC, + "humidity", "Humidity", DATA_FORMAT, "%u %%", DATA_INT, humidity, + NULL); + data_acquired_handler(data); + } + + return 1; +} + +static int tfa_twin_plus_303049_callback(bitbuffer_t *bitbuffer) +{ + int counter = 0; + for(int row=0; rownum_rows; row++) + counter += tfa_twin_plus_303049_process_row(row, bitbuffer); + return counter; +} + + +// Test code +// gcc -I src/ -I include/ -std=gnu99 -ggdb -D _TEST_DECODER src/devices/tfa_twin_plus_30.3049.c src/util.c +#ifdef _TEST_DECODER +int main() +{ + bitbuffer_t bb; + bb.num_rows = 1; + bb.bits_per_row[0] = 36; + const uint8_t b[75][5] = + { + { 0x00, 0x00, 0x00, 0x00, 0x00}, // this one is excluded despite the correct checksum + { 0xe4, 0x4b, 0x70, 0x73, 0x00}, // temp/hum:23.7/50 + { 0xe4, 0x4c, 0x1f, 0x73, 0xf0}, + { 0xe4, 0x25, 0xc8, 0x87, 0x50}, // 111001000010 010111001 000 1000011 1 0101 + { 0xe4, 0x2e, 0xc8, 0xbb, 0x40}, // 111001000010 111011001 000 1011101 1 0100 + { 0xe4, 0x26, 0xc8, 0x9b, 0xb0}, // 111001000010 011011001 000 1001101 1 1011 + { 0xe4, 0x2a, 0xc8, 0x6b, 0x90}, // 111001000010 101011001 000 0110101 1 1001 + { 0xe4, 0x22, 0xc8, 0xcb, 0xa0}, // 111001000010 001011001 000 1100101 1 1010 + { 0xe4, 0x2c, 0xc8, 0x0b, 0x80}, // 111001000010 110011001 000 0000101 1 1000 + { 0xe4, 0x24, 0xc8, 0xb3, 0x30}, // 111001000010 010011001 000 1011001 1 0011 + { 0xe4, 0x28, 0xc8, 0xd3, 0x90}, // 111001000010 100011001 000 1101001 1 1001 + { 0xe4, 0x4f, 0x48, 0x63, 0xf0}, // 111001000100 111101001 000 0110001 1 1111 + { 0xe4, 0x47, 0x48, 0xa3, 0xb0}, // 111001000100 011101001 000 1010001 1 1011 + { 0xe4, 0x47, 0x48, 0x23, 0x30}, // 111001000100 011101001 000 0010001 1 0011 + { 0xe4, 0x40, 0x50, 0xa3, 0x60}, // 111001000100 000001010 000 1010001 1 0110 + { 0xe4, 0x44, 0xe0, 0x43, 0x40}, // 111001000100 010011100 000 0100001 1 0100 + { 0xe4, 0x4f, 0x20, 0xc3, 0xb0}, // 111001000100 111100100 000 1100001 1 1011 + { 0xe4, 0x42, 0xc0, 0x43, 0x00}, // 111001000100 001011000 000 0100001 1 0000 + { 0xe4, 0x4b, 0x80, 0xc3, 0x10}, // 111001000100 101110000 000 1100001 1 0001 + { 0xe4, 0x4d, 0x00, 0xc3, 0xa0}, // 111001000100 110100000 000 1100001 1 1010 + { 0xe4, 0x4d, 0xff, 0x23, 0x20}, // 111001000100 110111111 111 0010001 1 0010 + { 0xe4, 0x4b, 0x7f, 0x23, 0xa0}, // 111001000100 101101111 111 0010001 1 1010 + { 0xe4, 0x40, 0x7f, 0xa3, 0x90}, // 111001000100 000001111 111 1010001 1 1001 + { 0xe4, 0x4a, 0xbf, 0x93, 0x80}, // 111001000100 101010111 111 1001001 1 1000 + { 0xe4, 0x43, 0x3f, 0xe3, 0xa0}, // 111001000100 001100111 111 1110001 1 1010 + { 0xe4, 0x42, 0x3f, 0xe3, 0xb0}, // 111001000100 001000111 111 1110001 1 1011 + { 0xe4, 0x43, 0xdf, 0x13, 0xa0}, // 111001000100 001111011 111 0001001 1 1010 + { 0xe4, 0x4a, 0xdf, 0x93, 0xf0}, // 111001000100 101011011 111 1001001 1 1111 + { 0xe4, 0x47, 0x5f, 0x93, 0xe0}, // 111001000100 011101011 111 1001001 1 1110 + { 0xe4, 0x41, 0x5f, 0x53, 0x40}, // 111001000100 000101011 111 0101001 1 0100 + { 0xe4, 0x49, 0x9f, 0x33, 0x20}, // 111001000100 100110011 111 0011001 1 0010 + { 0xe4, 0x41, 0x1f, 0xb3, 0xc0}, // 111001000100 000100011 111 1011001 1 1100 + { 0xe4, 0x4c, 0x1f, 0x73, 0xf0}, // 111001000100 110000011 111 0111001 1 1111 + { 0x24, 0x01, 0xf0, 0x13, 0x80}, // 0010 0100 0000 0001 11110000 00010011 1000 CH1 + { 0x84, 0x02, 0x08, 0x83, 0xa0}, // 1000 0100 0000 0010 00001000 10000011 1010 CH1 + { 0x96, 0x02, 0x08, 0x83, 0x80}, // 1001 0110 0000 0010 00001000 10000011 1000 CH1 + { 0xc4, 0x0c, 0x08, 0x83, 0x60}, // 1100 0100 0000 1100 00001000 10000011 0110 CH1 + { 0x46, 0x0c, 0x08, 0x83, 0x90}, // 0100 0110 0000 1100 00001000 10000011 1001 CH1 + { 0x75, 0x0c, 0x08, 0x83, 0x90}, // 0111 0101 0000 1100 00001000 10000011 1001 CH1 + { 0x75, 0x04, 0x08, 0x03, 0xe0}, // 0111 0101 0000 0100 00001000 00000011 1110 CH1 + { 0x96, 0x8e, 0x88, 0xc3, 0x10}, // 1001 0110 1000 1110 10001000 11000011 0001 CH1/LOW BAT + { 0x96, 0x81, 0x88, 0x83, 0xe0}, // 1001 0110 1000 0001 10001000 10000011 1110 CH1/LOW BAT + { 0x96, 0x86, 0x88, 0x83, 0xa0}, // 1001 0110 1000 0110 10001000 10000011 1010 CH1/LOW BAT + { 0xa8, 0x02, 0x48, 0xc3, 0x30}, // 1010 1000 0000 0010 01001000 11000011 0011 CH2 + { 0xa8, 0x40, 0x88, 0x83, 0xe0}, // 1010 1000 0100 0000 10001000 10000011 1110 CH2 + { 0x88, 0x05, 0x08, 0x83, 0x50}, // 1000 1000 0000 0101 00001000 10000011 0101 CH2 + { 0x0b, 0x09, 0x08, 0x43, 0xa0}, // 0000 1011 0000 1001 00001000 01000011 1010 CH2 + { 0x5b, 0x0a, 0x08, 0x83, 0x50}, // 0101 1011 0000 1010 00001000 10000011 0101 CH2 + { 0x7a, 0x0c, 0x08, 0x83, 0x20}, // 0111 1010 0000 1100 00001000 10000011 0010 CH2 + { 0xda, 0x04, 0x08, 0x83, 0x00}, // 1101 1010 0000 0100 00001000 10000011 0000 CH2 + { 0xb8, 0x08, 0x08, 0x83, 0xb0}, // 1011 1000 0000 1000 00001000 10000011 1011 CH2 + { 0xfb, 0x08, 0x08, 0x83, 0xd0}, // 1111 1011 0000 1000 00001000 10000011 1101 CH2 + { 0x68, 0x00, 0x08, 0x83, 0xa0}, // 0110 1000 0000 0000 00001000 10000011 1010 CH2 + { 0xea, 0x00, 0x08, 0x83, 0x50}, // 1110 1010 0000 0000 00001000 10000011 0101 CH2 + { 0x69, 0x00, 0x08, 0x83, 0xb0}, // 0110 1001 0000 0000 00001000 10000011 1011 CH2 + { 0xf8, 0x00, 0x08, 0x83, 0x70}, // 1111 1000 0000 0000 00001000 10000011 0111 CH2 + { 0xe9, 0x0f, 0xf0, 0x83, 0xd0}, // 1110 1001 0000 1111 11110000 10000011 1101 CH2 + { 0x1b, 0x0f, 0xf0, 0x83, 0x00}, // 0001 1011 0000 1111 11110000 10000011 0000 CH2 + { 0x98, 0x0f, 0xf0, 0x83, 0xa0}, // 1001 1000 0000 1111 11110000 10000011 1010 CH2 + { 0x4b, 0x07, 0xf0, 0x83, 0x90}, // 0100 1011 0000 0111 11110000 10000011 1001 CH2 + { 0xca, 0x07, 0xf0, 0x83, 0x40}, // 1100 1010 0000 0111 11110000 10000011 0100 CH2 + { 0x8b, 0x07, 0xf0, 0x83, 0x10}, // 1000 1011 0000 0111 11110000 10000011 0001 CH2 + { 0xda, 0x07, 0xf0, 0x83, 0x50}, // 1101 1010 0000 0111 11110000 10000011 0101 CH2 + { 0x29, 0x07, 0xf0, 0x83, 0xe0}, // 0010 1001 0000 0111 11110000 10000011 1110 CH2 + { 0x8b, 0x00, 0x08, 0x43, 0xb0}, // 1000 1011 0000 0000 00001000 01000011 1011 CH2 + { 0x2b, 0x0f, 0xf0, 0x83, 0x30}, // 0010 1011 0000 1111 11110000 10000011 0011 CH2 + { 0x59, 0x07, 0xf0, 0x83, 0xb0}, // 0101 1001 0000 0111 11110000 10000011 1011 CH2 + { 0xaa, 0x0a, 0x88, 0x63, 0xc0}, // 1010 1010 0000 1010 10001000 01100011 1100 CH2 + { 0x38, 0x08, 0x08, 0x43, 0xb0}, // 0011 1000 0000 1000 00001000 01000011 1011 CH2 + { 0xae, 0x08, 0x88, 0xc3, 0x70}, // 1010 1110 0000 1000 10001000 11000011 0111 CH3 + { 0x4f, 0x0d, 0x08, 0x83, 0x50}, // 0100 1111 0000 1101 00001000 10000011 0101 CH3 + { 0xbe, 0x05, 0x08, 0x83, 0x30}, // 1011 1110 0000 0101 00001000 10000011 0011 CH3 + { 0x3e, 0x01, 0x08, 0x83, 0x90}, // 0011 1110 0000 0001 00001000 10000011 1001 CH3 + { 0xbd, 0x01, 0x08, 0x83, 0x70}, // 1011 1101 0000 0001 00001000 10000011 0111 CH3 + { 0xac, 0x0e, 0x08, 0x83, 0xb0} // 1010 1100 0000 1110 00001000 10000011 1011 CH3 + }; + + int tests = 0; + for(size_t i=0; i