X-Git-Url: https://git.rvb.name/rtl-433.git/blobdiff_plain/ca13278b24eb61443559bcb61e64627fba3d8823..6d15c6f967221af825cf84e3ed12b96c763b127b:/src/devices/oil_watchman.c diff --git a/src/devices/oil_watchman.c b/src/devices/oil_watchman.c new file mode 100644 index 0000000..591e99b --- /dev/null +++ b/src/devices/oil_watchman.c @@ -0,0 +1,121 @@ +/* Oil tank monitor using Si4320 framed FSK protocol + * + * Tested devices: + * Sensor Systems Watchman Sonic + * + * Copyright © 2015 David Woodhouse + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#include "rtl_433.h" +#include "pulse_demod.h" +#include "util.h" + + +// Start of frame preamble is 111000xx +static const unsigned char preamble_pattern = 0xe0; + +// End of frame is 00xxxxxx or 11xxxxxx depending on final data bit +static const unsigned char postamble_pattern[2] = { 0x00, 0xc0 }; + +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 char *output_fields[] = { + "time", + "model", + "id", + "flags", + "maybetemp", + "temperature_C", + "binding_countdown", + "depth", + NULL +}; + +r_device oil_watchman = { + .name = "Watchman Sonic / Apollo Ultrasonic / Beckett Rocket oil tank monitor", + .modulation = FSK_PULSE_PCM, + .short_limit = 1000, + .long_limit = 1000, // NRZ + .reset_limit = 4000, + .json_callback = &oil_watchman_callback, + .disabled = 0, + .fields = output_fields, +};