Acurite 5in1 minor fixes
[rtl-433.git] / src / devices / acurite.c
1 #include "rtl_433.h"
2
3 // ** Acurite 5n1 functions **
4
5 const float acurite_winddirections[] =
6     { 337.5, 315.0, 292.5, 270.0, 247.5, 225.0, 202.5, 180,
7       157.5, 135.0, 112.5, 90.0, 67.5, 45.0, 22.5, 0.0 };
8
9 static int acurite_raincounter = 0;
10
11 static int acurite_crc(uint8_t row[BITBUF_COLS], int cols) {
12     // sum of first n-1 bytes modulo 256 should equal nth byte
13     int i;
14     int sum = 0;
15     for ( i=0; i < cols; i++)
16         sum += row[i];
17     if ( sum % 256 == row[cols] )
18         return 1;
19     else
20         return 0;
21 }
22
23 static int acurite_detect(uint8_t *pRow) {
24     int i;
25     if ( pRow[0] != 0x00 ) {
26         // invert bits due to wierd issue
27         for (i = 0; i < 8; i++)
28             pRow[i] = ~pRow[i] & 0xFF;
29         pRow[0] |= pRow[8];  // fix first byte that has mashed leading bit
30
31         if (acurite_crc(pRow, 7))
32             return 1;  // passes crc check
33     }
34     return 0;
35 }
36
37 static float acurite_getTemp (uint8_t highbyte, uint8_t lowbyte) {
38     // range -40 to 158 F
39     int highbits = (highbyte & 0x0F) << 7 ;
40     int lowbits = lowbyte & 0x7F;
41     int rawtemp = highbits | lowbits;
42     float temp = (rawtemp - 400) / 10.0;
43     return temp;
44 }
45
46 static int acurite_getWindSpeed (uint8_t highbyte, uint8_t lowbyte) {
47     // range: 0 to 159 kph
48         // TODO: sensor does not seem to be in kph, e.g.,
49         // a value of 49 here was registered as 41 kph on base unit
50         // value could be rpm, etc which may need (polynomial) scaling factor??
51         int highbits = ( highbyte & 0x1F) << 3;
52     int lowbits = ( lowbyte & 0x70 ) >> 4;
53     int speed = highbits | lowbits;
54     return speed;
55 }
56
57 static float acurite_getWindDirection (uint8_t byte) {
58     // 16 compass points, ccw from (NNW) to 15 (N)
59     int direction = byte & 0x0F;
60     return acurite_winddirections[direction];
61 }
62
63 static int acurite_getHumidity (uint8_t byte) {
64     // range: 1 to 99 %RH
65     int humidity = byte & 0x7F;
66     return humidity;
67 }
68
69 static int acurite_getRainfallCounter (uint8_t hibyte, uint8_t lobyte) {
70     // range: 0 to 99.99 in, 0.01 in incr., rolling counter?
71         int raincounter = ((hibyte & 0x7f) << 7) | (lobyte & 0x7F);
72     return raincounter;
73 }
74
75 static int acurite5n1_callback(uint8_t bb[BITBUF_ROWS][BITBUF_COLS],int16_t bits_per_row[BITBUF_ROWS]) {
76     // acurite 5n1 weather sensor decoding for rtl_433
77     // Jens Jensen 2014
78     int i;
79     uint8_t *buf = NULL;
80     // run through rows til we find one with good crc (brute force)
81     for (i=0; i < BITBUF_ROWS; i++) {
82         if (acurite_detect(bb[i])) {
83             buf = bb[i];
84             break; // done
85         }
86     }
87
88     if (buf) {
89         // decode packet here
90         if (debug_output) {
91             for (i=0; i < 8; i++)
92                 fprintf(stderr, "%02X ", buf[i]);
93             fprintf(stderr, "CRC OK\n");
94         }
95
96         if ((buf[2] & 0x0F) == 1) {
97             // wind speed, wind direction, rainfall
98             fprintf(stdout, "SENSOR:TYPE=ACURITE_5IN1,");
99
100             float rainfall = 0.00;
101             int raincounter = acurite_getRainfallCounter(buf[5], buf[6]);
102             if (acurite_raincounter > 0) {
103                 // track rainfall difference after first run
104                 rainfall = ( raincounter - acurite_raincounter ) * 0.01;
105             } else {
106                 // capture starting counter
107                 acurite_raincounter = raincounter;
108             }
109
110             fprintf(stdout, "WINDSPEED=%d,",
111                 acurite_getWindSpeed(buf[3], buf[4]));
112             fprintf(stdout, "WINDDIRECTION=%0.1f,",
113                 acurite_getWindDirection(buf[4]));
114             fprintf(stdout, "RAINGAUGE=%0.2f\n", rainfall);
115
116         } else if ((buf[2] & 0x0F) == 8) {
117             fprintf(stdout, "SENSOR:TYPE=ACURITE_5IN1,");
118             // wind speed, temp, RH
119             fprintf(stdout, "WINDSPEED=%d,",
120                 acurite_getWindSpeed(buf[3], buf[4]));
121             fprintf(stdout, "TEMPERATURE=%2.1f,",
122                 acurite_getTemp(buf[4], buf[5]));
123             fprintf(stdout, "HUMIDITY=%d\n",
124                 acurite_getHumidity(buf[6]));
125         }
126     } else {
127         return 0;
128     }
129
130     if (debug_output)
131         debug_callback(bb, bits_per_row);
132
133     return 1;
134 }
135
136 static int acurite_rain_gauge_callback(uint8_t bb[BITBUF_ROWS][BITBUF_COLS], int16_t bits_per_row[BITBUF_ROWS]) {
137     // This needs more validation to positively identify correct sensor type, but it basically works if message is really from acurite raingauge and it doesn't have any errors
138     if ((bb[0][0] != 0) && (bb[0][1] != 0) && (bb[0][2]!=0) && (bb[0][3] == 0) && (bb[0][4] == 0)) {
139             float total_rain = ((bb[0][1]&0xf)<<8)+ bb[0][2];
140                 total_rain /= 2; // Sensor reports number of bucket tips.  Each bucket tip is .5mm
141                 fprintf(stdout, "SENSOR:TYPE=ACURITE_RAIN_GAUGE,RAIN=%2.1f\n", total_rain);
142                 fprintf(stderr, "Raw Message: %02x %02x %02x %02x %02x\n",bb[0][0],bb[0][1],bb[0][2],bb[0][3],bb[0][4]);
143         return 1;
144     }
145     return 0;
146 }
147
148 static int acurite_th_detect(uint8_t *buf){
149     if(buf[5] != 0) return 0;
150     uint8_t sum = (buf[0] + buf[1] + buf[2] + buf[3]) & 0xff;
151     if(sum == 0) return 0;
152     return sum == buf[4];
153 }
154 static float acurite_th_temperature(uint8_t *s){
155     uint16_t shifted = (((s[1] & 0x0f) << 8) | s[2]) << 4; // Logical left shift
156     return (((int16_t)shifted) >> 4) / 10.0; // Arithmetic right shift
157 }
158 static int acurite_th_callback(uint8_t bb[BITBUF_ROWS][BITBUF_COLS], int16_t bits_per_row[BITBUF_ROWS]) {
159     uint8_t *buf = NULL;
160     int i;
161     for(i = 0; i < BITBUF_ROWS; i++){
162         if(acurite_th_detect(bb[i])){
163             buf = bb[i];
164             break;
165         }
166     }
167     if(buf){
168         fprintf(stdout, "SENSOR:TYPE=ACURITE_TEMP,");
169         fprintf(stdout, "TEMPERATURE=%.1f,", acurite_th_temperature(buf));
170         fprintf(stdout, "HUMIDITY=%d\n", buf[3]);
171         return 1;
172     }
173
174     return 0;
175 }
176
177 r_device acurite5n1 = {
178     /* .id             = */ 10,
179     /* .name           = */ "Acurite 5n1 Weather Station",
180     /* .modulation     = */ OOK_PWM_P,
181     /* .short_limit    = */ 70,
182     /* .long_limit     = */ 240,
183     /* .reset_limit    = */ 21000,
184     /* .json_callback  = */ &acurite5n1_callback,
185 };
186
187 r_device acurite_rain_gauge = {
188     /* .id             = */ 11,
189     /* .name           = */ "Acurite 896 Rain Gauge",
190     /* .modulation     = */ OOK_PWM_D,
191     /* .short_limit    = */ 1744/4,
192     /* .long_limit     = */ 3500/4,
193     /* .reset_limit    = */ 5000/4,
194     /* .json_callback  = */ &acurite_rain_gauge_callback,
195 };
196
197 r_device acurite_th = {
198     /* .id             = */ 12,
199     /* .name           = */ "Acurite Temperature and Humidity Sensor",
200     /* .modulation     = */ OOK_PWM_D,
201     /* .short_limit    = */ 300,
202     /* .long_limit     = */ 550,
203     /* .reset_limit    = */ 2500,
204     /* .json_callback  = */ &acurite_th_callback,
205 };