1 /** @file
2 WT450 wireless weather sensors protocol.
3
4 Tested devices:
5 WT260H
6 WT405H
7
8 Copyright (C) 2015 Tommy Vestermark
9 Copyright (C) 2015 Ladislav Foldyna
10
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
15 */
16
17 /**
18 source from:
19 http://ala-paavola.fi/jaakko/doku.php?id=wt450h
20
21 - The signal is FM encoded with clock cycle around 2000 µs
22 - No level shift within the clock cycle translates to a logic 0
23 - One level shift within the clock cycle translates to a logic 1
24 - Each clock cycle begins with a level shift
25 - My timing constants defined below are those observed by my program
26
27 +---+ +---+ +-------+ + high
28 | | | | | | |
29 | | | | | | |
30 + +---+ +---+ +-------+ low
31 ^ ^ ^ ^ ^ clock cycle
32 | 1 | 1 | 0 | 0 | translates as
33
34 Each transmission is 36 bits long (i.e. 72 ms).
35
36 Data is transmitted in pure binary values, NOT BCD-coded.
37
38 Outdoor sensor transmits data temperature, humidity.
39 Transmissions also include channel code and house code. The sensor transmits
40 every 60 seconds 3 packets.
41
42 1100 0001 | 0011 0011 | 1000 0011 | 1011 0011 | 0001
43 xxxx ssss | ccxx bhhh | hhhh tttt | tttt tttt | sseo
44
45 - x: constant
46 - s: House code
47 - c: Channel
48 - b: battery low indicator (0=>OK, 1=>LOW)
49 - h: Humidity
50 - t: Temperature, 12 bit, offset 50, scale 16
51 - s: sequence number of message repeat
52 - e: parity of all even bits
53 - o: parity of all odd bits
54 */
55
56 #include "decoder.h"
57
wt450_callback(r_device * decoder,bitbuffer_t * bitbuffer)58 static int wt450_callback(r_device *decoder, bitbuffer_t *bitbuffer)
59 {
60 uint8_t *b = bitbuffer->bb[0];
61 uint8_t humidity;
62 uint8_t temp_whole;
63 uint8_t temp_fraction;
64 uint8_t house_code;
65 uint8_t channel;
66 uint8_t battery_low;
67 int seq;
68 float temp;
69 uint8_t parity;
70 data_t *data;
71
72 if (bitbuffer->bits_per_row[0] != 36) {
73 if (decoder->verbose)
74 fprintf(stderr, "%s: wrong size of bit per row %d\n", __func__,
75 bitbuffer->bits_per_row[0]);
76 return DECODE_ABORT_LENGTH;
77 }
78
79 if (b[0]>>4 != 0xC) {
80 if (decoder->verbose)
81 bitbuffer_printf(bitbuffer, "%s: wrong preamble\n", __func__);
82 return DECODE_ABORT_EARLY;
83 }
84
85 parity = xor_bytes(b, 5);
86 parity ^= (parity >> 4);
87 parity ^= (parity >> 2);
88 parity &= 0x3;
89
90 if (parity) {
91 if (decoder->verbose)
92 bitbuffer_printf(bitbuffer, "%s: wrong parity (%x)\n", __func__, parity);
93 return DECODE_FAIL_MIC;
94 }
95
96 house_code = b[0] & 0xF;
97 channel = (b[1] >> 6) + 1;
98 battery_low = b[1] & 0x8;
99 humidity = ((b[1] & 0x7) << 4) | (b[2] >> 4);
100 temp_whole = (b[2] << 4) | (b[3] >> 4);
101 temp_fraction = (b[3] & 0xF);
102 temp = (temp_whole - 50) + (temp_fraction / 16.0);
103 seq = (b[4] >> 6);
104
105 /* clang-format off */
106 data = data_make(
107 "model", "", DATA_STRING, "WT450-TH",
108 "id", "House Code", DATA_INT, house_code,
109 "channel", "Channel", DATA_INT, channel,
110 "battery_ok", "Battery", DATA_INT, !battery_low,
111 "temperature_C", "Temperature", DATA_FORMAT, "%.02f C", DATA_DOUBLE, temp,
112 "humidity", "Humidity", DATA_FORMAT, "%u %%", DATA_INT, humidity,
113 "seq", "Sequence", DATA_INT, seq,
114 NULL);
115 /* clang-format on */
116
117 decoder_output_data(decoder, data);
118 return 1;
119 }
120
121 static char *output_fields[] = {
122 "model",
123 "id",
124 "channel",
125 "battery_ok",
126 "temperature_C",
127 "humidity",
128 "seq",
129 NULL,
130 };
131
132 r_device wt450 = {
133 .name = "WT450, WT260H, WT405H",
134 .modulation = OOK_PULSE_DMC,
135 .short_width = 976, // half-bit width 976 us
136 .long_width = 1952, // bit width 1952 us
137 .reset_limit = 18000,
138 .tolerance = 100, // us
139 .decode_fn = &wt450_callback,
140 .disabled = 0,
141 .fields = output_fields,
142 };
143