X-Git-Url: https://git.rvb.name/rtl-433.git/blobdiff_plain/ca13278b24eb61443559bcb61e64627fba3d8823..6d15c6f967221af825cf84e3ed12b96c763b127b:/src/devices/oregon_scientific_sl109h.c diff --git a/src/devices/oregon_scientific_sl109h.c b/src/devices/oregon_scientific_sl109h.c new file mode 100644 index 0000000..b6f4c58 --- /dev/null +++ b/src/devices/oregon_scientific_sl109h.c @@ -0,0 +1,159 @@ +//some hints from http://www.osengr.org/WxShield/Downloads/OregonScientific-RF-Protocols-II.pdf + +#include "rtl_433.h" +#include "util.h" + +#define SL109H_MESSAGE_LENGTH 38 +#define CHECKSUM_BYTE_COUNT 4 +#define CHECKSUM_START_POSITION 6 +#define HUMIDITY_START_POSITION 6 +#define HUMIDITY_BIT_COUNT 8 +#define TEMPERATURE_START_POSITION 14 +#define TEMPERATURE_BIT_COUNT 12 +#define ID_START_POSITION 30 + +static uint8_t calculate_humidity(bitbuffer_t *bitbuffer, unsigned row_index) +{ + int units_digit, tens_digit; + + uint8_t out[1] = {0}; + bitbuffer_extract_bytes(bitbuffer, row_index, HUMIDITY_START_POSITION, out, HUMIDITY_BIT_COUNT); + + units_digit = out[0] & 0x0f; + + tens_digit = (out[0] & 0xf0) >> 4; + + return 10 * tens_digit + units_digit; +} + +static int calculate_centigrade_decidegrees(bitbuffer_t *bitbuffer, unsigned row_index) +{ + int decidegrees = 0; + + uint8_t out[2] = {0}; + bitbuffer_extract_bytes(bitbuffer, row_index, TEMPERATURE_START_POSITION, out, TEMPERATURE_BIT_COUNT); + + if(out[0] & 0x80) decidegrees = (~decidegrees << TEMPERATURE_BIT_COUNT); + + decidegrees |= (out[0] << 4) | ((out[1] & 0xf0) >> 4); + + return decidegrees; +} + +static uint8_t get_channel_bits(uint8_t first_byte) +{ + return (first_byte & 0x0c) >> 2; +} +static int calculate_channel(uint8_t channel_bits) +{ + return (channel_bits % 3) ? channel_bits : 3; +} + +//rolling code: changes when thermometer reset button is pushed/battery is changed +static uint8_t get_id(bitbuffer_t *bitbuffer, unsigned row_index) +{ + uint8_t out[1] = {0}; + bitbuffer_extract_bytes(bitbuffer, row_index, ID_START_POSITION, out, SL109H_MESSAGE_LENGTH - ID_START_POSITION); + + return out[0]; +} + +//there may be more specific information here; not currently certain what information is encoded here +static int get_status(uint8_t fourth_byte) +{ + return (fourth_byte & 0x3C) >> 2; +} + +static int calculate_checksum(bitbuffer_t *bitbuffer, unsigned row_index, int channel) +{ + uint8_t calculated_checksum, actual_checksum; + uint8_t sum = 0; + int actual_expected_comparison; + + uint8_t out[CHECKSUM_BYTE_COUNT] = {0}; + bitbuffer_extract_bytes(bitbuffer, row_index, CHECKSUM_START_POSITION, out, SL109H_MESSAGE_LENGTH - CHECKSUM_START_POSITION); + + for(int i = 0; i < CHECKSUM_BYTE_COUNT; i++) sum += (out[i] & 0x0f) + (out[i] >> 4); + + calculated_checksum = ((sum + channel) % 16); + actual_checksum = bitbuffer->bb[row_index][0] >> 4; + actual_expected_comparison = (calculated_checksum == actual_checksum); + + if(debug_output & !actual_expected_comparison) { + fprintf(stderr, "Checksum error in Oregon Scientific SL109H message. Expected: %01x Calculated: %01x\n", actual_checksum, calculated_checksum); + fprintf(stderr, "Message: "); + bitbuffer_print(bitbuffer); + } + + return actual_expected_comparison; +} + + +static int oregon_scientific_callback_sl109h(bitbuffer_t *bitbuffer) +{ + data_t *data; + uint8_t *msg; + uint8_t channel_bits; + + float temp_c; + uint8_t humidity; + int channel; + uint8_t id; + int status; + char time_str[LOCAL_TIME_BUFLEN]; + + for(int row_index = 0; row_index < bitbuffer->num_rows; row_index++) { + msg = bitbuffer->bb[row_index]; + + channel_bits = get_channel_bits(msg[0]); + + if( !((bitbuffer->bits_per_row[row_index] == SL109H_MESSAGE_LENGTH) + && calculate_checksum(bitbuffer, row_index, channel_bits)) ) continue; + + local_time_str(0, time_str); + + temp_c = calculate_centigrade_decidegrees(bitbuffer, row_index) / 10.0; + + humidity = calculate_humidity(bitbuffer, row_index); + + id = get_id(bitbuffer, row_index); + + channel = calculate_channel(channel_bits); + + status = get_status(msg[3]); + + data = data_make("time", "", DATA_STRING, time_str, + "temperature_C", "Celcius", DATA_FORMAT, "%.02f C", DATA_DOUBLE, temp_c, + "humidity", "Humidity", DATA_FORMAT, "%u %%", DATA_INT, humidity, + "channel", "Channel", DATA_INT, channel, + "id", "Id", DATA_INT, id, + "status", "Status", DATA_INT, status, + NULL); + data_acquired_handler(data); + return 1; + } + + return 0; +} + +static char *output_fields[] = { + "time", + "id", + "channel", + "status", + "temperature_C", + "humidity", + NULL +}; + +r_device oregon_scientific_sl109h = { + .name = "Oregon Scientific SL109H Remote Thermal Hygro Sensor", + .modulation = OOK_PULSE_PPM_RAW, + .short_limit = 2800/*760*/, + .long_limit = 4400/*1050*/, + .reset_limit = 8000/*2240*/, + .json_callback = &oregon_scientific_callback_sl109h, + .disabled = 0, + .demod_arg = 0, + .fields = output_fields +};