5 * GT-WT-02 sensor on 433.92MHz
7 * Copyright (C) 2015 Paul Ortyl
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 3 as
10 * published by the Free Software Foundation.
13 /* Example and frame description provided by https://github.com/ludwich66
15 [01] {37} 34 00 ed 47 60 : 00110100 00000000 11101101 01000111 01100000
16 code, BatOK,not-man-send, Channel1, +23,7°C, 35%
18 [01] {37} 34 8f 87 15 90 : 00110100 10001111 10000111 00010101 10010000
19 code, BatOK,not-man-send, Channel1,-12,1°C, 10%
22 * the working range is 20-90 %
23 * if „LL“ in display view it sends 10 %
24 * if „HH“ in display view it sends 110%
26 SENSOR: GT-WT-02 (ALDI Globaltronics..)
27 TYP AAAAAAAA BCDDEFFF FFFFFFFF GGGGGGGx xxxxx
28 BIT 76543210 76543210 76543210 76543210 76543
31 A = Rolling Device Code, Change after battery replacement
32 B = Battery 0=OK 1=LOW
33 C = Manual Send Button Pressed 0=not pressed 1=pressed
34 D = Channel 00=CH1, 01=CH2, 11=CH3
35 E = Temp 0=positive 1=negative
36 F = PositiveTemp =12 Bit bin2dez Temp,
37 F = negative Temp = 4095+1- F (12Bit bin2dez) , Factor Divid F / 10 (1Dezimal)
38 G = Humidity = 7 Bit bin2dez 00-99
41 bin2dez(Bit1;Bit2;Bit3;Bit4)+ #rolling code
42 bin2dez(Bit5;Bit6;Bit7;Bit8)+ #rolling code
43 bin2dez(Bit9;Bit10;Bit11;Bit12)+ # send, bat , ch
44 bin2dez(Bit13;Bit14;Bit15;Bit16)+ #temp1
45 bin2dez(Bit17;Bit18;Bit19;Bit20)+ #temp2
46 bin2dez(Bit21;Bit22;Bit23;Bit24)+ #temp3
47 bin2dez(Bit25;Bit26;Bit27;Bit28)+ #hum1
48 bin2dez(Bit29;Bit30;Bit31;Bit=0) = #hum2
49 bin2dez(Bit32;Bit33;Bit34;Bit35;Bit36;Bit37) #checksum
50 checksum = sum modulo 64
54 static int gt_wt_02_process_row(int row, const bitbuffer_t *bitbuffer)
57 const uint8_t *b = bitbuffer->bb[row];
58 const int length = bitbuffer->bits_per_row[row];
61 || !(b[0] || b[1] || b[2] || b[3] || b[4])) /* exclude all zeros */
64 //fprintf(stderr, "GT-WT-02: %02x %02x %02x %02x %02x\n", b[0], b[1], b[2], b[3], b[4]);
66 // sum 8 nibbles (use 31 bits, the last one fill with 0 on 32nd bit)
67 const int sum_nibbles =
68 (b[0] >> 4) + (b[0] & 0xF)
69 + (b[1] >> 4) + (b[1] & 0xF)
70 + (b[2] >> 4) + (b[2] & 0xF)
71 + (b[3] >> 4) + (b[3] & 0xe);
73 // put last 6 bits into a number
74 const int checksum = ((b[3] & 1 )<<5) + (b[4]>>3);
76 // accept only correct checksums, (sum of nibbles modulo 64)
77 if ((sum_nibbles & 0x3F) != checksum)
80 // humidity: see above the note about working range
81 const int humidity = (b[3]>>1); // extract bits for humidity
82 char const * humidity_str; // pointer passed to the final printf
83 char humidity_str_buf[4]={0}; // buffer for humidity als decimal string
85 humidity_str = "LL"; // below working range of 20%
86 else if (110 == humidity)
87 humidity_str = "HH"; // above working range of 90%
88 else if (20<= humidity && humidity <= 90)
90 snprintf(humidity_str_buf, 4, "%2d", humidity);
91 humidity_str = humidity_str_buf;
94 return 0; // very unlikely, but the humidity is outside of valid range
96 const int sensor_id = b[0]; /* 8 x A */
97 const int battery_low = (b[1] >> 7 & 1); /* 1 x B */
98 const int button_pressed = (b[1] >> 6 & 1); /* 1 x C */
99 const int channel = (b[1] >> 4 & 3); /* 2 x D */
100 const int negative_sign = (b[1] >> 3 & 1); /* 1 x E */
101 const int temp = (((b[1] & 15) << 8) | b[2]); /* E + 11 X G */
103 float tempC = (negative_sign ? ( temp - (1<<12) ) : temp ) * 0.1F;
105 char time_str[LOCAL_TIME_BUFLEN];
106 local_time_str(0, time_str);
109 "time", "", DATA_STRING, time_str,
110 "model", "", DATA_STRING, "GT_WT_02 sensor",
111 "rc", "Rolling Code", DATA_INT, sensor_id,
112 "channel", "Channel", DATA_INT, channel+1,
113 "battery", "Battery", DATA_STRING, battery_low ? "LOW" : "OK",
114 "button", "Button ", DATA_INT, button_pressed,
115 "temperature_C", "Temperature", DATA_FORMAT, "%.01f C",DATA_DOUBLE,tempC,
116 "humidity", "Humidity", DATA_STRING, humidity_str,
118 data_acquired_handler(data);
121 // /* @todo: remove timestamp printing as soon as the controller takes this task */
122 // char time_str[LOCAL_TIME_BUFLEN];
123 // local_time_str(0, time_str);
125 // /* @todo make temperature unit configurable, not printing both */
126 // fprintf(stdout, "%s, GT-WT-02 Sensor %02x, battery %s, channel %d, button %d, temperature %3.1f C, humidity %s%%\n"
127 // , time_str, sensor_id, battery_low ? "LOW" : "OK", channel+1, button_pressed, tempC, humidity_str);
132 static int gt_wt_02_callback(bitbuffer_t *bitbuffer)
135 // iterate through all rows, return on first successful
136 for(int row=0; row<bitbuffer->num_rows && !counter; row++)
137 counter += gt_wt_02_process_row(row, bitbuffer);
141 static char *output_fields[] = {
153 r_device gt_wt_02 = {
154 .name = "GT-WT-02 Sensor",
155 .modulation = OOK_PULSE_PPM_RAW,
158 .reset_limit = 10000,
159 .json_callback = >_wt_02_callback,
162 .fields = output_fields,
166 // gcc -I src/ -I include/ -std=gnu99 -D _TEST_DECODER src/devices/gt_wt_02.c src/util.c
172 bb.bits_per_row[0] = 37;
173 const uint8_t b[4][5] =
175 {0x00, 0x00, 0x00, 0x00, 0x00}, // this one is excluded despite the correct checksum
176 {0x34, 0x00, 0xed, 0x47, 0x60},
177 {0x34, 0x8f, 0x87, 0x15, 0x90},
178 {0x34, 0x00, 0xde, 0x77, 0x78},
181 for(int i=0; i<4; i++)
183 memcpy(bb.bb[0], b[i], 5);
184 gt_wt_02_callback(&bb);
189 2015-08-16 19:08:16 GT-WT-02 Sensor 34: battery OK, channel 0, button 0, temperature 23.7 C / 74.7 F, humidity 35%
190 2015-08-16 19:08:16 GT-WT-02 Sensor 34: battery low, channel 0, button 0, temperature -12.1 C / 10.2 F, humidity LL%
191 2015-08-16 19:08:16 GT-WT-02 Sensor 34: battery OK, channel 0, button 0, temperature 22.2 C / 72.0 F, humidity 59%