Bugfixes
[rtl-433.git] / src / devices / fineoffset_wh1050.c
1
2 /*
3  * *** Fine Offset WH1050 Weather Station ***
4  * (aka )
5  * (aka .....)
6  *
7  * This module is a cut-down version of the WH1080 decoder.
8  * The WH1050 sensor unit is like the WH1080 unit except it has no
9  * wind direction sensor or time receiver.
10  * Other than omitting the ynused code, the differences are the message length
11  * and the location of the battery-low bit.
12  *
13  * The original module was by
14  *
15  * 2016 Nicola Quiriti ('ovrheat')
16  *
17  * Modifications by
18  *
19  * 2016 Don More
20  *
21  *********************
22  *
23  * This weather station is based on an indoor touchscreen receiver, and on a 5+1 outdoor wireless sensors group
24  * (rain, wind speed, temperature, humidity.
25  * See the product page here: http://www.foshk.com/Weather_Professional/WH1070.html (The 1050 model has no radio clock)
26  *
27  * Please note that the pressure sensor (barometer) is enclosed in the indoor console unit, NOT in the outdoor
28  * wireless sensors group.
29  * That's why it's NOT possible to get pressure data by wireless communication. If you need pressure data you should try
30  * an Arduino/Raspberry solution wired with a BMP180 or BMP085 sensor.
31  *
32  * Data are trasmitted in a 48 seconds cycle (data packet, then wait 48 seconds, then data packet...).
33  *
34  * The 'Total rainfall' field is a cumulative counter, increased by 0.3 millimeters of rain at once.
35  *
36  *
37  *
38  *
39  */
40
41
42 #include "data.h"
43 #include "rtl_433.h"
44 #include "util.h"
45 #include "math.h"
46
47 #define CRC_POLY 0x31
48 #define CRC_INIT 0xff
49
50 static unsigned short get_device_id(const uint8_t* br) {
51         return (br[1] << 4 & 0xf0 ) | (br[2] >> 4);
52 }
53
54 static char* get_battery(const uint8_t* br) {
55         if (!(br[2] & 0x04)) {
56                 return "OK";
57         } else {
58                 return "LOW";
59         }
60 }
61
62 // ------------ WEATHER SENSORS DECODING ----------------------------------------------------
63
64 static float get_temperature(const uint8_t* br) {
65     const int temp_raw = (br[2] << 8) + br[3];
66     return ((temp_raw & 0x03ff) - 0x190) / 10.0;
67 }
68
69 static int get_humidity(const uint8_t* br) {
70     return br[4];
71 }
72
73 static float get_wind_speed_raw(const uint8_t* br) {
74     return br[5]; // Raw
75 }
76
77 static float get_wind_avg_ms(const uint8_t* br) {
78     return (br[5] * 34.0f) / 100; // Meters/sec.
79 }
80
81 static float get_wind_avg_mph(const uint8_t* br) {
82     return ((br[5] * 34.0f) / 100) * 2.23693629f; // Mph
83 }
84
85 static float get_wind_avg_kmh(const uint8_t* br) {
86     return ((br[5] * 34.0f) / 100) * 3.6f; // Km/h
87 }
88
89 static float get_wind_avg_knot(const uint8_t* br) {
90     return ((br[5] * 34.0f) / 100) * 1.94384f; // Knots
91 }
92
93 static float get_wind_gust_raw(const uint8_t* br) {
94     return br[6]; // Raw
95 }
96
97 static float get_wind_gust_ms(const uint8_t* br) {
98     return (br[6] * 34.0f) / 100; // Meters/sec.
99 }
100
101 static float get_wind_gust_mph(const uint8_t* br) {
102     return ((br[6] * 34.0f) / 100) * 2.23693629f; // Mph
103
104 }
105
106 static float get_wind_gust_kmh(const uint8_t* br) {
107     return ((br[6] * 34.0f) / 100) * 3.6f; // Km/h
108 }
109
110 static float get_wind_gust_knot(const uint8_t* br) {
111     return ((br[6] * 34.0f) / 100) * 1.94384f; // Knots
112 }
113
114 static float get_rainfall(const uint8_t* br) {
115         return ((((unsigned short)br[7] & 0x0f) << 8) | br[8]) * 0.3f;
116 }
117
118
119 //-------------------------------------------------------------------------------------
120 //-------------------------------------------------------------------------------------
121
122
123
124 static int fineoffset_wh1050_callback(bitbuffer_t *bitbuffer) {
125     data_t *data;
126     char time_str[LOCAL_TIME_BUFLEN];
127     local_time_str(0, time_str);
128
129     if (bitbuffer->num_rows != 1) {
130         return 0;
131     }
132     if (bitbuffer->bits_per_row[0] != 80) {
133         return 0;
134     }
135
136     const uint8_t *br = bitbuffer->bb[0];
137
138     if (br[0] != 0xff) {
139         // preamble missing
140         return 0;
141     }
142
143     if (br[9] != crc8(br, 9, CRC_POLY, CRC_INIT)) {
144         // crc mismatch
145         return 0;
146     }
147
148 //---------------------------------------------------------------------------------------
149 //-------- GETTING WEATHER SENSORS DATA -------------------------------------------------
150
151     const float temperature = get_temperature(br);
152     const int humidity = get_humidity(br);
153
154         // Select which metric system for *wind avg speed* and *wind gust* :
155
156         // Wind average speed :
157
158         //const float speed = get_wind_avg_ms((br)   // <--- Data will be shown in Meters/sec.
159         //const float speed = get_wind_avg_mph((br)  // <--- Data will be shown in Mph
160         const float speed = get_wind_avg_kmh(br);  // <--- Data will be shown in Km/h
161         //const float speed = get_wind_avg_knot((br) // <--- Data will be shown in Knots
162
163
164         // Wind gust speed :
165
166     //const float gust = get_wind_gust_ms(br);   // <--- Data will be shown in Meters/sec.
167         //const float gust = get_wind_gust_mph(br);  // <--- Data will be shown in Mph
168         const float gust = get_wind_gust_kmh(br);  // <--- Data will be shown in km/h
169         //const float gust = get_wind_gust_knot(br); // <--- Data will be shown in Knots
170
171     const float rain = get_rainfall(br);
172     const int device_id = get_device_id(br);
173         const char* battery = get_battery(br);
174
175 //---------------------------------------------------------------------------------------
176 //--------- PRESENTING DATA --------------------------------------------------------------
177
178     data = data_make("time",            "",             DATA_STRING, time_str,
179                      "model",           "",             DATA_STRING, "Fine Offset WH1050 weather station",
180                      "id",            "StationID",      DATA_FORMAT, "%04X",    DATA_INT,    device_id,
181                      "temperature_C", "Temperature",    DATA_FORMAT, "%.01f C", DATA_DOUBLE, temperature,
182                      "humidity",      "Humidity",       DATA_FORMAT, "%u %%",   DATA_INT,    humidity,
183                      "speed",         "Wind avg speed", DATA_FORMAT, "%.02f",   DATA_DOUBLE, speed,
184                      "gust",          "Wind gust",      DATA_FORMAT, "%.02f",   DATA_DOUBLE, gust,
185                      "rain",          "Total rainfall", DATA_FORMAT, "%.01f",   DATA_DOUBLE, rain,
186                      "battery",       "Battery",        DATA_STRING, battery, // Unsure about Battery byte...
187                      NULL);
188     data_acquired_handler(data);
189     return 1;
190 }
191
192 static char *output_fields[] = {
193         "time",
194         "model",
195         "id",
196         "temperature_C",
197         "humidity",
198         "speed",
199         "gust",
200         "rain",
201         "battery",
202         NULL
203 };
204
205 r_device fineoffset_wh1050 = {
206     .name           = "Fine Offset WH1050 Weather Station",
207     .modulation     = OOK_PULSE_PWM_RAW,
208     .short_limit    = 976,
209     .long_limit     = 2400,
210     .reset_limit    = 10520,
211     .json_callback  = &fineoffset_wh1050_callback,
212     .disabled       = 0,
213     .demod_arg      = 0,
214     .fields         = output_fields,
215 };