Merge pull request #94 from vestom/fineoffset

Added support for Fine Offset Electronics Temp/Humidity sensor
This commit is contained in:
Benjamin Larsson
2015-01-28 00:38:37 +01:00
6 changed files with 169 additions and 2 deletions

1
.gitignore vendored
View File

@@ -45,3 +45,4 @@ build/
.project
*.orig
*~

View File

@@ -35,9 +35,10 @@
#define BITBUF_ROWS 50
/* Supported modulation types */
#define OOK_PWM_D 1 /* Pulses are of the same length, the distance varies */
#define OOK_PWM_D 1 /* Pulses are of the same length, the distance varies (PPM) */
#define OOK_PWM_P 2 /* The length of the pulses varies */
#define OOK_MANCHESTER 3 /* Manchester code */
#define OOK_PWM_RAW 4 /* Pulse Width Modulation. No startbit removal. Short pulses = 1, Long = 0 */
typedef struct {
unsigned int id;

View File

@@ -17,5 +17,6 @@ extern r_device mebus433;
extern r_device intertechno;
extern r_device newkaku;
extern r_device alectov1;
extern r_device fineoffset_WH2;
#endif /* INCLUDE_RTL_433_DEVICES_H_ */

View File

@@ -30,7 +30,8 @@ add_executable(rtl_433
devices/mebus.c
devices/intertechno.c
devices/alecto.c
devices/newkaku.c)
devices/newkaku.c
devices/fineoffset.c)
target_link_libraries(rtl_433
${LIBRTLSDR_LIBRARIES}

110
src/devices/fineoffset.c Normal file
View File

@@ -0,0 +1,110 @@
/* Fine Offset Electronics sensor protocol
*
* The protocol is for the wireless Temperature/Humidity sensor
* Fine Offset Electronics WH2
* aka Agimex Rosenborg 66796 (sold in Denmark)
* aka ClimeMET CM9088 (Sold in UK)
* aka ...
*
* The sensor sends two identical packages of 48 bits each ~50s. The bits are PWM modulated with On Off Keying
*
* The data is grouped in 6 bytes / 12 nibbles
* [pre] [pre] [type] [id] [id] [temp] [temp] [temp] [humi] [humi] [crc] [crc]
*
* pre is always 0xFF
* type is always 0x4 (may be different for different sensor type?)
* id is a random id that is generated when the sensor starts
* temp is 12 bit signed magnitude scaled by 10 celcius
* humi is 8 bit relative humidity percentage
*
* Based on reverse engineering with gnu-radio and the nice article here:
* http://lucsmall.com/2012/04/29/weather-station-hacking-part-2/
*
* Copyright (C) 2015 Tommy Vestermark
* 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"
// Generic CRC-8
// (Should probably be moved to somewhere common)
// polynomial byte is from x^7 to x^0 (x^8 is implicitly one)
uint8_t crc8(uint8_t const message[], unsigned nBytes, uint8_t polynomial) {
uint8_t remainder = 0;
unsigned byte, bit;
for (byte = 0; byte < nBytes; ++byte) {
remainder ^= message[byte];
for (bit = 0; bit < 8; ++bit) {
if (remainder & 0x80) {
remainder = (remainder << 1) ^ polynomial;
}
else {
remainder = (remainder << 1);
}
}
}
return remainder;
}
static int fineoffset_WH2_callback(uint8_t bb[BITBUF_ROWS][BITBUF_COLS], int16_t bits_per_row[BITBUF_ROWS]) {
uint8_t ID;
float temperature;
float humidity;
const uint8_t polynomial = 0x31; // x8 + x5 + x4 + 1 (x8 is implicit)
// Validate package
if (bits_per_row[0] >= 48 && // Dont waste time on a short package
bb[0][0] == 0xFF && // Preamble
bb[0][5] == crc8(&bb[0][1], 4, polynomial) // CRC (excluding preamble)
)
{
// Nibble 3,4 contains ID
ID = ((bb[0][1]&0x0F) << 4) | ((bb[0][2]&0xF0) >> 4);
// Nible 5,6,7 contains 12 bits of temperature
// The temperature is signed magnitude and scaled by 10
int16_t temp;
temp = bb[0][3];
temp |= (int16_t)(bb[0][2] & 0x0F) << 8;
if(temp & 0x800) {
temp &= 0x7FF; // remove sign bit
temp = -temp; // reverse magnitude
}
temperature = (float)temp / 10;
// Nibble 8,9 contains humidity
humidity = bb[0][4];
fprintf(stderr, "Fine Offset Electronics, WH2:\n");
fprintf(stderr, "ID = 0x%2X\n", ID);
fprintf(stderr, "temperature = %.1f C\n", temperature);
fprintf(stderr, "humidity = %2.0f %%\n", humidity);
// fprintf(stderr, "raw = %02x %02x %02x %02x %02x %02x\n",bb[0][0],bb[0][1],bb[0][2],bb[0][3],bb[0][4],bb[0][5]);
if (debug_output)
debug_callback(bb, bits_per_row);
return 1;
}
return 0;
}
r_device fineoffset_WH2 = {
/* .id = */ 12,
/* .name = */ "Fine Offset Electronics, WH-2 Sensor",
/* .modulation = */ OOK_PWM_RAW,
/* .short_limit = */ 200, // Short pulse 136, long pulse 381, fixed gap 259
/* .long_limit = */ 700, // Maximum pulse period (long pulse + fixed gap)
/* .reset_limit = */ 700, // We just want 1 package
/* .json_callback = */ &fineoffset_WH2_callback,
};

View File

@@ -796,6 +796,55 @@ static void manchester_decode(struct dm_state *demod, struct protocol_state* p,
}
}
/* Pulse Width Modulation. No startbit removal */
static void pwm_raw_decode(struct dm_state *demod, struct protocol_state* p, int16_t *buf, uint32_t len) {
unsigned int i;
for (i = 0; i < len; i++) {
if (p->start_c) p->sample_counter++;
// Detect Pulse Start (leading edge)
if (!p->pulse_start && (buf[i] > demod->level_limit)) {
p->pulse_start = 1;
p->sample_counter = 0;
// Check for first bit in sequence
if(!p->start_c) {
p->start_c = 1;
}
}
// Detect Pulse End (trailing edge)
if (p->pulse_start && (buf[i] < demod->level_limit)) {
p->pulse_start = 0;
if (p->sample_counter <= p->short_limit) {
demod_add_bit(p, 1);
} else {
demod_add_bit(p, 0);
}
}
// Detect Pulse period overrun
if (p->sample_counter == p->long_limit) {
demod_next_bits_packet(p);
}
// Detect Pulse exceeding reset limit
if (p->sample_counter > p->reset_limit) {
p->sample_counter = 0;
p->start_c = 0;
p->pulse_start = 0;
if (p->callback)
events+=p->callback(p->bits_buffer, p->bits_per_row);
else
demod_print_bits_packet(p);
demod_reset_bits_packet(p);
}
}
}
/** Something that might look like a IIR lowpass filter
*
* [b,a] = butter(1, 0.01) -> quantizes nicely thus suitable for fixed point
@@ -874,6 +923,9 @@ static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx) {
case OOK_MANCHESTER:
manchester_decode(demod, demod->r_devs[i], demod->f_buf, len/2);
break;
case OOK_PWM_RAW:
pwm_raw_decode(demod, demod->r_devs[i], demod->f_buf, len / 2);
break;
default:
fprintf(stderr, "Unknown modulation %d in protocol!\n", demod->r_devs[i]->modulation);
}
@@ -1013,6 +1065,7 @@ int main(int argc, char **argv) {
register_protocol(demod, &alectov1);
register_protocol(demod, &intertechno);
register_protocol(demod, &mebus433);
register_protocol(demod, &fineoffset_WH2);
if (argc <= optind - 1) {
usage();