Bugfixes
[rtl-433.git] / src / devices / bresser_3ch.c
1 /* Bresser sensor protocol
2  *
3  * The protocol is for the wireless Temperature/Humidity sensor
4  * Bresser Thermo-/Hygro-Sensor 3CH
5  *
6  * The sensor sends 15 identical packages of 40 bits each ~60s.
7  * The bits are PWM modulated with On Off Keying.
8  *
9  * A short pulse of 250 us followed by a 500 us gap is a 0 bit,
10  * a long pulse of 500 us followed by a 250 us gap is a 1 bit,
11  * there is a sync preamble of pulse, gap, 750 us each, repeated 4 times.
12  * Actual received and demodulated timings might be 2% shorter.
13  *
14  * The data is grouped in 5 bytes / 10 nibbles
15  * [id] [id] [flags] [temp] [temp] [temp] [humi] [humi] [chk] [chk]
16  *
17  * id is an 8 bit random id that is generated when the sensor starts
18  * flags are 4 bits battery low indicator, test button press and channel
19  * temp is 12 bit unsigned fahrenheit offset by 90 and scaled by 10
20  * humi is 8 bit relative humidity percentage
21  *
22  * Copyright (C) 2015 Christian W. Zuckschwerdt <zany@triq.net>
23  */
24 #include "rtl_433.h"
25 #include "pulse_demod.h"
26 #include "util.h"
27 #include "data.h"
28
29 static int bresser_3ch_callback(bitbuffer_t *bitbuffer) {
30     bitrow_t *bb = bitbuffer->bb;
31     data_t *data;
32     char time_str[LOCAL_TIME_BUFLEN];
33
34     int id, status, battery_low, test, channel, temp_raw, humidity;
35     float temp_f;
36
37     /* note:
38        4 double wide sync pulses each go to an own row, the rows length will be
39        1 1 1 1 41 1 1 1 1 41 1 1 1 1 41 1 1 1 1 41 1 1 1 1 491
40      */
41     int r = bitbuffer_find_repeated_row(bitbuffer, 3, 40);
42     if (r < 0 || bitbuffer->bits_per_row[r] > 41) {
43         return 0;
44     }
45
46     uint8_t *b = bb[r];
47     b[0] = ~b[0];
48     b[1] = ~b[1];
49     b[2] = ~b[2];
50     b[3] = ~b[3];
51     b[4] = ~b[4];
52
53     if (((b[0] + b[1] + b[2] + b[3] - b[4]) & 0xFF) != 0) {
54         if (debug_output) {
55             fprintf(stderr, "Bresser 3CH checksum error\n");
56         }
57         return 0;
58     }
59
60     id = b[0];
61     status = b[1];
62     battery_low = (b[1] & 0x80) >> 7;
63     test = (b[1] & 0x40) >> 6;
64     channel = (b[1] & 0x30) >> 4;
65
66     temp_raw = ((b[1] & 0x0F) << 8) + b[2];
67     // 12 bits allows for values -90.0 F - 319.6 F (-67 C - 159 C)
68     temp_f = (temp_raw - 900) / 10.0;
69
70     humidity = b[3];
71
72     if ((channel == 0) || (humidity > 100) || (temp_f < -20.0) || (temp_f > 160.0)) {
73         if (debug_output) {
74             fprintf(stderr, "Bresser 3CH data error\n");
75         }
76         return 0;
77     }
78
79     local_time_str(0, time_str);
80     data = data_make("time",          "",            DATA_STRING, time_str,
81                      "model",         "",            DATA_STRING, "Bresser 3CH sensor",
82                      "id",            "",            DATA_INT, id,
83                      "channel",       "Channel",     DATA_INT, channel,
84                      "battery",       "Battery",     DATA_STRING, battery_low ? "LOW": "OK",
85                      "temperature_F", "Temperature", DATA_FORMAT, "%.2f F", DATA_DOUBLE, temp_f,
86                      "humidity",      "Humidity",    DATA_FORMAT, "%u %%", DATA_INT, humidity,
87                      NULL);
88     data_acquired_handler(data);
89
90     return 1;
91 }
92
93 static char *output_fields[] = {
94     "time",
95     "model",
96     "id",
97     "channel",
98     "battery",
99     "temperature_F",
100     "humidity",
101     NULL
102 };
103
104 r_device bresser_3ch = {
105     .name           = "Bresser Thermo-/Hygro-Sensor 3CH",
106     .modulation     = OOK_PULSE_PWM_RAW,
107     .short_limit    = 375,   // short pulse is ~250 us, long pulse is ~500 us
108     .long_limit     = 625,   // long gap (with short pulse) is ~500 us, sync gap is ~750 us
109     .reset_limit    = 1250,  // maximum gap is 1000 us (long gap + longer sync gap on last repeat)
110     .json_callback  = &bresser_3ch_callback,
111     .disabled       = 0,
112     .demod_arg      = 0,
113     .fields         = output_fields,
114 };