Bugfixes
[rtl-433.git] / src / devices / nexus.c
1 /* Nexus sensor protocol with ID, temperature and optional humidity
2  * also FreeTec NC-7345 sensors for FreeTec Weatherstation NC-7344.
3  *
4  * the sensor sends 36 bits 12 times,
5  * the packets are ppm modulated (distance coding) with a pulse of ~500 us
6  * followed by a short gap of ~1000 us for a 0 bit or a long ~2000 us gap for a
7  * 1 bit, the sync gap is ~4000 us.
8  *
9  * the data is grouped in 9 nibbles
10  * [id0] [id1] [flags] [temp0] [temp1] [temp2] [const] [humi0] [humi1]
11  *
12  * The 8-bit id changes when the battery is changed in the sensor.
13  * flags are 4 bits B 0 C C, where B is the battery status: 1=OK, 0=LOW
14  * and CC is the channel: 0=CH1, 1=CH2, 2=CH3
15  * temp is 12 bit signed scaled by 10
16  * const is always 1111 (0x0F)
17  * humiditiy is 8 bits
18  *
19  * The sensor can be bought at Clas Ohlsen
20  */
21
22 #include "rtl_433.h"
23 #include "util.h"
24 #include "data.h"
25
26 extern int rubicson_crc_check(bitrow_t *bb);
27
28 static int nexus_callback(bitbuffer_t *bitbuffer) {
29     bitrow_t *bb = bitbuffer->bb;
30     data_t *data;
31
32     char time_str[LOCAL_TIME_BUFLEN];
33
34     if (debug_output > 1) {
35        fprintf(stderr,"Possible Nexus: ");
36        bitbuffer_print(bitbuffer);
37     }
38
39     uint8_t id;
40     uint8_t battery;
41     uint8_t channel;
42     int16_t temp;
43     uint8_t humidity;
44     int r = bitbuffer_find_repeated_row(bitbuffer, 3, 36);
45
46     /** The nexus protocol will trigger on rubicson data, so calculate the rubicson crc and make sure
47       * it doesn't match. By guesstimate it should generate a correct crc 1/255% of the times.
48       * So less then 0.5% which should be acceptable.
49       */
50     if (r >= 0 &&
51         bitbuffer->bits_per_row[r] <= 37 && // we expect 36 bits but there might be a trailing 0 bit
52         bb[r][0] != 0 &&
53         bb[r][2] != 0 &&
54         bb[r][3] != 0 &&
55         !rubicson_crc_check(bb)) {
56
57         /* Get time now */
58         local_time_str(0, time_str);
59
60         /* Nibble 0,1 contains id */
61         id = bb[r][0];
62
63         /* Nibble 2 is battery and channel */
64         battery = bb[r][1]&0x80;
65         channel = ((bb[r][1]&0x30) >> 4) + 1;
66
67         /* Nible 3,4,5 contains 12 bits of temperature
68          * The temerature is signed and scaled by 10 */
69         temp = (int16_t)((uint16_t)(bb[r][1] << 12) | (bb[r][2] << 4));
70         temp = temp >> 4;
71
72         /* Nibble 6,7 is humidity */
73         humidity = (uint8_t)(((bb[r][3]&0x0F)<<4)|(bb[r][4]>>4));
74
75         // Thermo
76         if (bb[r][3] == 0xF0) {
77         data = data_make("time",          "",            DATA_STRING, time_str,
78                          "model",         "",            DATA_STRING, "Nexus Temperature",
79                          "id",            "House Code",  DATA_INT, id,
80                          "battery",       "Battery",     DATA_STRING, battery ? "OK" : "LOW",
81                          "channel",       "Channel",     DATA_INT, channel,
82                          "temperature_C", "Temperature", DATA_FORMAT, "%.02f C", DATA_DOUBLE, temp/10.0,
83                          NULL);
84         data_acquired_handler(data);
85         }
86         // Thermo/Hygro
87         else {
88         data = data_make("time",          "",            DATA_STRING, time_str,
89                          "model",         "",            DATA_STRING, "Nexus Temperature/Humidity",
90                          "id",            "House Code",  DATA_INT, id,
91                          "battery",       "Battery",     DATA_STRING, battery ? "OK" : "LOW",
92                          "channel",       "Channel",     DATA_INT, channel,
93                          "temperature_C", "Temperature", DATA_FORMAT, "%.02f C", DATA_DOUBLE, temp/10.0,
94                          "humidity",      "Humidity",    DATA_FORMAT, "%u %%", DATA_INT, humidity,
95                          NULL);
96         data_acquired_handler(data);
97         }
98         return 1;
99     }
100     return 0;
101 }
102
103 static char *output_fields[] = {
104     "time",
105     "model",
106     "id",
107     "battery",
108     "channel",
109     "temperature_C",
110     "humidity",
111     NULL
112 };
113
114 r_device nexus = {
115     .name           = "Nexus Temperature & Humidity Sensor",
116     .modulation     = OOK_PULSE_PPM_RAW,
117     .short_limit    = 1744,
118     .long_limit     = 3500,
119     .reset_limit    = 5000,
120     .json_callback  = &nexus_callback,
121     .disabled       = 0,
122     .demod_arg      = 0,
123     .fields         = output_fields
124 };