+ for (uint16_t brow = 0; brow < bitbuf->num_rows; ++brow) {
+ browlen = (bitbuf->bits_per_row[brow] + 7)/8;
+ bb = bitbuf->bb[brow];
+
+ if (debug_output > 1)
+ fprintf(stderr,"acurite_986: row %d bits %d, bytes %d \n", brow, bitbuf->bits_per_row[brow], browlen);
+
+ if (bitbuf->bits_per_row[brow] < 39 ||
+ bitbuf->bits_per_row[brow] > 43 ) {
+ if (debug_output > 1 && bitbuf->bits_per_row[brow] > 16)
+ fprintf(stderr,"acurite_986: skipping wrong len\n");
+ continue;
+ }
+
+ // Reduce false positives
+ // may eliminate these with a beter PPM (precise?) demod.
+ if ((bb[0] == 0xff && bb[1] == 0xff && bb[2] == 0xff) ||
+ (bb[0] == 0x00 && bb[1] == 0x00 && bb[2] == 0x00)) {
+ continue;
+ }
+
+ // There will be 1 extra false zero bit added by the demod.
+ // this forces an extra zero byte to be added
+ if (browlen > 5 && bb[browlen - 1] == 0)
+ browlen--;
+
+ // Reverse the bits
+ for (uint8_t i = 0; i < browlen; i++)
+ br[i] = reverse8(bb[i]);
+
+ if (debug_output > 0) {
+ fprintf(stderr,"Acurite 986 reversed: ");
+ for (uint8_t i = 0; i < browlen; i++)
+ fprintf(stderr," %02x",br[i]);
+ fprintf(stderr,"\n");
+ }
+
+ tempf = br[0];
+ sensor_id = (br[1] << 8) + br[2];
+ status = br[3];
+ sensor_num = (status & 0x01) + 1;
+ status = status >> 1;
+ // By default Sensor 1 is the Freezer, 2 Refrigerator
+ sensor_type = sensor_num == 2 ? 'F' : 'R';
+ crc = br[4];
+
+ if ((crcc = crc8le(br, 5, 0x07, 0)) != 0) {
+ // XXX make debug
+ if (debug_output) {
+ fprintf(stderr,"%s Acurite 986 sensor bad CRC: %02x -",
+ time_str, crc8le(br, 4, 0x07, 0));
+ for (uint8_t i = 0; i < browlen; i++)
+ fprintf(stderr," %02x", br[i]);
+ fprintf(stderr,"\n");
+ }
+ continue;
+ }
+
+ if ((status & 1) == 1) {
+ fprintf(stderr, "%s Acurite 986 sensor 0x%04x - %d%c: low battery, status %02x\n",
+ time_str, sensor_id, sensor_num, sensor_type, status);
+ }
+
+ // catch any status bits that haven't been decoded yet
+ if ((status & 0xFE) != 0) {
+ fprintf(stderr, "%s Acurite 986 sensor 0x%04x - %d%c: Unexpected status %02x\n",
+ time_str, sensor_id, sensor_num, sensor_type, status);
+ }
+
+ if (tempf & 0x80) {
+ tempf = (tempf & 0x7f) * -1;
+ }
+ tempc = fahrenheit2celsius(tempf);
+
+
+ printf("%s Acurite 986 sensor 0x%04x - %d%c: %3.1f C %d F\n",
+ time_str, sensor_id, sensor_num, sensor_type,
+ tempc, tempf);
+
+ valid_cnt++;
+
+ }
+
+ if (valid_cnt)
+ return 1;
+
+ return 0;
+}
+
+// Checksum code from
+// https://eclecticmusingsofachaoticmind.wordpress.com/2015/01/21/home-automation-temperature-sensors/
+// with modifications listed in
+// http://www.osengr.org/WxShield/Downloads/Weather-Sensor-RF-Protocols.pdf
+//
+// This is the same algorithm as used in ambient_weather.c
+//
+uint8_t Checksum(int length, uint8_t *buff) {
+ uint8_t mask = 0xd3;
+ uint8_t checksum = 0x00;
+ uint8_t data;
+ int byteCnt;
+
+ for (byteCnt = 0; byteCnt < length; byteCnt++) {
+ int bitCnt;
+ data = buff[byteCnt];
+
+ for (bitCnt = 7; bitCnt >= 0; bitCnt--) {
+ uint8_t bit;
+
+ // Rotate mask right
+ bit = mask & 1;
+ mask = (mask >> 1) | (mask << 7);
+ if (bit) {
+ mask ^= 0x18;
+ }
+
+ // XOR mask into checksum if data bit is 1
+ if (data & 0x80) {
+ checksum ^= mask;
+ }
+ data <<= 1;
+ }
+ }
+ return checksum;
+}
+
+
+static int acurite_606_callback(bitbuffer_t *bitbuf) {
+ data_t *data;
+ bitrow_t *bb = bitbuf->bb;
+ float temperature; // temperature in C
+ int16_t temp; // temperature as read from the data packet
+ int battery; // the battery status: 1 is good, 0 is low
+ int8_t sensor_id; // the sensor ID - basically a random number that gets reset whenever the battery is removed
+
+
+ local_time_str(0, time_str);
+
+ if (debug_output > 1) {
+ fprintf(stderr,"acurite_606\n");
+ bitbuffer_print(bitbuf);
+ }
+
+ // throw out all blank messages
+ if (bb[1][0] == 0 && bb[1][1] == 0 && bb[1][2] == 0 && bb[1][3] == 0)
+ return 0;
+
+ // do some basic checking to make sure we have a valid data record
+ if ((bb[0][0] == 0) && (bb[1][4] == 0)) { //This test may need some more scrutiny...
+ // calculate the checksum and only continue if we have a maching checksum
+ uint8_t chk = Checksum(3, &bb[1][0]);
+
+ if (chk == bb[1][3]) {
+ // Processing the temperature:
+ // Upper 4 bits are stored in nibble 1, lower 8 bits are stored in nibble 2
+ // upper 4 bits of nibble 1 are reserved for other usages (e.g. battery status)
+ temp = (int16_t)((uint16_t)(bb[1][1] << 12) | (bb[1][2] << 4));
+ temp = temp >> 4;
+
+ temperature = temp / 10.0;
+ sensor_id = bb[1][0];
+ battery = (bb[1][1] & 0x80) >> 7;
+
+ data = data_make("time", "", DATA_STRING, time_str,
+ "model", "", DATA_STRING, "Acurite 606TX Sensor",
+ "id", "", DATA_INT, sensor_id,
+ "battery", "Battery", DATA_STRING, battery ? "OK" : "LOW",
+ "temperature_C", "Temperature", DATA_FORMAT, "%.1f C", DATA_DOUBLE, temperature,
+ NULL);
+ data_acquired_handler(data);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+static int acurite_00275rm_callback(bitbuffer_t *bitbuf) {
+ int crc, battery_low, id, model, valid = 0;
+ uint8_t *bb;
+ data_t *data;
+ char *model1 = "00275rm", *model2 = "00276rm";
+ float tempc, ptempc;
+ uint8_t probe, humidity, phumidity, water;
+ uint8_t signal[3][11]; // Hold three copies of the signal
+ int nsignal = 0;
+
+ local_time_str(0, time_str);
+
+ if (debug_output > 1) {
+ fprintf(stderr,"acurite_00275rm\n");
+ bitbuffer_print(bitbuf);
+ }
+
+ // This sensor repeats signal three times. Store each copy.
+ for (uint16_t brow = 0; brow < bitbuf->num_rows; ++brow) {
+ if (bitbuf->bits_per_row[brow] != 88) continue;
+ if (nsignal>=3) continue;
+ memcpy(signal[nsignal], bitbuf->bb[brow], 11);
+ if (debug_output) {
+ fprintf(stderr,"acurite_00275rm: ");
+ for (int i=0; i<11; i++) fprintf(stderr," %02x",signal[nsignal][i]);
+ fprintf(stderr,"\n");
+ }
+ nsignal++;
+ }
+
+ // All three signals were found
+ if (nsignal==3) {
+ // Combine signal copies so that majority bit count wins
+ for (int i=0; i<11; i++) {
+ signal[0][i] =
+ (signal[0][i] & signal[1][i]) |
+ (signal[1][i] & signal[2][i]) |
+ (signal[2][i] & signal[0][i]);
+ }
+ // CRC check fails?
+ if ((crc=crc16(&(signal[0][0]), 11/*len*/, 0xb2/*poly*/, 0xd0/*seed*/)) != 0) {
+ if (debug_output) {
+ fprintf(stderr,"%s Acurite 00275rm sensor bad CRC: %02x -",
+ time_str, crc);
+ for (uint8_t i = 0; i < 11; i++)
+ fprintf(stderr," %02x", signal[0][i]);
+ fprintf(stderr,"\n");
+ }
+ // CRC is OK
+ } else {
+ // Decode the combined signal
+ id = (signal[0][0]<<16) | (signal[0][1]<<8) | signal[0][3];
+ battery_low = (signal[0][2] & 0x40)==0;
+ model = (signal[0][2] & 1);
+ tempc = 0.1 * ( (signal[0][4]<<4) | (signal[0][5]>>4) ) - 100;
+ probe = signal[0][5] & 3;
+ humidity = ((signal[0][6] & 0x1f) << 2) | (signal[0][7] >> 6);
+ // No probe
+ if (probe==0) {
+ data = data_make(
+ "time", "", DATA_STRING, time_str,
+ "model", "", DATA_STRING, model ? model1 : model2,
+ "probe", "", DATA_INT, probe,
+ "id", "", DATA_INT, id,
+ "battery", "", DATA_STRING, battery_low ? "LOW" : "OK",
+ "temperature_C", "Celcius", DATA_FORMAT, "%.1f C", DATA_DOUBLE, tempc,
+ "humidity", "Humidity", DATA_INT, humidity,
+ "crc", "", DATA_STRING, "ok",
+
+ NULL);
+ // Water probe (detects water leak)
+ } else if (probe==1) {
+ water = (signal[0][7] & 0x0f) == 15;
+ data = data_make(
+ "time", "", DATA_STRING, time_str,
+ "model", "", DATA_STRING, model ? model1 : model2,
+ "probe", "", DATA_INT, probe,
+ "id", "", DATA_INT, id,
+ "battery", "", DATA_STRING, battery_low ? "LOW" : "OK",
+ "temperature_C", "Celcius", DATA_FORMAT, "%.1f C", DATA_DOUBLE, tempc,
+ "humidity", "Humidity", DATA_INT, humidity,
+ "water", "", DATA_INT, water,
+ "crc", "", DATA_STRING, "ok",
+ NULL);
+ // Soil probe (detects temperature)
+ } else if (probe==2) {
+ ptempc = 0.1 * ( ((0x0f&signal[0][7])<<8) | signal[0][8] ) - 100;
+ data = data_make(
+ "time", "", DATA_STRING, time_str,
+ "model", "", DATA_STRING, model ? model1 : model2,
+ "probe", "", DATA_INT, probe,
+ "id", "", DATA_INT, id,
+ "battery", "", DATA_STRING, battery_low ? "LOW" : "OK",
+ "temperature_C", "Celcius", DATA_FORMAT, "%.1f C", DATA_DOUBLE, tempc,
+ "humidity", "Humidity", DATA_INT, humidity,
+ "ptemperature_C", "Celcius", DATA_FORMAT, "%.1f C", DATA_DOUBLE, ptempc,
+ "crc", "", DATA_STRING, "ok",
+ NULL);
+ // Spot probe (detects temperature and humidity)
+ } else if (probe==3) {
+ ptempc = 0.1 * ( ((0x0f&signal[0][7])<<8) | signal[0][8] ) - 100;
+ phumidity = signal[0][9] & 0x7f;
+ data = data_make(
+ "time", "", DATA_STRING, time_str,
+ "model", "", DATA_STRING, model ? model1 : model2,
+ "probe", "", DATA_INT, probe,
+ "id", "", DATA_INT, id,
+ "battery", "", DATA_STRING, battery_low ? "LOW" : "OK",
+ "temperature_C", "Celcius", DATA_FORMAT, "%.1f C", DATA_DOUBLE, tempc,
+ "humidity", "Humidity", DATA_INT, humidity,
+ "ptemperature_C", "Celcius", DATA_FORMAT, "%.1f C", DATA_DOUBLE, ptempc,
+ "phumidity", "Humidity", DATA_INT, phumidity,
+ "crc", "", DATA_STRING, "ok",
+ NULL);
+ }
+ data_acquired_handler(data);
+ valid=1;
+ }
+ }
+ if (valid) return 1;