1 /* Bresser sensor protocol
 
   3  * The protocol is for the wireless Temperature/Humidity sensor
 
   4  * Bresser Thermo-/Hygro-Sensor 3CH
 
   6  * The sensor sends 15 identical packages of 40 bits each ~60s.
 
   7  * The bits are PWM modulated with On Off Keying.
 
   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.
 
  14  * The data is grouped in 5 bytes / 10 nibbles
 
  15  * [id] [id] [flags] [temp] [temp] [temp] [humi] [humi] [chk] [chk]
 
  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
 
  22  * Copyright (C) 2015 Christian W. Zuckschwerdt <zany@triq.net>
 
  25 #include "pulse_demod.h"
 
  29 static int bresser_3ch_callback(bitbuffer_t *bitbuffer) {
 
  30     bitrow_t *bb = bitbuffer->bb;
 
  32     char time_str[LOCAL_TIME_BUFLEN];
 
  34     int id, status, battery_low, test, channel, temp_raw, humidity;
 
  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
 
  41     int r = bitbuffer_find_repeated_row(bitbuffer, 3, 40);
 
  42     if (r < 0 || bitbuffer->bits_per_row[r] > 41) {
 
  53     if (((b[0] + b[1] + b[2] + b[3] - b[4]) & 0xFF) != 0) {
 
  55             fprintf(stderr, "Bresser 3CH checksum error\n");
 
  62     battery_low = (b[1] & 0x80) >> 7;
 
  63     test = (b[1] & 0x40) >> 6;
 
  64     channel = (b[1] & 0x30) >> 4;
 
  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;
 
  72     if ((channel == 0) || (humidity > 100) || (temp_f < -20.0) || (temp_f > 160.0)) {
 
  74             fprintf(stderr, "Bresser 3CH data error\n");
 
  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,
 
  88     data_acquired_handler(data);
 
  93 static char *output_fields[] = {
 
 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,
 
 113     .fields         = output_fields,