3 * *** Fine Offset WH1050 Weather Station ***
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.
13 * The original module was by
15 * 2016 Nicola Quiriti ('ovrheat')
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)
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.
32 * Data are trasmitted in a 48 seconds cycle (data packet, then wait 48 seconds, then data packet...).
34 * The 'Total rainfall' field is a cumulative counter, increased by 0.3 millimeters of rain at once.
50 static unsigned short get_device_id(const uint8_t* br) {
51 return (br[1] << 4 & 0xf0 ) | (br[2] >> 4);
54 static char* get_battery(const uint8_t* br) {
55 if (!(br[2] & 0x04)) {
62 // ------------ WEATHER SENSORS DECODING ----------------------------------------------------
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;
69 static int get_humidity(const uint8_t* br) {
73 static float get_wind_speed_raw(const uint8_t* br) {
77 static float get_wind_avg_ms(const uint8_t* br) {
78 return (br[5] * 34.0f) / 100; // Meters/sec.
81 static float get_wind_avg_mph(const uint8_t* br) {
82 return ((br[5] * 34.0f) / 100) * 2.23693629f; // Mph
85 static float get_wind_avg_kmh(const uint8_t* br) {
86 return ((br[5] * 34.0f) / 100) * 3.6f; // Km/h
89 static float get_wind_avg_knot(const uint8_t* br) {
90 return ((br[5] * 34.0f) / 100) * 1.94384f; // Knots
93 static float get_wind_gust_raw(const uint8_t* br) {
97 static float get_wind_gust_ms(const uint8_t* br) {
98 return (br[6] * 34.0f) / 100; // Meters/sec.
101 static float get_wind_gust_mph(const uint8_t* br) {
102 return ((br[6] * 34.0f) / 100) * 2.23693629f; // Mph
106 static float get_wind_gust_kmh(const uint8_t* br) {
107 return ((br[6] * 34.0f) / 100) * 3.6f; // Km/h
110 static float get_wind_gust_knot(const uint8_t* br) {
111 return ((br[6] * 34.0f) / 100) * 1.94384f; // Knots
114 static float get_rainfall(const uint8_t* br) {
115 return ((((unsigned short)br[7] & 0x0f) << 8) | br[8]) * 0.3f;
119 //-------------------------------------------------------------------------------------
120 //-------------------------------------------------------------------------------------
124 static int fineoffset_wh1050_callback(bitbuffer_t *bitbuffer) {
126 char time_str[LOCAL_TIME_BUFLEN];
127 local_time_str(0, time_str);
129 if (bitbuffer->num_rows != 1) {
132 if (bitbuffer->bits_per_row[0] != 80) {
136 const uint8_t *br = bitbuffer->bb[0];
143 if (br[9] != crc8(br, 9, CRC_POLY, CRC_INIT)) {
148 //---------------------------------------------------------------------------------------
149 //-------- GETTING WEATHER SENSORS DATA -------------------------------------------------
151 const float temperature = get_temperature(br);
152 const int humidity = get_humidity(br);
154 // Select which metric system for *wind avg speed* and *wind gust* :
156 // Wind average speed :
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
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
171 const float rain = get_rainfall(br);
172 const int device_id = get_device_id(br);
173 const char* battery = get_battery(br);
175 //---------------------------------------------------------------------------------------
176 //--------- PRESENTING DATA --------------------------------------------------------------
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...
188 data_acquired_handler(data);
192 static char *output_fields[] = {
205 r_device fineoffset_wh1050 = {
206 .name = "Fine Offset WH1050 Weather Station",
207 .modulation = OOK_PULSE_PWM_RAW,
210 .reset_limit = 10520,
211 .json_callback = &fineoffset_wh1050_callback,
214 .fields = output_fields,