X-Git-Url: https://git.rvb.name/rtl-433.git/blobdiff_plain/ca13278b24eb61443559bcb61e64627fba3d8823..6d15c6f967221af825cf84e3ed12b96c763b127b:/src/devices/ambient_weather.c diff --git a/src/devices/ambient_weather.c b/src/devices/ambient_weather.c new file mode 100644 index 0000000..34f1578 --- /dev/null +++ b/src/devices/ambient_weather.c @@ -0,0 +1,193 @@ +#include "rtl_433.h" +#include "data.h" +#include "util.h" + +static float +get_temperature (uint8_t * msg) +{ + int temp_f = msg[4]; + temp_f <<= 4; + temp_f |= ((msg[5] & 0xf0) >> 4); + temp_f -= 400; + return (temp_f / 10.0f); +} + +static uint8_t +get_humidity (uint8_t * msg) +{ + uint8_t humidity = ( (msg[5] & 0x0f) << 4) | ((msg[6] & 0xf0) >> 4); + return humidity; +} + +static uint8_t +calculate_checksum (uint8_t *buff, int length) +{ + uint8_t mask = 0x7C; + uint8_t checksum = 0x64; + 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 +validate_checksum (uint8_t * msg, int len) +{ + uint8_t expected = ((msg[6] & 0x0f) << 4) | ((msg[7] & 0xf0) >> 4); + + uint8_t pkt[5]; + pkt[0] = ((msg[1] & 0x0f) << 4) | ((msg[2] & 0xf0) >> 4); + pkt[1] = ((msg[2] & 0x0f) << 4) | ((msg[3] & 0xf0) >> 4); + pkt[2] = ((msg[3] & 0x0f) << 4) | ((msg[4] & 0xf0) >> 4); + pkt[3] = ((msg[4] & 0x0f) << 4) | ((msg[5] & 0xf0) >> 4); + pkt[4] = ((msg[5] & 0x0f) << 4) | ((msg[6] & 0xf0) >> 4); + uint8_t calculated = calculate_checksum (pkt, 5); + + if (expected == calculated) + return 0; + else { + if (debug_output >= 1) { + fprintf(stderr, "Checksum error in Ambient Weather message. Expected: %02x Calculated: %02x\n", expected, calculated); + fprintf(stderr, "Message: "); int i; for (i=0; i> 4); + return deviceID; +} + +static uint16_t +get_channel (uint8_t * msg) +{ + uint16_t channel = (msg[3] & 0x07) + 1; + return channel; +} + +static uint8_t +get_battery_status(uint8_t * msg) +{ + uint8_t status = (msg[3] & 8) != 0; + return status; // if not zero, battery is low + +} + +static int +ambient_weather_parser (bitbuffer_t *bitbuffer) +{ + bitrow_t *bb = bitbuffer->bb; + float temperature; + uint8_t humidity; + uint16_t channel; + uint16_t deviceID; + uint8_t isBatteryLow; + + char time_str[LOCAL_TIME_BUFLEN]; + data_t *data; + local_time_str(0, time_str); + + if(bitbuffer->bits_per_row[0] != 195) // There seems to be 195 bits in a correct message + return 0; + + /* shift all the bits left 1 to align the fields */ + int i; + for (i = 0; i < BITBUF_COLS-1; i++) { + uint8_t bits1 = bb[0][i] << 1; + uint8_t bits2 = (bb[0][i+1] & 0x80) >> 7; + bits1 |= bits2; + bb[0][i] = bits1; + } + + /* DEBUG: print out the received packet */ + /* + fprintf(stderr, "\n! "); + for (i = 0 ; i < BITBUF_COLS ; i++) { + fprintf (stderr, "%02x ", bb[0][i]); + } + fprintf (stderr,"\n\n"); + */ + + if ( ((bb[0][0] == 0x00) && (bb[0][1] == 0x14) && (bb[0][2] & 0x50)) || + ((bb[0][0] == 0xff) && (bb[0][1] == 0xd4) && (bb[0][2] & 0x50)) ) { + + if (validate_checksum (bb[0], BITBUF_COLS)) { + return 0; + } + + temperature = get_temperature (bb[0]); + humidity = get_humidity (bb[0]); + channel = get_channel (bb[0]); + deviceID = get_device_id (bb[0]); + isBatteryLow = get_battery_status(bb[0]); + + data = data_make("time", "", DATA_STRING, time_str, + "model", "", DATA_STRING, "Ambient Weather F007TH Thermo-Hygrometer", + "device", "House Code", DATA_INT, deviceID, + "channel", "Channel", DATA_INT, channel, + "battery", "Battery", DATA_STRING, isBatteryLow ? "Low" : "Ok", + "temperature_F", "Temperature", DATA_FORMAT, "%.1f", DATA_DOUBLE, temperature, + "humidity", "Humidity", DATA_FORMAT, "%u %%", DATA_INT, humidity, + NULL); + data_acquired_handler(data); + + return 1; + } + + return 0; +} + +static int +ambient_weather_callback (bitbuffer_t *bitbuffer) +{ + return ambient_weather_parser (bitbuffer); +} + +static char *output_fields[] = { + "time", + "device", + "channel", + "temperature_F", + "humidity", + NULL +}; + +r_device ambient_weather = { + .name = "Ambient Weather Temperature Sensor", + .modulation = OOK_PULSE_MANCHESTER_ZEROBIT, + .short_limit = 500, + .long_limit = 0, // not used + .reset_limit = 2400, + .json_callback = &ambient_weather_callback, + .disabled = 0, + .demod_arg = 0, + .fields = output_fields +};