Редизайн на основе текущей ветки мейнстрима + новые устройства.
[rtl-433.git] / src / devices / gt_wt_02.c
1 #include "rtl_433.h"
2 #include "util.h"
3
4 /*
5  * GT-WT-02 sensor on 433.92MHz
6  *
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.
11  */
12
13  /* Example and frame description provided by https://github.com/ludwich66
14
15  [01] {37} 34 00 ed 47 60 : 00110100 00000000 11101101 01000111 01100000
16  code, BatOK,not-man-send, Channel1, +23,7°C, 35%
17
18  [01] {37} 34 8f 87 15 90 : 00110100 10001111 10000111 00010101 10010000
19  code, BatOK,not-man-send, Channel1,-12,1°C, 10%
20
21  Humidity:
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%
25
26  SENSOR: GT-WT-02 (ALDI Globaltronics..)
27  TYP AAAAAAAA BCDDEFFF FFFFFFFF GGGGGGGx xxxxx
28  BIT 76543210 76543210 76543210 76543210 76543
29
30  TYPDescriptian
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
39  x = checksum
40
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
51 */
52
53
54 static int gt_wt_02_process_row(int row, const bitbuffer_t *bitbuffer)
55 {
56   data_t *data;  /*JF*/
57   const uint8_t *b = bitbuffer->bb[row];
58   const int length = bitbuffer->bits_per_row[row];
59
60   if ( 37 != length
61       || !(b[0] || b[1] || b[2] || b[3] || b[4])) /* exclude all zeros */
62     return 0;
63
64   //fprintf(stderr, "GT-WT-02: %02x %02x %02x %02x %02x\n", b[0], b[1], b[2], b[3], b[4]);
65
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);
72
73   // put last 6 bits into a number
74   const int checksum = ((b[3] & 1 )<<5) + (b[4]>>3);
75
76   // accept only correct checksums, (sum of nibbles modulo 64)
77   if ((sum_nibbles & 0x3F) != checksum)
78     return 0;
79
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
84   if (10 == humidity)
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)
89   {
90     snprintf(humidity_str_buf, 4, "%2d", humidity);
91     humidity_str = humidity_str_buf;
92   }
93   else
94     return 0;  // very unlikely, but the humidity is outside of valid range
95
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 */
102
103   float tempC = (negative_sign ? ( temp - (1<<12) ) : temp ) * 0.1F;
104
105   char time_str[LOCAL_TIME_BUFLEN];
106   local_time_str(0, time_str);
107
108   data = data_make(
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,
117     NULL);
118     data_acquired_handler(data);
119     return 1;
120 //# {
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);
124 //
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);
128 //}
129 //return 1; */
130 }
131
132 static int gt_wt_02_callback(bitbuffer_t *bitbuffer)
133 {
134   int counter = 0;
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);
138   return counter;
139 }
140
141 static char *output_fields[] = {
142   "time",
143   "model",
144   "rc",
145   "channel",
146   "battery",
147   "button",
148   "temperature_C",
149   "humidity",
150   NULL
151 };
152
153 r_device gt_wt_02 = {
154   .name          = "GT-WT-02 Sensor",
155   .modulation    = OOK_PULSE_PPM_RAW,
156   .short_limit   = 3000,
157   .long_limit    = 6000,
158   .reset_limit   = 10000,
159   .json_callback = &gt_wt_02_callback,
160   .disabled      = 0,
161   .demod_arg     = 0,
162   .fields        = output_fields,
163 };
164
165 // Test code
166 // gcc -I src/ -I include/ -std=gnu99 -D _TEST_DECODER src/devices/gt_wt_02.c src/util.c
167 #ifdef _TEST_DECODER
168 int main()
169 {
170   bitbuffer_t bb;
171   bb.num_rows = 1;
172   bb.bits_per_row[0] = 37;
173   const uint8_t b[4][5] =
174     {
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},
179     };
180
181   for(int i=0; i<4; i++)
182   {
183     memcpy(bb.bb[0], b[i], 5);
184     gt_wt_02_callback(&bb);
185   }
186
187 /*
188  * Result:
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%
192 */
193
194 }
195
196 #endif