Merge pull request #219 from enavarro222/master
Fix bug with Oregeon Scientific outputs
This commit is contained in:
commit
c29463f5de
1 changed files with 302 additions and 302 deletions
|
@ -77,26 +77,27 @@ static int validate_os_checksum(unsigned char *msg, int checksum_nibble_idx) {
|
|||
unsigned int checksum, sum_of_nibbles=0;
|
||||
for (i=0; i<(checksum_nibble_idx-1);i+=2) {
|
||||
unsigned char val=msg[i>>1];
|
||||
sum_of_nibbles += ((val>>4) + (val &0x0f));
|
||||
sum_of_nibbles += ((val>>4) + (val &0x0f));
|
||||
}
|
||||
if (checksum_nibble_idx & 1) {
|
||||
sum_of_nibbles += (msg[checksum_nibble_idx>>1]>>4);
|
||||
checksum = (msg[checksum_nibble_idx>>1] & 0x0f) | (msg[(checksum_nibble_idx+1)>>1]&0xf0);
|
||||
} else
|
||||
checksum = (msg[checksum_nibble_idx>>1]>>4) | ((msg[checksum_nibble_idx>>1]&0x0f)<<4);
|
||||
sum_of_nibbles += (msg[checksum_nibble_idx>>1]>>4);
|
||||
checksum = (msg[checksum_nibble_idx>>1] & 0x0f) | (msg[(checksum_nibble_idx+1)>>1]&0xf0);
|
||||
} else {
|
||||
checksum = (msg[checksum_nibble_idx>>1]>>4) | ((msg[checksum_nibble_idx>>1]&0x0f)<<4);
|
||||
}
|
||||
sum_of_nibbles &= 0xff;
|
||||
|
||||
if (sum_of_nibbles == checksum)
|
||||
if (sum_of_nibbles == checksum) {
|
||||
return 0;
|
||||
else {
|
||||
} else {
|
||||
fprintf(stderr, "Checksum error in Oregon Scientific message. Expected: %02x Calculated: %02x\n", checksum, sum_of_nibbles);
|
||||
fprintf(stderr, "Message: "); int i; for (i=0 ;i<((checksum_nibble_idx+4)>>1) ; i++) fprintf(stdout, "%02x ", msg[i]); fprintf(stdout, "\n\n");
|
||||
return 1;
|
||||
fprintf(stderr, "Message: "); int i; for (i=0 ;i<((checksum_nibble_idx+4)>>1) ; i++) fprintf(stdout, "%02x ", msg[i]); fprintf(stdout, "\n\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int validate_os_v2_message(unsigned char * msg, int bits_expected, int valid_v2_bits_received,
|
||||
int nibbles_in_checksum) {
|
||||
int nibbles_in_checksum) {
|
||||
// Oregon scientific v2.1 protocol sends each bit using the complement of the bit, then the bit for better error checking. Compare number of valid bits processed vs number expected
|
||||
if (bits_expected == valid_v2_bits_received) {
|
||||
return (validate_os_checksum(msg, nibbles_in_checksum));
|
||||
|
@ -108,334 +109,333 @@ static int validate_os_v2_message(unsigned char * msg, int bits_expected, int va
|
|||
}
|
||||
|
||||
static int oregon_scientific_v2_1_parser(bitbuffer_t *bitbuffer) {
|
||||
bitrow_t *bb = bitbuffer->bb;
|
||||
// Check 2nd and 3rd bytes of stream for possible Oregon Scientific v2.1 sensor data (skip first byte to get past sync/startup bit errors)
|
||||
if ( ((bb[0][1] == 0x55) && (bb[0][2] == 0x55)) ||
|
||||
((bb[0][1] == 0xAA) && (bb[0][2] == 0xAA))) {
|
||||
int i,j;
|
||||
unsigned char msg[BITBUF_COLS] = {0};
|
||||
bitrow_t *bb = bitbuffer->bb;
|
||||
// Check 2nd and 3rd bytes of stream for possible Oregon Scientific v2.1 sensor data (skip first byte to get past sync/startup bit errors)
|
||||
if( ((bb[0][1] == 0x55) && (bb[0][2] == 0x55)) ||
|
||||
((bb[0][1] == 0xAA) && (bb[0][2] == 0xAA))) {
|
||||
int i,j;
|
||||
unsigned char msg[BITBUF_COLS] = {0};
|
||||
|
||||
// Possible v2.1 Protocol message
|
||||
int num_valid_v2_bits = 0;
|
||||
// Possible v2.1 Protocol message
|
||||
int num_valid_v2_bits = 0;
|
||||
|
||||
unsigned int sync_test_val = (bb[0][3]<<24) | (bb[0][4]<<16) | (bb[0][5]<<8) | (bb[0][6]);
|
||||
int dest_bit = 0;
|
||||
int pattern_index;
|
||||
// Could be extra/dropped bits in stream. Look for sync byte at expected position +/- some bits in either direction
|
||||
for(pattern_index=0; pattern_index<8; pattern_index++) {
|
||||
unsigned int mask = (unsigned int) (0xffff0000>>pattern_index);
|
||||
unsigned int pattern = (unsigned int)(0x55990000>>pattern_index);
|
||||
unsigned int pattern2 = (unsigned int)(0xaa990000>>pattern_index);
|
||||
unsigned int sync_test_val = (bb[0][3]<<24) | (bb[0][4]<<16) | (bb[0][5]<<8) | (bb[0][6]);
|
||||
int dest_bit = 0;
|
||||
int pattern_index;
|
||||
// Could be extra/dropped bits in stream. Look for sync byte at expected position +/- some bits in either direction
|
||||
for(pattern_index=0; pattern_index<8; pattern_index++) {
|
||||
unsigned int mask = (unsigned int) (0xffff0000>>pattern_index);
|
||||
unsigned int pattern = (unsigned int)(0x55990000>>pattern_index);
|
||||
unsigned int pattern2 = (unsigned int)(0xaa990000>>pattern_index);
|
||||
|
||||
//fprintf(stdout, "OS v2.1 sync byte search - test_val=%08x pattern=%08x mask=%08x\n", sync_test_val, pattern, mask);
|
||||
//fprintf(stdout, "OS v2.1 sync byte search - test_val=%08x pattern=%08x mask=%08x\n", sync_test_val, pattern, mask);
|
||||
|
||||
if (((sync_test_val & mask) == pattern) ||
|
||||
((sync_test_val & mask) == pattern2)) {
|
||||
// Found sync byte - start working on decoding the stream data.
|
||||
// pattern_index indicates where sync nibble starts, so now we can find the start of the payload
|
||||
int start_byte = 5 + (pattern_index>>3);
|
||||
int start_bit = pattern_index & 0x07;
|
||||
//fprintf(stdout, "OS v2.1 Sync test val %08x found, starting decode at byte index %d bit %d\n", sync_test_val, start_byte, start_bit);
|
||||
int bits_processed = 0;
|
||||
unsigned char last_bit_val = 0;
|
||||
j=start_bit;
|
||||
for (i=start_byte;i<BITBUF_COLS;i++) {
|
||||
while (j<8) {
|
||||
if (bits_processed & 0x01) {
|
||||
unsigned char bit_val = ((bb[0][i] & (0x80 >> j)) >> (7-j));
|
||||
if (((sync_test_val & mask) == pattern) ||
|
||||
((sync_test_val & mask) == pattern2)) {
|
||||
// Found sync byte - start working on decoding the stream data.
|
||||
// pattern_index indicates where sync nibble starts, so now we can find the start of the payload
|
||||
int start_byte = 5 + (pattern_index>>3);
|
||||
int start_bit = pattern_index & 0x07;
|
||||
//fprintf(stdout, "OS v2.1 Sync test val %08x found, starting decode at byte index %d bit %d\n", sync_test_val, start_byte, start_bit);
|
||||
int bits_processed = 0;
|
||||
unsigned char last_bit_val = 0;
|
||||
j=start_bit;
|
||||
for (i=start_byte;i<BITBUF_COLS;i++) {
|
||||
while (j<8) {
|
||||
if (bits_processed & 0x01) {
|
||||
unsigned char bit_val = ((bb[0][i] & (0x80 >> j)) >> (7-j));
|
||||
|
||||
// check if last bit received was the complement of the current bit
|
||||
if ((num_valid_v2_bits == 0) && (last_bit_val == bit_val))
|
||||
num_valid_v2_bits = bits_processed; // record position of first bit in stream that doesn't verify correctly
|
||||
last_bit_val = bit_val;
|
||||
// check if last bit received was the complement of the current bit
|
||||
if ((num_valid_v2_bits == 0) && (last_bit_val == bit_val))
|
||||
num_valid_v2_bits = bits_processed; // record position of first bit in stream that doesn't verify correctly
|
||||
last_bit_val = bit_val;
|
||||
|
||||
// copy every other bit from source stream to dest packet
|
||||
msg[dest_bit>>3] |= (((bb[0][i] & (0x80 >> j)) >> (7-j)) << (7-(dest_bit & 0x07)));
|
||||
// copy every other bit from source stream to dest packet
|
||||
msg[dest_bit>>3] |= (((bb[0][i] & (0x80 >> j)) >> (7-j)) << (7-(dest_bit & 0x07)));
|
||||
|
||||
//fprintf(stdout,"i=%d j=%d dest_bit=%02x bb=%02x msg=%02x\n",i, j, dest_bit, bb[0][i], msg[dest_bit>>3]);
|
||||
if ((dest_bit & 0x07) == 0x07) {
|
||||
// after assembling each dest byte, flip bits in each nibble to convert from lsb to msb bit ordering
|
||||
int k = (dest_bit>>3);
|
||||
unsigned char indata = msg[k];
|
||||
// flip the 4 bits in the upper and lower nibbles
|
||||
msg[k] = ((indata & 0x11) << 3) | ((indata & 0x22) << 1) |
|
||||
((indata & 0x44) >> 1) | ((indata & 0x88) >> 3);
|
||||
}
|
||||
dest_bit++;
|
||||
}
|
||||
else
|
||||
last_bit_val = ((bb[0][i] & (0x80 >> j)) >> (7-j)); // used for v2.1 bit error detection
|
||||
bits_processed++;
|
||||
j++;
|
||||
}
|
||||
j=0;
|
||||
}
|
||||
break;
|
||||
} //if (sync_test_val...
|
||||
} // for (pattern...
|
||||
//fprintf(stdout,"i=%d j=%d dest_bit=%02x bb=%02x msg=%02x\n",i, j, dest_bit, bb[0][i], msg[dest_bit>>3]);
|
||||
if ((dest_bit & 0x07) == 0x07) {
|
||||
// after assembling each dest byte, flip bits in each nibble to convert from lsb to msb bit ordering
|
||||
int k = (dest_bit>>3);
|
||||
unsigned char indata = msg[k];
|
||||
// flip the 4 bits in the upper and lower nibbles
|
||||
msg[k] = ((indata & 0x11) << 3) | ((indata & 0x22) << 1) |
|
||||
((indata & 0x44) >> 1) | ((indata & 0x88) >> 3);
|
||||
}
|
||||
dest_bit++;
|
||||
} else {
|
||||
last_bit_val = ((bb[0][i] & (0x80 >> j)) >> (7-j)); // used for v2.1 bit error detection
|
||||
}
|
||||
bits_processed++;
|
||||
j++;
|
||||
}
|
||||
j=0;
|
||||
}
|
||||
break;
|
||||
} //if (sync_test_val...
|
||||
} // for (pattern...
|
||||
|
||||
data_t *data;
|
||||
time_t time_now;
|
||||
char time_str[LOCAL_TIME_BUFLEN];
|
||||
time(&time_now);
|
||||
local_time_str(time_now, time_str);
|
||||
data_t *data;
|
||||
time_t time_now;
|
||||
char time_str[LOCAL_TIME_BUFLEN];
|
||||
time(&time_now);
|
||||
local_time_str(time_now, time_str);
|
||||
|
||||
int sensor_id = (msg[0] << 8) | msg[1];
|
||||
if ((sensor_id == 0x1d20) || (sensor_id == 0x1d30)) {
|
||||
if (validate_os_v2_message(msg, 153, num_valid_v2_bits, 15) == 0) {
|
||||
if ((sensor_id == 0x1d20) || (sensor_id == 0x1d30)) {
|
||||
if (validate_os_v2_message(msg, 153, num_valid_v2_bits, 15) == 0) {
|
||||
|
||||
if (sensor_id == 0x1d20) {
|
||||
data = data_make("time", "", DATA_STRING, time_str,
|
||||
"model", "", DATA_STRING, "Weather Sensor THGR122N",
|
||||
"id" "House Code", DATA_INT, get_os_rollingcode(msg, sensor_id),
|
||||
"channel", "Channel", DATA_INT, get_os_channel(msg, sensor_id),
|
||||
"battery", "Battery", DATA_STRING, get_os_battery(msg, sensor_id) ? "LOW" : "OK",
|
||||
"temperature_C", "Temperature", DATA_FORMAT, "%.02f C", DATA_DOUBLE, get_os_temperature(msg, sensor_id),
|
||||
"humidity", "Humidity", DATA_FORMAT, "%u %%", DATA_INT, get_os_humidity(msg, sensor_id),
|
||||
NULL);
|
||||
data_acquired_handler(data);
|
||||
}
|
||||
else {
|
||||
data = data_make("time", "", DATA_STRING, time_str,
|
||||
"model", "", DATA_STRING, "Weather Sensor THGR968 Outdoor",
|
||||
"id" "House Code", DATA_INT, get_os_rollingcode(msg, sensor_id),
|
||||
"channel", "Channel", DATA_INT, get_os_channel(msg, sensor_id),
|
||||
"battery", "Battery", DATA_STRING, get_os_battery(msg, sensor_id) ? "LOW" : "OK",
|
||||
"temperature_C", "Temperature", DATA_FORMAT, "%.02f C", DATA_DOUBLE, get_os_temperature(msg, sensor_id),
|
||||
"humidity", "Humidity", DATA_FORMAT, "%u %%", DATA_INT, get_os_humidity(msg, sensor_id),
|
||||
NULL);
|
||||
data_acquired_handler(data);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
if (sensor_id == 0x1d20) {
|
||||
data = data_make("time", "", DATA_STRING, time_str,
|
||||
"model", "", DATA_STRING, "Weather Sensor THGR122N",
|
||||
"id", "House Code", DATA_INT, get_os_rollingcode(msg, sensor_id),
|
||||
"channel", "Channel", DATA_INT, get_os_channel(msg, sensor_id),
|
||||
"battery", "Battery", DATA_STRING, get_os_battery(msg, sensor_id) ? "LOW" : "OK",
|
||||
"temperature_C", "Temperature", DATA_FORMAT, "%.02f C", DATA_DOUBLE, get_os_temperature(msg, sensor_id),
|
||||
"humidity", "Humidity", DATA_FORMAT, "%u %%", DATA_INT, get_os_humidity(msg, sensor_id),
|
||||
NULL);
|
||||
data_acquired_handler(data);
|
||||
} else {
|
||||
data = data_make("time", "", DATA_STRING, time_str,
|
||||
"model", "", DATA_STRING, "Weather Sensor THGR968 Outdoor",
|
||||
"id", "House Code", DATA_INT, get_os_rollingcode(msg, sensor_id),
|
||||
"channel", "Channel", DATA_INT, get_os_channel(msg, sensor_id),
|
||||
"battery", "Battery", DATA_STRING, get_os_battery(msg, sensor_id) ? "LOW" : "OK",
|
||||
"temperature_C", "Temperature", DATA_FORMAT, "%.02f C", DATA_DOUBLE, get_os_temperature(msg, sensor_id),
|
||||
"humidity", "Humidity", DATA_FORMAT, "%u %%", DATA_INT, get_os_humidity(msg, sensor_id),
|
||||
NULL);
|
||||
data_acquired_handler(data);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
} else if (sensor_id == 0x5d60) {
|
||||
if (validate_os_v2_message(msg, 185, num_valid_v2_bits, 19) == 0) {
|
||||
unsigned int comfort = msg[7] >>4;
|
||||
char *comfort_str="Normal";
|
||||
if (comfort == 4) comfort_str = "Comfortable";
|
||||
else if (comfort == 8) comfort_str = "Dry";
|
||||
else if (comfort == 0xc) comfort_str = "Humid";
|
||||
unsigned int forecast = msg[9]>>4;
|
||||
char *forecast_str="Cloudy";
|
||||
if (forecast == 3) forecast_str = "Rainy";
|
||||
else if (forecast == 6) forecast_str = "Partly Cloudy";
|
||||
else if (forecast == 0xc) forecast_str = "Sunny";
|
||||
float temp_c = get_os_temperature(msg, 0x5d60);
|
||||
fprintf(stdout,"Weather Sensor BHTR968 Indoor Temp: %3.1fC %3.1fF Humidity: %d%%", temp_c, ((temp_c*9)/5)+32, get_os_humidity(msg, 0x5d60));
|
||||
fprintf(stdout, " (%s) Pressure: %dmbar (%s)\n", comfort_str, ((msg[7] & 0x0f) | (msg[8] & 0xf0))+856, forecast_str);
|
||||
}
|
||||
return 1;
|
||||
} else if (sensor_id == 0x2d10) {
|
||||
if (validate_os_v2_message(msg, 161, num_valid_v2_bits, 16) == 0) {
|
||||
float rain_rate = (((msg[4] &0x0f)*100)+((msg[4]>>4)*10) + ((msg[5]>>4)&0x0f)) /10.0F;
|
||||
float total_rain = (((msg[7]&0xf)*10000)+((msg[7]>>4)*1000) + ((msg[6]&0xf)*100)+((msg[6]>>4)*10) + (msg[5]&0xf))/10.0F;
|
||||
if (validate_os_v2_message(msg, 185, num_valid_v2_bits, 19) == 0) {
|
||||
unsigned int comfort = msg[7] >>4;
|
||||
char *comfort_str="Normal";
|
||||
if (comfort == 4) comfort_str = "Comfortable";
|
||||
else if (comfort == 8) comfort_str = "Dry";
|
||||
else if (comfort == 0xc) comfort_str = "Humid";
|
||||
unsigned int forecast = msg[9]>>4;
|
||||
char *forecast_str="Cloudy";
|
||||
if (forecast == 3) forecast_str = "Rainy";
|
||||
else if (forecast == 6) forecast_str = "Partly Cloudy";
|
||||
else if (forecast == 0xc) forecast_str = "Sunny";
|
||||
float temp_c = get_os_temperature(msg, 0x5d60);
|
||||
fprintf(stdout,"Weather Sensor BHTR968 Indoor Temp: %3.1fC %3.1fF Humidity: %d%%", temp_c, ((temp_c*9)/5)+32, get_os_humidity(msg, 0x5d60));
|
||||
fprintf(stdout, " (%s) Pressure: %dmbar (%s)\n", comfort_str, ((msg[7] & 0x0f) | (msg[8] & 0xf0))+856, forecast_str);
|
||||
}
|
||||
return 1;
|
||||
} else if (sensor_id == 0x2d10) {
|
||||
if (validate_os_v2_message(msg, 161, num_valid_v2_bits, 16) == 0) {
|
||||
float rain_rate = (((msg[4] &0x0f)*100)+((msg[4]>>4)*10) + ((msg[5]>>4)&0x0f)) /10.0F;
|
||||
float total_rain = (((msg[7]&0xf)*10000)+((msg[7]>>4)*1000) + ((msg[6]&0xf)*100)+((msg[6]>>4)*10) + (msg[5]&0xf))/10.0F;
|
||||
|
||||
data = data_make("time", "", DATA_STRING, time_str,
|
||||
"model", "", DATA_STRING, "Weather Sensor RGR968 Rain Gauge",
|
||||
"id" "House Code", DATA_INT, get_os_rollingcode(msg, sensor_id),
|
||||
"channel", "Channel", DATA_INT, get_os_channel(msg, sensor_id),
|
||||
"battery", "Battery", DATA_STRING, get_os_battery(msg, sensor_id) ? "LOW" : "OK",
|
||||
"rain_rate", "Rain Rate", DATA_FORMAT, "%.02f mm/hr", DATA_DOUBLE, rain_rate,
|
||||
"rain_total", "Total Rain", DATA_FORMAT, "%.02f mm", DATA_DOUBLE, total_rain,
|
||||
NULL);
|
||||
data_acquired_handler(data);
|
||||
}
|
||||
return 1;
|
||||
} else if (sensor_id == 0xec40 && num_valid_v2_bits==153) {
|
||||
if (validate_os_v2_message(msg, 153, num_valid_v2_bits, 12) == 0) {
|
||||
data = data_make("time", "", DATA_STRING, time_str,
|
||||
"model", "", DATA_STRING, "Weather Sensor RGR968 Rain Gauge",
|
||||
"id", "House Code", DATA_INT, get_os_rollingcode(msg, sensor_id),
|
||||
"channel", "Channel", DATA_INT, get_os_channel(msg, sensor_id),
|
||||
"battery", "Battery", DATA_STRING, get_os_battery(msg, sensor_id) ? "LOW" : "OK",
|
||||
"rain_rate", "Rain Rate", DATA_FORMAT, "%.02f mm/hr", DATA_DOUBLE, rain_rate,
|
||||
"rain_total", "Total Rain", DATA_FORMAT, "%.02f mm", DATA_DOUBLE, total_rain,
|
||||
NULL);
|
||||
data_acquired_handler(data);
|
||||
}
|
||||
return 1;
|
||||
} else if (sensor_id == 0xec40 && num_valid_v2_bits==153) {
|
||||
if (validate_os_v2_message(msg, 153, num_valid_v2_bits, 12) == 0) {
|
||||
|
||||
data = data_make("time", "", DATA_STRING, time_str,
|
||||
"model", "", DATA_STRING, "Thermo Sensor THR228N",
|
||||
"id" "House Code", DATA_INT, get_os_rollingcode(msg, sensor_id),
|
||||
"channel", "Channel", DATA_INT, get_os_channel(msg, sensor_id),
|
||||
"battery", "Battery", DATA_STRING, get_os_battery(msg, sensor_id) ? "LOW" : "OK",
|
||||
"temperature_C", "Temperature", DATA_FORMAT, "%.02f C", DATA_DOUBLE, get_os_temperature(msg, sensor_id),
|
||||
NULL);
|
||||
data_acquired_handler(data);
|
||||
}
|
||||
return 1;
|
||||
} else if (sensor_id == 0xec40 && num_valid_v2_bits==129) {
|
||||
if (validate_os_v2_message(msg, 129, num_valid_v2_bits, 12) == 0) {
|
||||
data = data_make("time", "", DATA_STRING, time_str,
|
||||
"model", "", DATA_STRING, "Thermo Sensor THR228N",
|
||||
"id", "House Code", DATA_INT, get_os_rollingcode(msg, sensor_id),
|
||||
"channel", "Channel", DATA_INT, get_os_channel(msg, sensor_id),
|
||||
"battery", "Battery", DATA_STRING, get_os_battery(msg, sensor_id) ? "LOW" : "OK",
|
||||
"temperature_C", "Temperature", DATA_FORMAT, "%.02f C", DATA_DOUBLE, get_os_temperature(msg, sensor_id),
|
||||
NULL);
|
||||
data_acquired_handler(data);
|
||||
}
|
||||
return 1;
|
||||
} else if (sensor_id == 0xec40 && num_valid_v2_bits==129) {
|
||||
if (validate_os_v2_message(msg, 129, num_valid_v2_bits, 12) == 0) {
|
||||
|
||||
data = data_make("time", "", DATA_STRING, time_str,
|
||||
"model", "", DATA_STRING, "Thermo Sensor THN132N",
|
||||
"id" "House Code", DATA_INT, get_os_rollingcode(msg, sensor_id),
|
||||
"channel", "Channel", DATA_INT, get_os_channel(msg, sensor_id),
|
||||
"battery", "Battery", DATA_STRING, get_os_battery(msg, sensor_id) ? "LOW" : "OK",
|
||||
"temperature_C", "Temperature", DATA_FORMAT, "%.02f C", DATA_DOUBLE, get_os_temperature(msg, sensor_id),
|
||||
NULL);
|
||||
data_acquired_handler(data);
|
||||
}
|
||||
return 1;
|
||||
} else if ((sensor_id >= 0x0cc3) && (sensor_id <= 0xfcc3)) {
|
||||
if (num_valid_v2_bits==153 && (validate_os_v2_message(msg, 153, num_valid_v2_bits, 15) == 0)) {
|
||||
data = data_make("time", "", DATA_STRING, time_str,
|
||||
"model", "", DATA_STRING, "Thermo Sensor THN132N",
|
||||
"id", "House Code", DATA_INT, get_os_rollingcode(msg, sensor_id),
|
||||
"channel", "Channel", DATA_INT, get_os_channel(msg, sensor_id),
|
||||
"battery", "Battery", DATA_STRING, get_os_battery(msg, sensor_id) ? "LOW" : "OK",
|
||||
"temperature_C", "Temperature", DATA_FORMAT, "%.02f C", DATA_DOUBLE, get_os_temperature(msg, sensor_id),
|
||||
NULL);
|
||||
data_acquired_handler(data);
|
||||
}
|
||||
return 1;
|
||||
} else if ((sensor_id >= 0x0cc3) && (sensor_id <= 0xfcc3)) {
|
||||
if (num_valid_v2_bits==153 && (validate_os_v2_message(msg, 153, num_valid_v2_bits, 15) == 0)) {
|
||||
|
||||
data = data_make("time", "", DATA_STRING, time_str,
|
||||
"model", "", DATA_STRING, "Thermo Hygro RF Clock Sensor RTGN318",
|
||||
"id" "House Code", DATA_INT, get_os_rollingcode(msg, sensor_id),
|
||||
"channel", "Channel", DATA_INT, get_os_channel(msg, sensor_id), // 1 to 5
|
||||
"battery", "Battery", DATA_STRING, get_os_battery(msg, sensor_id) ? "LOW" : "OK",
|
||||
"temperature_C", "Temperature", DATA_FORMAT, "%.02f C", DATA_DOUBLE, get_os_temperature(msg, sensor_id),
|
||||
"humidity", "Humidity", DATA_FORMAT, "%u %%", DATA_INT, get_os_humidity(msg, sensor_id),
|
||||
NULL);
|
||||
data_acquired_handler(data);
|
||||
} else if (num_valid_v2_bits==201 && (validate_os_v2_message(msg, 201, num_valid_v2_bits, 21) == 0)) {
|
||||
data = data_make("time", "", DATA_STRING, time_str,
|
||||
"model", "", DATA_STRING, "Thermo Hygro RF Clock Sensor RTGN318",
|
||||
"id", "House Code", DATA_INT, get_os_rollingcode(msg, sensor_id),
|
||||
"channel", "Channel", DATA_INT, get_os_channel(msg, sensor_id), // 1 to 5
|
||||
"battery", "Battery", DATA_STRING, get_os_battery(msg, sensor_id) ? "LOW" : "OK",
|
||||
"temperature_C", "Temperature", DATA_FORMAT, "%.02f C", DATA_DOUBLE, get_os_temperature(msg, sensor_id),
|
||||
"humidity", "Humidity", DATA_FORMAT, "%u %%", DATA_INT, get_os_humidity(msg, sensor_id),
|
||||
NULL);
|
||||
data_acquired_handler(data);
|
||||
} else if (num_valid_v2_bits==201 && (validate_os_v2_message(msg, 201, num_valid_v2_bits, 21) == 0)) {
|
||||
|
||||
// RF Clock message ??
|
||||
}
|
||||
return 1;
|
||||
} else if (num_valid_v2_bits > 16) {
|
||||
fprintf(stdout, "%d bit message received from unrecognized Oregon Scientific v2.1 sensor with device ID %x.\n", num_valid_v2_bits, sensor_id);
|
||||
fprintf(stdout, "Message: "); for (i=0 ; i<20 ; i++) fprintf(stdout, "%02x ", msg[i]); fprintf(stdout,"\n\n");
|
||||
// RF Clock message ??
|
||||
}
|
||||
return 1;
|
||||
} else if (num_valid_v2_bits > 16) {
|
||||
fprintf(stdout, "%d bit message received from unrecognized Oregon Scientific v2.1 sensor with device ID %x.\n", num_valid_v2_bits, sensor_id);
|
||||
fprintf(stdout, "Message: "); for (i=0 ; i<20 ; i++) fprintf(stdout, "%02x ", msg[i]); fprintf(stdout,"\n\n");
|
||||
} else {
|
||||
//fprintf(stdout, "\nPossible Oregon Scientific v2.1 message, but sync nibble wasn't found\n"); fprintf(stdout, "Raw Data: "); for (i=0 ; i<BITBUF_COLS ; i++) fprintf(stdout, "%02x ", bb[0][i]); fprintf(stdout,"\n\n");
|
||||
//fprintf(stdout, "\nPossible Oregon Scientific v2.1 message, but sync nibble wasn't found\n"); fprintf(stdout, "Raw Data: "); for (i=0 ; i<BITBUF_COLS ; i++) fprintf(stdout, "%02x ", bb[0][i]); fprintf(stdout,"\n\n");
|
||||
}
|
||||
} else {
|
||||
//if (bb[0][3] != 0) int i; fprintf(stdout, "\nBadly formatted OS v2.1 message encountered."); for (i=0 ; i<BITBUF_COLS ; i++) fprintf(stdout, "%02x ", bb[0][i]); fprintf(stdout,"\n\n");}
|
||||
}
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
//if (bb[0][3] != 0) int i; fprintf(stdout, "\nBadly formatted OS v2.1 message encountered."); for (i=0 ; i<BITBUF_COLS ; i++) fprintf(stdout, "%02x ", bb[0][i]); fprintf(stdout,"\n\n");}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int oregon_scientific_v3_parser(bitbuffer_t *bitbuffer) {
|
||||
bitrow_t *bb = bitbuffer->bb;
|
||||
bitrow_t *bb = bitbuffer->bb;
|
||||
|
||||
// Check stream for possible Oregon Scientific v3 protocol data (skip part of first and last bytes to get past sync/startup bit errors)
|
||||
if ((((bb[0][0]&0xf) == 0x0f) && (bb[0][1] == 0xff) && ((bb[0][2]&0xc0) == 0xc0)) ||
|
||||
(((bb[0][0]&0xf) == 0x00) && (bb[0][1] == 0x00) && ((bb[0][2]&0xc0) == 0x00))) {
|
||||
int i,j;
|
||||
unsigned char msg[BITBUF_COLS] = {0};
|
||||
unsigned int sync_test_val = (bb[0][2]<<24) | (bb[0][3]<<16) | (bb[0][4]<<8);
|
||||
int dest_bit = 0;
|
||||
int pattern_index;
|
||||
// Could be extra/dropped bits in stream. Look for sync byte at expected position +/- some bits in either direction
|
||||
for(pattern_index=0; pattern_index<16; pattern_index++) {
|
||||
unsigned int mask = (unsigned int)(0xfff00000>>pattern_index);
|
||||
unsigned int pattern = (unsigned int)(0xffa00000>>pattern_index);
|
||||
unsigned int pattern2 = (unsigned int)(0xff500000>>pattern_index);
|
||||
unsigned int pattern3 = (unsigned int)(0x00500000>>pattern_index);
|
||||
unsigned int pattern4 = (unsigned int)(0x04600000>>pattern_index);
|
||||
//fprintf(stdout, "OS v3 Sync nibble search - test_val=%08x pattern=%08x mask=%08x\n", sync_test_val, pattern, mask);
|
||||
if (((sync_test_val & mask) == pattern) ||
|
||||
((sync_test_val & mask) == pattern2) ||
|
||||
((sync_test_val & mask) == pattern3) ||
|
||||
((sync_test_val & mask) == pattern4)) {
|
||||
// Found sync byte - start working on decoding the stream data.
|
||||
// pattern_index indicates where sync nibble starts, so now we can find the start of the payload
|
||||
int start_byte = 3 + (pattern_index>>3);
|
||||
int start_bit = (pattern_index+4) & 0x07;
|
||||
//fprintf(stdout, "Oregon Scientific v3 Sync test val %08x ok, starting decode at byte index %d bit %d\n", sync_test_val, start_byte, start_bit);
|
||||
j = start_bit;
|
||||
for (i=start_byte;i<BITBUF_COLS;i++) {
|
||||
while (j<8) {
|
||||
unsigned char bit_val = ((bb[0][i] & (0x80 >> j)) >> (7-j));
|
||||
// Check stream for possible Oregon Scientific v3 protocol data (skip part of first and last bytes to get past sync/startup bit errors)
|
||||
if ((((bb[0][0]&0xf) == 0x0f) && (bb[0][1] == 0xff) && ((bb[0][2]&0xc0) == 0xc0)) ||
|
||||
(((bb[0][0]&0xf) == 0x00) && (bb[0][1] == 0x00) && ((bb[0][2]&0xc0) == 0x00))) {
|
||||
int i,j;
|
||||
unsigned char msg[BITBUF_COLS] = {0};
|
||||
unsigned int sync_test_val = (bb[0][2]<<24) | (bb[0][3]<<16) | (bb[0][4]<<8);
|
||||
int dest_bit = 0;
|
||||
int pattern_index;
|
||||
// Could be extra/dropped bits in stream. Look for sync byte at expected position +/- some bits in either direction
|
||||
for(pattern_index=0; pattern_index<16; pattern_index++) {
|
||||
unsigned int mask = (unsigned int)(0xfff00000>>pattern_index);
|
||||
unsigned int pattern = (unsigned int)(0xffa00000>>pattern_index);
|
||||
unsigned int pattern2 = (unsigned int)(0xff500000>>pattern_index);
|
||||
unsigned int pattern3 = (unsigned int)(0x00500000>>pattern_index);
|
||||
unsigned int pattern4 = (unsigned int)(0x04600000>>pattern_index);
|
||||
//fprintf(stdout, "OS v3 Sync nibble search - test_val=%08x pattern=%08x mask=%08x\n", sync_test_val, pattern, mask);
|
||||
if (((sync_test_val & mask) == pattern) ||
|
||||
((sync_test_val & mask) == pattern2) ||
|
||||
((sync_test_val & mask) == pattern3) ||
|
||||
((sync_test_val & mask) == pattern4)) {
|
||||
// Found sync byte - start working on decoding the stream data.
|
||||
// pattern_index indicates where sync nibble starts, so now we can find the start of the payload
|
||||
int start_byte = 3 + (pattern_index>>3);
|
||||
int start_bit = (pattern_index+4) & 0x07;
|
||||
//fprintf(stdout, "Oregon Scientific v3 Sync test val %08x ok, starting decode at byte index %d bit %d\n", sync_test_val, start_byte, start_bit);
|
||||
j = start_bit;
|
||||
for (i=start_byte;i<BITBUF_COLS;i++) {
|
||||
while (j<8) {
|
||||
unsigned char bit_val = ((bb[0][i] & (0x80 >> j)) >> (7-j));
|
||||
|
||||
// copy every bit from source stream to dest packet
|
||||
msg[dest_bit>>3] |= (((bb[0][i] & (0x80 >> j)) >> (7-j)) << (7-(dest_bit & 0x07)));
|
||||
// copy every bit from source stream to dest packet
|
||||
msg[dest_bit>>3] |= (((bb[0][i] & (0x80 >> j)) >> (7-j)) << (7-(dest_bit & 0x07)));
|
||||
|
||||
//fprintf(stdout,"i=%d j=%d dest_bit=%02x bb=%02x msg=%02x\n",i, j, dest_bit, bb[0][i], msg[dest_bit>>3]);
|
||||
if ((dest_bit & 0x07) == 0x07) {
|
||||
// after assembling each dest byte, flip bits in each nibble to convert from lsb to msb bit ordering
|
||||
int k = (dest_bit>>3);
|
||||
unsigned char indata = msg[k];
|
||||
// flip the 4 bits in the upper and lower nibbles
|
||||
msg[k] = ((indata & 0x11) << 3) | ((indata & 0x22) << 1) |
|
||||
((indata & 0x44) >> 1) | ((indata & 0x88) >> 3);
|
||||
}
|
||||
dest_bit++;
|
||||
j++;
|
||||
}
|
||||
j=0;
|
||||
}
|
||||
break;
|
||||
if ((dest_bit & 0x07) == 0x07) {
|
||||
// after assembling each dest byte, flip bits in each nibble to convert from lsb to msb bit ordering
|
||||
int k = (dest_bit>>3);
|
||||
unsigned char indata = msg[k];
|
||||
// flip the 4 bits in the upper and lower nibbles
|
||||
msg[k] = ((indata & 0x11) << 3) | ((indata & 0x22) << 1) |
|
||||
((indata & 0x44) >> 1) | ((indata & 0x88) >> 3);
|
||||
}
|
||||
dest_bit++;
|
||||
j++;
|
||||
}
|
||||
j=0;
|
||||
}
|
||||
|
||||
if ((msg[0] == 0xf8) && (msg[1] == 0x24)) {
|
||||
if (validate_os_checksum(msg, 15) == 0) {
|
||||
int channel = ((msg[2] >> 4)&0x0f);
|
||||
float temp_c = get_os_temperature(msg, 0xf824);
|
||||
int humidity = get_os_humidity(msg, 0xf824);
|
||||
fprintf(stdout,"Weather Sensor THGR810 Channel %d Temp: %3.1fC %3.1fF Humidity: %d%%\n", channel, temp_c, ((temp_c*9)/5)+32, humidity);
|
||||
}
|
||||
return 1; //msg[k] = ((msg[k] & 0x0F) << 4) + ((msg[k] & 0xF0) >> 4);
|
||||
} else if ((msg[0] == 0xd8) && (msg[1] == 0x74)) {
|
||||
if (validate_os_checksum(msg, 13) == 0) { // ok
|
||||
int channel = ((msg[2] >> 4)&0x0f);
|
||||
int uvidx = get_os_uv(msg, 0xd874);
|
||||
fprintf(stdout, "Weather Sensor UVN800 Channel %d UV index: %d \n", channel, uvidx);
|
||||
}
|
||||
} else if ((msg[0] == 0x19) && (msg[1] == 0x84)) {
|
||||
if (validate_os_checksum(msg, 17) == 0) {
|
||||
float gustWindspeed = (msg[11]+msg[10])/100;
|
||||
float quadrant = msg[8]*22.5;
|
||||
fprintf(stdout, "Weather Sensor WGR800 Wind Gauge Gust Wind Speed : %2.0f m/s Wind direction %3.0f dgrs\n", gustWindspeed, quadrant);
|
||||
}
|
||||
return 1;
|
||||
} else if ((msg[0] == 0x20) || (msg[0] == 0x21) || (msg[0] == 0x22)
|
||||
|| (msg[0] == 0x23) || (msg[0] == 0x24)) { // Owl CM160 Readings
|
||||
msg[0]=msg[0] & 0x0f;
|
||||
if (validate_os_checksum(msg, 22) == 0) {
|
||||
float rawAmp = (msg[4] >> 4 << 8 | (msg[3] & 0x0f )<< 4 | msg[3] >> 4);
|
||||
fprintf(stdout, "current measurement reading value = %.0f\n", rawAmp);
|
||||
fprintf(stdout, "current watts (230v) = %.0f\n", rawAmp /(0.27*230)*1000);
|
||||
}
|
||||
} else if (msg[0] == 0x26) { // Owl CM180 readings
|
||||
int k;
|
||||
for (k=0; k<BITBUF_COLS;k++) { // Reverse nibbles
|
||||
msg[k] = (msg[k] & 0xF0) >> 4 | (msg[k] & 0x0F) << 4;
|
||||
}
|
||||
unsigned short int ipower = power(msg);
|
||||
unsigned long long itotal = total(msg);
|
||||
float total_energy = itotal/3600/1000.0;
|
||||
if (itotal)
|
||||
fprintf(stdout,"Energy Sensor CM180 Id %x%x power: %dW, total: %lluW, Total Energy: %.3fkWh\n", msg[0], msg[1], ipower, itotal, total_energy);
|
||||
else
|
||||
fprintf(stdout,"Energy Sensor CM180 Id %x%x power: %dW\n", msg[0], msg[1], ipower);
|
||||
|
||||
} else if ((msg[0] != 0) && (msg[1]!= 0)) { // sync nibble was found and some data is present...
|
||||
fprintf(stderr, "Message received from unrecognized Oregon Scientific v3 sensor.\n");
|
||||
fprintf(stderr, "Message: "); for (i=0 ; i<BITBUF_COLS ; i++) fprintf(stdout, "%02x ", msg[i]); fprintf(stdout, "\n");
|
||||
fprintf(stderr, " Raw: "); for (i=0 ; i<BITBUF_COLS ; i++) fprintf(stdout, "%02x ", bb[0][i]); fprintf(stdout,"\n\n");
|
||||
} else if (bb[0][3] != 0 ) {
|
||||
//fprintf(stdout, "\nPossible Oregon Scientific v3 message, but sync nibble wasn't found\n");
|
||||
//fprintf(stdout, "Raw Data: "); for (i=0 ; i<BITBUF_COLS ; i++) fprintf(stdout, "%02x ", bb[0][i]); fprintf(stdout,"\n\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else { // Based on first couple of bytes, either corrupt message or something other than an Oregon Scientific v3 message
|
||||
//if (bb[0][3] != 0) { fprintf(stdout, "\nUnrecognized Msg in v3: "); int i; for (i=0 ; i<BITBUF_COLS ; i++) fprintf(stdout, "%02x ", bb[0][i]); fprintf(stdout,"\n\n"); }
|
||||
}
|
||||
return 0;
|
||||
|
||||
if ((msg[0] == 0xf8) && (msg[1] == 0x24)) {
|
||||
if (validate_os_checksum(msg, 15) == 0) {
|
||||
int channel = ((msg[2] >> 4)&0x0f);
|
||||
float temp_c = get_os_temperature(msg, 0xf824);
|
||||
int humidity = get_os_humidity(msg, 0xf824);
|
||||
fprintf(stdout,"Weather Sensor THGR810 Channel %d Temp: %3.1fC %3.1fF Humidity: %d%%\n", channel, temp_c, ((temp_c*9)/5)+32, humidity);
|
||||
}
|
||||
return 1; //msg[k] = ((msg[k] & 0x0F) << 4) + ((msg[k] & 0xF0) >> 4);
|
||||
} else if ((msg[0] == 0xd8) && (msg[1] == 0x74)) {
|
||||
if (validate_os_checksum(msg, 13) == 0) { // ok
|
||||
int channel = ((msg[2] >> 4)&0x0f);
|
||||
int uvidx = get_os_uv(msg, 0xd874);
|
||||
fprintf(stdout, "Weather Sensor UVN800 Channel %d UV index: %d \n", channel, uvidx);
|
||||
}
|
||||
} else if ((msg[0] == 0x19) && (msg[1] == 0x84)) {
|
||||
if (validate_os_checksum(msg, 17) == 0) {
|
||||
float gustWindspeed = (msg[11]+msg[10])/100;
|
||||
float quadrant = msg[8]*22.5;
|
||||
fprintf(stdout, "Weather Sensor WGR800 Wind Gauge Gust Wind Speed : %2.0f m/s Wind direction %3.0f dgrs\n", gustWindspeed, quadrant);
|
||||
}
|
||||
return 1;
|
||||
} else if ((msg[0] == 0x20) || (msg[0] == 0x21) || (msg[0] == 0x22)
|
||||
|| (msg[0] == 0x23) || (msg[0] == 0x24)) { // Owl CM160 Readings
|
||||
msg[0]=msg[0] & 0x0f;
|
||||
if (validate_os_checksum(msg, 22) == 0) {
|
||||
float rawAmp = (msg[4] >> 4 << 8 | (msg[3] & 0x0f )<< 4 | msg[3] >> 4);
|
||||
fprintf(stdout, "current measurement reading value = %.0f\n", rawAmp);
|
||||
fprintf(stdout, "current watts (230v) = %.0f\n", rawAmp /(0.27*230)*1000);
|
||||
}
|
||||
} else if (msg[0] == 0x26) { // Owl CM180 readings
|
||||
int k;
|
||||
for (k=0; k<BITBUF_COLS;k++) { // Reverse nibbles
|
||||
msg[k] = (msg[k] & 0xF0) >> 4 | (msg[k] & 0x0F) << 4;
|
||||
}
|
||||
unsigned short int ipower = power(msg);
|
||||
unsigned long long itotal = total(msg);
|
||||
float total_energy = itotal/3600/1000.0;
|
||||
if (itotal)
|
||||
fprintf(stdout,"Energy Sensor CM180 Id %x%x power: %dW, total: %lluW, Total Energy: %.3fkWh\n", msg[0], msg[1], ipower, itotal, total_energy);
|
||||
else
|
||||
fprintf(stdout,"Energy Sensor CM180 Id %x%x power: %dW\n", msg[0], msg[1], ipower);
|
||||
|
||||
} else if ((msg[0] != 0) && (msg[1]!= 0)) { // sync nibble was found and some data is present...
|
||||
fprintf(stderr, "Message received from unrecognized Oregon Scientific v3 sensor.\n");
|
||||
fprintf(stderr, "Message: "); for (i=0 ; i<BITBUF_COLS ; i++) fprintf(stdout, "%02x ", msg[i]); fprintf(stdout, "\n");
|
||||
fprintf(stderr, " Raw: "); for (i=0 ; i<BITBUF_COLS ; i++) fprintf(stdout, "%02x ", bb[0][i]); fprintf(stdout,"\n\n");
|
||||
} else if (bb[0][3] != 0 ) {
|
||||
//fprintf(stdout, "\nPossible Oregon Scientific v3 message, but sync nibble wasn't found\n");
|
||||
//fprintf(stdout, "Raw Data: "); for (i=0 ; i<BITBUF_COLS ; i++) fprintf(stdout, "%02x ", bb[0][i]); fprintf(stdout,"\n\n");
|
||||
}
|
||||
}
|
||||
else { // Based on first couple of bytes, either corrupt message or something other than an Oregon Scientific v3 message
|
||||
//if (bb[0][3] != 0) { fprintf(stdout, "\nUnrecognized Msg in v3: "); int i; for (i=0 ; i<BITBUF_COLS ; i++) fprintf(stdout, "%02x ", bb[0][i]); fprintf(stdout,"\n\n"); }
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int oregon_scientific_callback(bitbuffer_t *bitbuffer) {
|
||||
int ret = oregon_scientific_v2_1_parser(bitbuffer);
|
||||
if (ret == 0)
|
||||
ret = oregon_scientific_v3_parser(bitbuffer);
|
||||
return ret;
|
||||
int ret = oregon_scientific_v2_1_parser(bitbuffer);
|
||||
if (ret == 0)
|
||||
ret = oregon_scientific_v3_parser(bitbuffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *output_fields[] = {
|
||||
"time",
|
||||
"model",
|
||||
"id",
|
||||
"channel",
|
||||
"battery",
|
||||
"temperature_C",
|
||||
"humidity",
|
||||
"rain_rate",
|
||||
"rain_total",
|
||||
NULL
|
||||
"time",
|
||||
"model",
|
||||
"id",
|
||||
"channel",
|
||||
"battery",
|
||||
"temperature_C",
|
||||
"humidity",
|
||||
"rain_rate",
|
||||
"rain_total",
|
||||
NULL
|
||||
};
|
||||
|
||||
r_device oregon_scientific = {
|
||||
.name = "Oregon Scientific Weather Sensor",
|
||||
.modulation = OOK_PULSE_MANCHESTER_ZEROBIT,
|
||||
.short_limit = 110, // Nominal 1024Hz (122), but pulses are shorter than pauses
|
||||
.long_limit = 0, // not used
|
||||
.reset_limit = 600,
|
||||
.json_callback = &oregon_scientific_callback,
|
||||
.disabled = 0,
|
||||
.demod_arg = 0,
|
||||
.fields = output_fields
|
||||
.name = "Oregon Scientific Weather Sensor",
|
||||
.modulation = OOK_PULSE_MANCHESTER_ZEROBIT,
|
||||
.short_limit = 110, // Nominal 1024Hz (122), but pulses are shorter than pauses
|
||||
.long_limit = 0, // not used
|
||||
.reset_limit = 600,
|
||||
.json_callback = &oregon_scientific_callback,
|
||||
.disabled = 0,
|
||||
.demod_arg = 0,
|
||||
.fields = output_fields
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue