Bugfixes
[rtl-433.git] / src / devices / wt450.c
1 /* wt450 wireless weather sensors protocol
2  *
3  * Tested devices:
4  * WT260H
5  * WT405H
6  *
7  * Copyright (C) 2015 Tommy Vestermark
8  * Copyright (C) 2015 Ladislav Foldyna
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  */
14
15 /*
16  source from:
17  http://ala-paavola.fi/jaakko/doku.php?id=wt450h
18
19
20  The signal is FM encoded with clock cycle around 2000 µs
21  No level shift within the clock cycle translates to a logic 0
22  One level shift within the clock cycle translates to a logic 1
23  Each clock cycle begins with a level shift
24  My timing constants defined below are those observed by my program
25
26  +---+   +---+   +-------+       +  high
27  |   |   |   |   |       |       |
28  |   |   |   |   |       |       |
29  +   +---+   +---+       +-------+  low
30  ^       ^       ^       ^       ^  clock cycle
31  |   1   |   1   |   0   |   0   |  translates as
32
33  Each transmission is 36 bits long (i.e. 72 ms)
34
35  Data is transmitted in pure binary values, NOT BCD-coded.
36 */
37
38
39 /*
40  * Outdoor sensor transmits data temperature, humidity.
41  * Transmissions also include channel code and house code. The sensor transmits
42  * every 60 seconds 3 packets.
43  *
44  * 1100 0001 | 0011 0011 | 1000 0011 | 1011 0011 | 0001
45  * xxxx ssss | ccxx bhhh | hhhh tttt | tttt tttt | tttp
46  *
47  * x - constant
48  * s - House code
49  * c - Channel
50  * b - battery indicator (0=>OK, 1=>LOW)
51  * h - Humidity
52  * t - Temperature
53  * p - parity (xor of all bits should give 0)
54  */
55
56 #include "rtl_433.h"
57 #include "util.h"
58 #include "pulse_demod.h"
59 #include "data.h"
60
61 static int wt450_callback(bitbuffer_t *bitbuffer) {
62
63    bitrow_t *bb = bitbuffer->bb;
64    uint8_t *b = bb[0];
65
66    uint8_t humidity = 0;
67    uint8_t temp_whole = 0;
68    uint8_t temp_fraction = 0;
69    uint8_t house_code = 0;
70    uint8_t channel = 0;
71    uint8_t battery_low = 0;
72    float temp = 0;
73    uint8_t bit;
74    uint8_t parity = 0;
75
76    char time_str[LOCAL_TIME_BUFLEN];
77    data_t *data;
78    local_time_str(0, time_str);
79
80 //bitbuffer_print(bitbuffer);
81
82    if ( bitbuffer->bits_per_row[0] != 36 )
83    {
84       if (debug_output) 
85          fprintf(stderr, "%s wt450_callback: wrong size of bit per row %d\n",
86                  time_str, bitbuffer->bits_per_row[0] );
87
88       return 0;
89    }
90
91    if ( b[0]>>4 != 0xC )
92    {
93       if (debug_output)
94       {
95          fprintf(stderr, "%s wt450_callback: wrong preamble\n", time_str);
96          bitbuffer_print(bitbuffer);
97       }
98       return 0;
99    }
100
101    for ( bit = 0; bit < bitbuffer->bits_per_row[0]; bit++ )
102    {
103       parity ^= (b[bit/8] & (0x80 >> (bit % 8))) ? 1 : 0;
104    }
105
106    if ( parity )
107    {
108       if (debug_output)
109       {
110          fprintf(stderr, "%s wt450_callback: wrong parity\n", time_str);
111          bitbuffer_print(bitbuffer);
112       }
113       return 0;
114    }
115
116    house_code = b[0] & 0xF;
117    channel = (b[1] >> 6) + 1;
118    battery_low = b[1] & 0x8;
119    humidity = ((b[1] & 0x7) << 4) + (b[2] >> 4);
120    temp_whole = (b[2] << 4) + (b[3] >> 4);
121    temp_fraction = ((b[3] & 0xF) << 3) + (b[4] >> 5);
122    temp = (temp_whole - 50) + (temp_fraction/100.0);
123
124    data = data_make("time",          "",           DATA_STRING, time_str,
125                     "model",         "",           DATA_STRING, "WT450 sensor",
126                     "id",            "House Code", DATA_INT, house_code,
127                     "channel",       "Channel",    DATA_INT, channel,
128                     "battery",       "Battery",    DATA_STRING, battery_low ? "LOW" : "OK",
129                     "temperature_C", "Temperature",DATA_FORMAT, "%.02f C", DATA_DOUBLE, temp,
130                     "humidity",      "Humidity",   DATA_FORMAT, "%u %%", DATA_INT, humidity,
131                     NULL);
132    data_acquired_handler(data);
133
134    return 1;
135 }
136
137 PWM_Precise_Parameters clock_bits_parameters_generic = {
138    .pulse_tolerance     = 20,
139    .pulse_sync_width    = 0,    // No sync bit used
140 };
141
142 static char *output_fields[] = {
143         "time",
144         "model",
145         "id",
146         "channel",
147         "battery",
148         "temperature_C",
149         "humidity",
150         NULL
151 };
152
153 r_device wt450 = {
154    .name          = "WT450",
155    .modulation    = OOK_PULSE_CLOCK_BITS,
156    .short_limit   = 980,
157    .long_limit    = 1952,
158    .reset_limit   = 18000,
159    .json_callback = &wt450_callback,
160    .disabled      = 0,
161    .demod_arg     = (uintptr_t)&clock_bits_parameters_generic,
162    .fields        = output_fields
163 };