X-Git-Url: https://git.rvb.name/rtl-433.git/blobdiff_plain/ca13278b24eb61443559bcb61e64627fba3d8823..6d15c6f967221af825cf84e3ed12b96c763b127b:/src/devices/nexus.c diff --git a/src/devices/nexus.c b/src/devices/nexus.c new file mode 100644 index 0000000..ea3a096 --- /dev/null +++ b/src/devices/nexus.c @@ -0,0 +1,124 @@ +/* Nexus sensor protocol with ID, temperature and optional humidity + * also FreeTec NC-7345 sensors for FreeTec Weatherstation NC-7344. + * + * the sensor sends 36 bits 12 times, + * the packets are ppm modulated (distance coding) with a pulse of ~500 us + * followed by a short gap of ~1000 us for a 0 bit or a long ~2000 us gap for a + * 1 bit, the sync gap is ~4000 us. + * + * the data is grouped in 9 nibbles + * [id0] [id1] [flags] [temp0] [temp1] [temp2] [const] [humi0] [humi1] + * + * The 8-bit id changes when the battery is changed in the sensor. + * flags are 4 bits B 0 C C, where B is the battery status: 1=OK, 0=LOW + * and CC is the channel: 0=CH1, 1=CH2, 2=CH3 + * temp is 12 bit signed scaled by 10 + * const is always 1111 (0x0F) + * humiditiy is 8 bits + * + * The sensor can be bought at Clas Ohlsen + */ + +#include "rtl_433.h" +#include "util.h" +#include "data.h" + +extern int rubicson_crc_check(bitrow_t *bb); + +static int nexus_callback(bitbuffer_t *bitbuffer) { + bitrow_t *bb = bitbuffer->bb; + data_t *data; + + char time_str[LOCAL_TIME_BUFLEN]; + + if (debug_output > 1) { + fprintf(stderr,"Possible Nexus: "); + bitbuffer_print(bitbuffer); + } + + uint8_t id; + uint8_t battery; + uint8_t channel; + int16_t temp; + uint8_t humidity; + int r = bitbuffer_find_repeated_row(bitbuffer, 3, 36); + + /** The nexus protocol will trigger on rubicson data, so calculate the rubicson crc and make sure + * it doesn't match. By guesstimate it should generate a correct crc 1/255% of the times. + * So less then 0.5% which should be acceptable. + */ + if (r >= 0 && + bitbuffer->bits_per_row[r] <= 37 && // we expect 36 bits but there might be a trailing 0 bit + bb[r][0] != 0 && + bb[r][2] != 0 && + bb[r][3] != 0 && + !rubicson_crc_check(bb)) { + + /* Get time now */ + local_time_str(0, time_str); + + /* Nibble 0,1 contains id */ + id = bb[r][0]; + + /* Nibble 2 is battery and channel */ + battery = bb[r][1]&0x80; + channel = ((bb[r][1]&0x30) >> 4) + 1; + + /* Nible 3,4,5 contains 12 bits of temperature + * The temerature is signed and scaled by 10 */ + temp = (int16_t)((uint16_t)(bb[r][1] << 12) | (bb[r][2] << 4)); + temp = temp >> 4; + + /* Nibble 6,7 is humidity */ + humidity = (uint8_t)(((bb[r][3]&0x0F)<<4)|(bb[r][4]>>4)); + + // Thermo + if (bb[r][3] == 0xF0) { + data = data_make("time", "", DATA_STRING, time_str, + "model", "", DATA_STRING, "Nexus Temperature", + "id", "House Code", DATA_INT, id, + "battery", "Battery", DATA_STRING, battery ? "OK" : "LOW", + "channel", "Channel", DATA_INT, channel, + "temperature_C", "Temperature", DATA_FORMAT, "%.02f C", DATA_DOUBLE, temp/10.0, + NULL); + data_acquired_handler(data); + } + // Thermo/Hygro + else { + data = data_make("time", "", DATA_STRING, time_str, + "model", "", DATA_STRING, "Nexus Temperature/Humidity", + "id", "House Code", DATA_INT, id, + "battery", "Battery", DATA_STRING, battery ? "OK" : "LOW", + "channel", "Channel", DATA_INT, channel, + "temperature_C", "Temperature", DATA_FORMAT, "%.02f C", DATA_DOUBLE, temp/10.0, + "humidity", "Humidity", DATA_FORMAT, "%u %%", DATA_INT, humidity, + NULL); + data_acquired_handler(data); + } + return 1; + } + return 0; +} + +static char *output_fields[] = { + "time", + "model", + "id", + "battery", + "channel", + "temperature_C", + "humidity", + NULL +}; + +r_device nexus = { + .name = "Nexus Temperature & Humidity Sensor", + .modulation = OOK_PULSE_PPM_RAW, + .short_limit = 1744, + .long_limit = 3500, + .reset_limit = 5000, + .json_callback = &nexus_callback, + .disabled = 0, + .demod_arg = 0, + .fields = output_fields +};