1 /* Nexus sensor protocol with ID, temperature and optional humidity
2 * also FreeTec NC-7345 sensors for FreeTec Weatherstation NC-7344.
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.
9 * the data is grouped in 9 nibbles
10 * [id0] [id1] [flags] [temp0] [temp1] [temp2] [const] [humi0] [humi1]
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)
19 * The sensor can be bought at Clas Ohlsen
26 extern int rubicson_crc_check(bitrow_t *bb);
28 static int nexus_callback(bitbuffer_t *bitbuffer) {
29 bitrow_t *bb = bitbuffer->bb;
32 char time_str[LOCAL_TIME_BUFLEN];
34 if (debug_output > 1) {
35 fprintf(stderr,"Possible Nexus: ");
36 bitbuffer_print(bitbuffer);
44 int r = bitbuffer_find_repeated_row(bitbuffer, 3, 36);
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.
51 bitbuffer->bits_per_row[r] <= 37 && // we expect 36 bits but there might be a trailing 0 bit
55 !rubicson_crc_check(bb)) {
58 local_time_str(0, time_str);
60 /* Nibble 0,1 contains id */
63 /* Nibble 2 is battery and channel */
64 battery = bb[r][1]&0x80;
65 channel = ((bb[r][1]&0x30) >> 4) + 1;
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));
72 /* Nibble 6,7 is humidity */
73 humidity = (uint8_t)(((bb[r][3]&0x0F)<<4)|(bb[r][4]>>4));
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,
84 data_acquired_handler(data);
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,
96 data_acquired_handler(data);
103 static char *output_fields[] = {
115 .name = "Nexus Temperature & Humidity Sensor",
116 .modulation = OOK_PULSE_PPM_RAW,
120 .json_callback = &nexus_callback,
123 .fields = output_fields