rtl_433/src/devices/bt_rain.c

109 lines
3.8 KiB
C

/** @file
Biltema-Rain sensor.
Copyright (C) 2017 Timopen, cleanup by Benjamin Larsson
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.
*/
/**
Biltema-Rain sensor.
Based on the springfield.c code, there is a lack of samples and data
thus the decoder is disabled by default.
- nibble[0] and nibble[1] is the id, changes with every reset.
- nibble[2] first bit is battery (0=OK).
- nibble[3] bit 1 is tx button pressed.
- nibble[3] bit 2 = below zero, subtract temperature with 1024. I.e. 11 bit 2's complement.
- nibble[3](bit 3 and 4) + nibble[4] + nibble[5] is the temperature in Celsius with one decimal.
- nibble[2](bit 2-4) + nibble[6] + nibble[7] is the rain rate, increases 25!? with every tilt of
the teeter (1.3 mm rain) after 82 tilts it starts over but carries the rest to the next round
e.g tilt 82 = 2 divide by 19.23 to get mm.
- nibble[8] is checksum, have not figured it out yet. Last bit is sync? or included in checksum?.
*/
#include "decoder.h"
// Actually 37 bits for all but last transmission which is 36 bits
#define NUM_BITS 36
static int bt_rain_decode(r_device *decoder, bitbuffer_t *bitbuffer)
{
data_t *data;
uint8_t *b;
int row;
int id, battery, rain, button, channel;
int temp_raw;
float temp_c, rainrate;
row = bitbuffer_find_repeated_row(bitbuffer, 4, NUM_BITS);
if (row < 0)
return DECODE_ABORT_EARLY;
if (bitbuffer->bits_per_row[row] != NUM_BITS && bitbuffer->bits_per_row[row] != NUM_BITS + 1)
return DECODE_ABORT_LENGTH;
b = bitbuffer->bb[row];
if (b[0] == 0xff && b[1] == 0xff && b[2] == 0xff && b[3] == 0xff)
return DECODE_FAIL_SANITY; // prevent false positive checksum
id = b[0];
battery = b[1] >> 7;
channel = ((b[1] & 0x30) >> 4) + 1; // either this or the rain top bits could be wrong
button = (b[1] & 0x08) >> 3;
temp_raw = (int16_t)(((b[1] & 0x07) << 13) | (b[2] << 5)); // uses sign extend
temp_c = (temp_raw >> 5) * 0.1f;
rain = ((b[1] & 0x07) << 4) | b[3]; // either b[1] or the channel above bould be wrong
int rest = rain % 25;
if (rest % 2)
rain += ((rest / 2) * 2048);
else
rain += ((rest + 1) / 2) * 2048 + 12 * 2048;
rainrate = rain * 0.052f; // 19.23mm per tip
/* clang-format off */
data = data_make(
"model", "", DATA_STRING, "Biltema-Rain",
"id", "ID", DATA_INT, id,
"channel", "Channel", DATA_INT, channel,
"battery_ok", "Battery", DATA_INT, !battery,
"transmit", "Transmit", DATA_STRING, button ? "MANUAL" : "AUTO", // TODO: delete this
"temperature_C", "Temperature", DATA_FORMAT, "%.1f C", DATA_DOUBLE, temp_c,
"rain_rate_mm_h", "Rain per hour", DATA_FORMAT, "%.2f mm/h", DATA_DOUBLE, rainrate,
"button", "Button", DATA_INT, button,
NULL);
/* clang-format on */
decoder_output_data(decoder, data);
return 1;
}
static char const *const output_fields[] = {
"model",
"id",
"channel",
"battery_ok",
"transmit", // TODO: delete this
"temperature_C",
"rain_rate_mm_h",
"button",
NULL,
};
r_device const bt_rain = {
.name = "Biltema rain gauge",
.modulation = OOK_PULSE_PPM,
.short_width = 1940,
.long_width = 3900,
.gap_limit = 4100,
.reset_limit = 8800,
.decode_fn = &bt_rain_decode,
.disabled = 1,
.fields = output_fields};