Skip to content

Commit 4461594

Browse files
blackholefinderandrewjw
authored andcommitted
Add radio clock to Fineoffset-WH1050 (merbanan#2463)
* Added message type which contains time data every 2hours.
1 parent 4984ad8 commit 4461594

File tree

1 file changed

+98
-27
lines changed

1 file changed

+98
-27
lines changed

src/devices/fineoffset_wh1050.c

Lines changed: 98 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,26 @@ I.e., data packet, wait 48 seconds, two data packets, wait 48 seconds, data pack
3434
3535
The 'Total rainfall' field is a cumulative counter, increased by 0.3 millimeters of rain each step.
3636
37-
Message layout and example:
37+
The station is also known as TFA STRATOS 35.1077
38+
See the product page here: https://www.tfa-dostmann.de/en/product/wireless-weather-station-with-wind-and-rain-gauge-stratos-35-1077/
39+
This model seems also capable to decode the DCF77 time signal sent by the time signal decoder (which is enclosed on the sensor tx):
40+
around the minute 59 of the even hours the sensor's TX stops sending weather data, probably to receive (and sync with) DCF77 signals.
41+
After around 3-4 minutes of silence it starts to send just time data for some minute, then it starts again with
42+
weather data as usual.
43+
44+
To recognize which message is received (weather or time) you can use the 'msg_type' field on json output:
45+
- msg_type 0 = weather data
46+
- msg_type 1 = time data
47+
48+
Weather data - Message layout and example:
3849
3950
AA BC CD DD EE FF GG HH HH II
4051
{80} ff 5f 51 93 48 00 00 12 46 aa
4152
4253
- A : 8 bits : Preamble 0xFF
43-
- B : 4 bits : ?? - always seems to be 0x5
54+
- B : 4 bits : ?? - seems to be 0x5 for whether data, 0x6 for time data
4455
- C : 8 bits : Id, changes when reset (e.g., 0xF5)
45-
- D : 1 bit : ?? - unknown, always seems to be 0
56+
- D : 1 bit : msg_type - 0, for whether data
4657
- D : 1 bit : Battery, 0 = ok, 1 = low (e.g, OK)
4758
- D : 10 bits : Temperature in Celsius, offset 400, scaled by 10 (e.g., 0.3 degrees C)
4859
- E : 8 bits : Relative humidity, percent (e.g., 72%)
@@ -51,6 +62,32 @@ Message layout and example:
5162
- H : 16 bits : Total rainfall in units of 0.3mm, since reset (e.g., 1403.4 mm)
5263
- I : 8 bits : CRC, poly 0x31, init 0x00 (excluding preamble)
5364
65+
Time data - Message layout and example:
66+
67+
AA BC CD DE FG HI JK LM NO PP
68+
{80} ff 69 0a 96 02 41 23 43 27 df
69+
70+
- A : 8 bits : Preamble 0xFF
71+
- B : 4 bits : ?? - seems to be 0x5 for whether data, seems 0x6 for time data
72+
- C : 8 bits : Id, changes when reset (e.g., 0xF5)
73+
- D : 1 bit : msg_type - 1, for time data
74+
- D : 1 bit : Battery, 0 = ok, 1 = low (e.g, OK)
75+
- D : 4 bits : ??
76+
- D : 2 bits : hour BCD coded (*10)
77+
- E : 4 bits : hour BCD coded (*1)
78+
- F : 4 bits : minute BCD coded (*10)
79+
- G : 4 bits : minute BCD coded (*1)
80+
- H : 4 bits : second BCD coded (*10)
81+
- I : 4 bits : second BCD coded (*1)
82+
- J : 4 bits : year BCD coded (*10), counted from 2000
83+
- K : 4 bits : year BCD coded (*1), counted from 2000
84+
- L : 3 bits : ??
85+
- L : 1 bits : month BCD coded (*10)
86+
- M : 4 bits : month BCD coded (*1)
87+
- N : 4 bits : day BCD coded (*10)
88+
- O : 4 bits : day BCD coded (*1)
89+
- P : 8 bits : CRC, poly 0x31, init 0x00 (excluding preamble)
90+
5491
*/
5592

5693
#include "decoder.h"
@@ -91,30 +128,62 @@ static int fineoffset_wh1050_callback(r_device *decoder, bitbuffer_t *bitbuffer)
91128
return DECODE_FAIL_MIC; // crc mismatch
92129
}
93130

94-
// GETTING WEATHER SENSORS DATA
95-
int temp_raw = ((br[1] & 0x03) << 8) | br[2];
96-
float temperature = (temp_raw - 400) * 0.1f;
97-
int humidity = br[3];
98-
float speed = (br[4] * 0.34f) * 3.6f; // m/s -> km/h
99-
float gust = (br[5] * 0.34f) * 3.6f; // m/s -> km/h
100-
int rain_raw = (br[6] << 8) | br[7];
101-
float rain = rain_raw * 0.3f;
102-
int device_id = (br[0] << 4 & 0xf0) | (br[1] >> 4);
103-
int battery_low = br[1] & 0x04;
104-
105-
/* clang-format off */
106-
data = data_make(
107-
"model", "", DATA_STRING, "Fineoffset-WH1050",
108-
"id", "StationID", DATA_FORMAT, "%04X", DATA_INT, device_id,
109-
"battery_ok", "Battery", DATA_INT, !battery_low,
110-
"temperature_C", "Temperature", DATA_FORMAT, "%.01f C", DATA_DOUBLE, temperature,
111-
"humidity", "Humidity", DATA_FORMAT, "%u %%", DATA_INT, humidity,
112-
"wind_avg_km_h", "Wind avg speed", DATA_FORMAT, "%.02f", DATA_DOUBLE, speed,
113-
"wind_max_km_h", "Wind gust", DATA_FORMAT, "%.02f", DATA_DOUBLE, gust,
114-
"rain_mm", "Total rainfall", DATA_FORMAT, "%.01f", DATA_DOUBLE, rain,
115-
"mic", "Integrity", DATA_STRING, "CRC",
116-
NULL);
117-
/* clang-format on */
131+
// GETTING MESSAGE TYPE
132+
int msg_type = (br[1] & 0x08) >> 3;
133+
134+
if (msg_type == 0) {
135+
// GETTING WEATHER SENSORS DATA
136+
int temp_raw = ((br[1] & 0x03) << 8) | br[2];
137+
float temperature = (temp_raw - 400) * 0.1f;
138+
int humidity = br[3];
139+
float speed = (br[4] * 0.34f) * 3.6f; // m/s -> km/h
140+
float gust = (br[5] * 0.34f) * 3.6f; // m/s -> km/h
141+
int rain_raw = (br[6] << 8) | br[7];
142+
float rain = rain_raw * 0.3f;
143+
int device_id = (br[0] << 4 & 0xf0) | (br[1] >> 4);
144+
int battery_low = br[1] & 0x04;
145+
146+
/* clang-format off */
147+
data = data_make(
148+
"model", "", DATA_STRING, "Fineoffset-WH1050",
149+
"msg_type", "Msg type", DATA_INT, msg_type,
150+
"id", "StationID", DATA_FORMAT, "%04X", DATA_INT, device_id,
151+
"battery_ok", "Battery", DATA_INT, !battery_low,
152+
"temperature_C", "Temperature", DATA_FORMAT, "%.01f C", DATA_DOUBLE, temperature,
153+
"humidity", "Humidity", DATA_FORMAT, "%u %%", DATA_INT, humidity,
154+
"wind_avg_km_h", "Wind avg speed", DATA_FORMAT, "%.02f", DATA_DOUBLE, speed,
155+
"wind_max_km_h", "Wind gust", DATA_FORMAT, "%.02f", DATA_DOUBLE, gust,
156+
"rain_mm", "Total rainfall", DATA_FORMAT, "%.01f", DATA_DOUBLE, rain,
157+
"mic", "Integrity", DATA_STRING, "CRC",
158+
NULL);
159+
/* clang-format on */
160+
}
161+
else {
162+
// GETTING TIME DATA
163+
int device_id = (br[0] << 4 & 0xf0) | (br[1] >> 4);
164+
int battery_low = br[1] & 0x04;
165+
int hours = ((br[2] & 0x30) >> 4) * 10 + (br[2] & 0x0F);
166+
int minutes = ((br[3] & 0xF0) >> 4) * 10 + (br[3] & 0x0F);
167+
int seconds = ((br[4] & 0xF0) >> 4) * 10 + (br[4] & 0x0F);
168+
int year = ((br[5] & 0xF0) >> 4) * 10 + (br[5] & 0x0F) + 2000;
169+
int month = ((br[6] & 0x10) >> 4) * 10 + (br[6] & 0x0F);
170+
int day = ((br[7] & 0xF0) >> 4) * 10 + (br[7] & 0x0F);
171+
172+
char clock_str[23];
173+
sprintf(clock_str, "%04d-%02d-%02dT%02d:%02d:%02d",
174+
year, month, day, hours, minutes, seconds);
175+
176+
/* clang-format off */
177+
data = data_make(
178+
"model", "", DATA_STRING, "Fineoffset-WH1050",
179+
"msg_type", "Msg type", DATA_INT, msg_type,
180+
"id", "Station ID", DATA_INT, device_id,
181+
"battery_ok", "Battery", DATA_INT, !battery_low,
182+
"radio_clock", "Radio Clock", DATA_STRING, clock_str,
183+
"mic", "Integrity", DATA_STRING, "CRC",
184+
NULL);
185+
/* clang-format on */
186+
}
118187

119188
decoder_output_data(decoder, data);
120189
return 1;
@@ -123,12 +192,14 @@ static int fineoffset_wh1050_callback(r_device *decoder, bitbuffer_t *bitbuffer)
123192
static char const *const output_fields[] = {
124193
"model",
125194
"id",
195+
"msg_type",
126196
"battery_ok",
127197
"temperature_C",
128198
"humidity",
129199
"wind_avg_km_h",
130200
"wind_max_km_h",
131201
"rain_mm",
202+
"radio_clock",
132203
"mic",
133204
NULL,
134205
};

0 commit comments

Comments
 (0)