static int oil_watchman_callback(bitbuffer_t *bitbuffer) { uint8_t *b; uint32_t unit_id; uint16_t depth = 0; uint16_t binding_countdown = 0; uint8_t flags; uint8_t maybetemp; double temperature; char time_str[LOCAL_TIME_BUFLEN]; data_t *data; unsigned bitpos = 0; bitbuffer_t databits = {0}; int events = 0; local_time_str(0, time_str); // Find a preamble with enough bits after it that it could be a complete packet while ((bitpos = bitbuffer_search(bitbuffer, 0, bitpos, &preamble_pattern, 6)) + 136 <= bitbuffer->bits_per_row[0]) { // Skip the matched preamble bits to point to the data bitpos += 6; bitpos = bitbuffer_manchester_decode(bitbuffer, 0, bitpos, &databits, 64); if (databits.bits_per_row[0] != 64) continue; b = databits.bb[0]; // Check for postamble, depending on last data bit if (bitbuffer_search(bitbuffer, 0, bitpos, &postamble_pattern[b[7] & 1], 2) != bitpos) continue; if (b[7] != crc8le(b, 7, 0x31, 0)) continue; // The unit ID changes when you rebind by holding a magnet to the // sensor for long enough; it seems to be time-based. unit_id = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]; // 0x01: Rebinding (magnet held to sensor) // 0x08: Leak/theft alarm // top three bits seem also to vary with temperature (independently of maybetemp) flags = b[4]; // Not entirely sure what this is but it might be inversely // proportional to temperature. maybetemp = b[5] >> 2; temperature = (double)(145.0 - 5.0 * maybetemp) / 3.0; if (flags & 1) // When binding, the countdown counts up from 0x51 to 0x5a // (as long as you hold the magnet to it for long enough) // before the device ID changes. The receiver unit needs // to receive this *strongly* in order to change its // allegiance. binding_countdown = b[6]; else // A depth reading of zero indicates no reading. Even with // the sensor flat down on a table, it still reads about 13. depth = ((b[5] & 3) << 8) | b[6]; data = data_make("time", "", DATA_STRING, time_str, "model", "", DATA_STRING, "Oil Watchman", "id", "", DATA_FORMAT, "%06x", DATA_INT, unit_id, "flags", "", DATA_FORMAT, "%02x", DATA_INT, flags, "maybetemp", "", DATA_INT, maybetemp, "temperature_C", "", DATA_DOUBLE, temperature, "binding_countdown", "", DATA_INT, binding_countdown, "depth", "", DATA_INT, depth, NULL); data_acquired_handler(data); events++; } return events; }
static int acurite_986_callback(bitbuffer_t *bitbuf) { int browlen; uint8_t *bb, sensor_num, status, crc, crcc; uint8_t br[8]; int8_t tempf; // Raw Temp is 8 bit signed Fahrenheit float tempc; uint16_t sensor_id, valid_cnt = 0; char sensor_type; local_time_str(0, time_str); if (debug_output > 1) { fprintf(stderr,"acurite_986\n"); bitbuffer_print(bitbuf); } 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; }