913 lines
35 KiB
C
913 lines
35 KiB
C
//#######################################################################################################
|
|
//## This Plugin is only for use with the RFLink software package ##
|
|
//## Plugin-48 Oregon V1/2/3 ##
|
|
//#######################################################################################################
|
|
/*********************************************************************************************\
|
|
* This protocol takes care of receiving a few 868 Mhz protocols
|
|
*
|
|
* Protocols : Visonic,
|
|
* ELV EM-Serie: EM-1000S, EM-100-EM, EM-1000-GZ
|
|
* ELV KS serie: Thermo (AS3), Thermo/Hygro (AS2000, ASH2000, S2000, S2001A, S2001IA, ASH2200, S300IA)
|
|
* Rain (S2000R), Wind (S2000W), Thermo/Hygro/Baro (S2001I, S2001ID), UV (S2500H)
|
|
* Pyrano (Strahlungsleistung), Kombi (KS200, KS300)
|
|
* FS20 FS serie
|
|
*
|
|
* Author : StuntTeam
|
|
* Support : http://sourceforge.net/projects/rflink/
|
|
* License : This code is free for use in any open source project when this header is included.
|
|
* Usage of any parts of this code in a commercial application is prohibited!
|
|
*********************************************************************************************
|
|
* Changelog: v0.1 beta
|
|
*********************************************************************************************
|
|
* Technical information:
|
|
* Supports Oregon V1, V2 and V3 protocol messages
|
|
* Core code from https://github.com/Cactusbone/ookDecoder/blob/master/ookDecoder.ino
|
|
* Copyright (c) 2014 Charly Koza cactusbone@free.fr Copyright (c) 2012 Olivier Lebrun olivier.lebrun@connectingstuff.net
|
|
* Copyright (c) 2012 Dominique Pierre (zzdomi) Copyright (c) 2010 Jean-Claude Wippler jcw@equi4.com
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
|
|
* files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
|
|
* modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
|
|
* is furnished to do so, subject to the following conditions:
|
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
\*********************************************************************************************/
|
|
#define PLUGIN_ID 101
|
|
#define PLUGIN_NAME "Few868"
|
|
|
|
#define OSV3_PULSECOUNT_MIN 126
|
|
#define OSV3_PULSECOUNT_MAX 278
|
|
|
|
|
|
// =====================================================================================================
|
|
class DecodeOOK {
|
|
protected:
|
|
byte total_bits, bits, flip, state, pos, data[25];
|
|
virtual char decode(word width) = 0;
|
|
public:
|
|
enum { UNKNOWN, T0, T1, T2, T3, OK, DONE };
|
|
// -------------------------------------
|
|
DecodeOOK() { resetDecoder(); }
|
|
// -------------------------------------
|
|
bool nextPulse(word width) {
|
|
if (state != DONE)
|
|
|
|
switch (decode(width)) {
|
|
case -1: resetDecoder(); break;
|
|
case 1: done(); break;
|
|
}
|
|
return isDone();
|
|
}
|
|
// -------------------------------------
|
|
bool isDone() const { return state == DONE; }
|
|
// -------------------------------------
|
|
const byte* getData(byte& count) const {
|
|
count = pos;
|
|
return data;
|
|
}
|
|
// -------------------------------------
|
|
void resetDecoder() {
|
|
total_bits = bits = pos = flip = 0;
|
|
state = UNKNOWN;
|
|
}
|
|
// -------------------------------------
|
|
// add one bit to the packet data pbuffer
|
|
// -------------------------------------
|
|
virtual void gotBit(char value) {
|
|
total_bits++;
|
|
byte *ptr = data + pos;
|
|
*ptr = (*ptr >> 1) | (value << 7);
|
|
|
|
if (++bits >= 8) {
|
|
bits = 0;
|
|
if (++pos >= sizeof data) {
|
|
resetDecoder();
|
|
return;
|
|
}
|
|
}
|
|
state = OK;
|
|
}
|
|
// -------------------------------------
|
|
// store a bit using Manchester encoding
|
|
// -------------------------------------
|
|
void manchester(char value) {
|
|
flip ^= value; // manchester code, long pulse flips the bit
|
|
gotBit(flip);
|
|
}
|
|
// -------------------------------------
|
|
// move bits to the front so that all the bits are aligned to the end
|
|
// -------------------------------------
|
|
void alignTail(byte max = 0) {
|
|
// align bits
|
|
if (bits != 0) {
|
|
data[pos] >>= 8 - bits;
|
|
for (byte i = 0; i < pos; ++i)
|
|
data[i] = (data[i] >> bits) | (data[i + 1] << (8 - bits));
|
|
bits = 0;
|
|
}
|
|
// optionally shift bytes down if there are too many of 'em
|
|
if (max > 0 && pos > max) {
|
|
byte n = pos - max;
|
|
pos = max;
|
|
for (byte i = 0; i < pos; ++i)
|
|
data[i] = data[i + n];
|
|
}
|
|
}
|
|
// -------------------------------------
|
|
void reverseBits() {
|
|
for (byte i = 0; i < pos; ++i) {
|
|
byte b = data[i];
|
|
for (byte j = 0; j < 8; ++j) {
|
|
data[i] = (data[i] << 1) | (b & 1);
|
|
b >>= 1;
|
|
}
|
|
}
|
|
}
|
|
// -------------------------------------
|
|
void reverseNibbles() {
|
|
for (byte i = 0; i < pos; ++i)
|
|
data[i] = (data[i] << 4) | (data[i] >> 4);
|
|
}
|
|
// -------------------------------------
|
|
void done() {
|
|
while (bits)
|
|
gotBit(0); // padding
|
|
state = DONE;
|
|
}
|
|
};
|
|
|
|
// 868 MHz decoders
|
|
|
|
/// OOK decoder for Visonic devices.
|
|
class VisonicDecoder : public DecodeOOK {
|
|
public:
|
|
VisonicDecoder () {}
|
|
|
|
virtual char decode (word width) {
|
|
if (200 <= width && width < 1000) {
|
|
byte w = width >= 600;
|
|
switch (state) {
|
|
case UNKNOWN:
|
|
case OK:
|
|
state = w == 0 ? T0 : T1;
|
|
break;
|
|
case T0:
|
|
gotBit(!w);
|
|
if (w)
|
|
return 0;
|
|
break;
|
|
case T1:
|
|
gotBit(!w);
|
|
if (!w)
|
|
return 0;
|
|
break;
|
|
}
|
|
// sync error, flip all the preceding bits to resync
|
|
for (byte i = 0; i <= pos; ++i)
|
|
data[i] ^= 0xFF;
|
|
} else if (width >= 2500 && 8 * pos + bits >= 36 && state == OK) {
|
|
for (byte i = 0; i < 4; ++i)
|
|
gotBit(0);
|
|
alignTail(5); // keep last 40 bits
|
|
// only report valid packets
|
|
byte b = data[0] ^ data[1] ^ data[2] ^ data[3] ^ data[4];
|
|
if ((b & 0xF) == (b >> 4))
|
|
return 1;
|
|
} else
|
|
return -1;
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
/// OOK decoder for FS20 type EM devices.
|
|
class EMxDecoder : public DecodeOOK {
|
|
public:
|
|
EMxDecoder () : DecodeOOK (30) {} // ignore packets repeated within 3 sec
|
|
|
|
// see also http://fhz4linux.info/tiki-index.php?page=EM+Protocol
|
|
virtual char decode (word width) {
|
|
if (200 <= width && width < 1000) {
|
|
byte w = width >= 600;
|
|
switch (state) {
|
|
case UNKNOWN:
|
|
if (w == 0)
|
|
++flip;
|
|
else if (flip > 20)
|
|
state = OK;
|
|
else
|
|
return -1;
|
|
break;
|
|
case OK:
|
|
if (w == 0)
|
|
state = T0;
|
|
else
|
|
return -1;
|
|
break;
|
|
case T0:
|
|
gotBit(w);
|
|
break;
|
|
}
|
|
} else if (width >= 1500 && pos >= 9)
|
|
return 1;
|
|
else
|
|
return -1;
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
/// OOK decoder for FS20 type KS devices.
|
|
class KSxDecoder : public DecodeOOK {
|
|
public:
|
|
KSxDecoder () {}
|
|
|
|
// see also http://www.dc3yc.homepage.t-online.de/protocol.htm
|
|
virtual char decode (word width) {
|
|
if (200 <= width && width < 1000) {
|
|
byte w = width >= 600;
|
|
switch (state) {
|
|
case UNKNOWN:
|
|
gotBit(w);
|
|
bits = pos = 0;
|
|
if (data[0] != 0x95)
|
|
state = UNKNOWN;
|
|
break;
|
|
case OK:
|
|
state = w == 0 ? T0 : T1;
|
|
break;
|
|
case T0:
|
|
gotBit(1);
|
|
if (!w)
|
|
return -1;
|
|
break;
|
|
case T1:
|
|
gotBit(0);
|
|
if (w)
|
|
return -1;
|
|
break;
|
|
}
|
|
} else if (width >= 1500 && pos >= 6)
|
|
return 1;
|
|
else
|
|
return -1;
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
/// OOK decoder for FS20 type FS devices.
|
|
class FSxDecoder : public DecodeOOK {
|
|
public:
|
|
FSxDecoder () {}
|
|
|
|
// see also http://fhz4linux.info/tiki-index.php?page=FS20%20Protocol
|
|
virtual char decode (word width) {
|
|
if (300 <= width && width < 775) {
|
|
byte w = width >= 500;
|
|
switch (state) {
|
|
case UNKNOWN:
|
|
if (w == 0)
|
|
++flip;
|
|
else if (flip > 20)
|
|
state = T1;
|
|
else
|
|
return -1;
|
|
break;
|
|
case OK:
|
|
state = w == 0 ? T0 : T1;
|
|
break;
|
|
case T0:
|
|
gotBit(0);
|
|
if (w)
|
|
return -1;
|
|
break;
|
|
case T1:
|
|
gotBit(1);
|
|
if (!w)
|
|
return -1;
|
|
break;
|
|
}
|
|
} else if (width >= 1500 && pos >= 5)
|
|
return 1;
|
|
else
|
|
return -1;
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
// =====================================================================================================
|
|
// =====================================================================================================
|
|
|
|
|
|
OregonDecoderV1 orscV1;
|
|
OregonDecoderV2 orscV2;
|
|
OregonDecoderV3 orscV3;
|
|
|
|
volatile word pulse;
|
|
// =====================================================================================================
|
|
// =====================================================================================================
|
|
byte osdata[13];
|
|
|
|
void reportSerial(class DecodeOOK& decoder) {
|
|
byte pos;
|
|
const byte* data = decoder.getData(pos);
|
|
for (byte i = 0; i < pos; ++i) {
|
|
if (i < 13) osdata[i]=data[i];
|
|
}
|
|
decoder.resetDecoder();
|
|
}
|
|
// =====================================================================================================
|
|
// calculate a packet checksum by performing a
|
|
byte checksum(byte type, int count, byte check) {
|
|
byte calc=0;
|
|
// type 1, add all nibbles, deduct 10
|
|
if (type == 1) {
|
|
for(byte i = 0; i<count;i++) {
|
|
calc += (osdata[i]&0xF0) >> 4;
|
|
calc += (osdata[i]&0xF);
|
|
}
|
|
calc=calc-10;
|
|
} else
|
|
// type 2, add all nibbles up to count, add the 13th nibble , deduct 10
|
|
if (type == 2) {
|
|
for(byte i = 0; i<count;i++) {
|
|
calc += (osdata[i]&0xF0) >> 4;
|
|
calc += (osdata[i]&0xF);
|
|
}
|
|
calc += (osdata[6]&0xF);
|
|
calc=calc-10;
|
|
} else
|
|
// type 3, add all nibbles up to count, subtract 10 only use the low 4 bits for the compare
|
|
if (type == 3) {
|
|
for(byte i = 0; i<count;i++) {
|
|
calc += (osdata[i]&0xF0) >> 4;
|
|
calc += (osdata[i]&0xF);
|
|
}
|
|
calc=calc-10;
|
|
calc=(calc&0x0f);
|
|
} else
|
|
if (type == 4) {
|
|
for(byte i = 0; i<count;i++) {
|
|
calc += (osdata[i]&0xF0) >> 4;
|
|
calc += (osdata[i]&0xF);
|
|
}
|
|
calc=calc-10;
|
|
|
|
}
|
|
if (check == calc ) return 0;
|
|
return 1;
|
|
}
|
|
// =====================================================================================================
|
|
boolean Plugin_048(byte function, char *string) {
|
|
boolean success=false;
|
|
|
|
#ifdef PLUGIN_048_CORE
|
|
if ((RawSignal.Number < OSV3_PULSECOUNT_MIN) || (RawSignal.Number > OSV3_PULSECOUNT_MAX) ) return false;
|
|
|
|
byte basevar=0;
|
|
byte rc=0;
|
|
byte found = 0;
|
|
byte channel = 0;
|
|
|
|
int temp = 0;
|
|
byte hum = 0;
|
|
int comfort = 0;
|
|
int baro = 0;
|
|
int forecast = 0;
|
|
int uv = 0;
|
|
int wdir = 0;
|
|
int wspeed = 0;
|
|
int awspeed = 0;
|
|
int rain = 0;
|
|
int raintot = 0;
|
|
|
|
word p = pulse;
|
|
// ==================================================================================
|
|
for (int x = 0; x < RawSignal.Number; x++) {
|
|
p = RawSignal.Pulses[x]*RAWSIGNAL_SAMPLE_RATE;
|
|
if (p != 0) {
|
|
if (orscV1.nextPulse(p)) {
|
|
reportSerial(orscV1);
|
|
found=1;
|
|
}
|
|
if (orscV2.nextPulse(p)) {
|
|
reportSerial(orscV2);
|
|
found=2;
|
|
}
|
|
if (orscV3.nextPulse(p)) {
|
|
reportSerial(orscV3);
|
|
found=3;
|
|
}
|
|
}
|
|
}
|
|
if (found == 0) break;
|
|
|
|
// ==================================================================================
|
|
// Protocol and device info:
|
|
// ==================================================================================
|
|
//Serial.print("Oregon V");
|
|
//Serial.print(found);
|
|
//Serial.print(": ");
|
|
//for(byte x=0; x<13;x++) {
|
|
// Serial.print( osdata[x],HEX );
|
|
// Serial.print((" "));
|
|
//}
|
|
//Serial.println();
|
|
//Serial.print("Oregon ID=");
|
|
unsigned int id=(osdata[0]<<8)+ (osdata[1]);
|
|
rc=osdata[0];
|
|
//Serial.println(id,HEX);
|
|
// ==================================================================================
|
|
// Process the various device types:
|
|
// ==================================================================================
|
|
// Oregon V1 packet structure
|
|
// SL-109H, AcuRite 09955
|
|
// TEMP + CRC
|
|
// ==================================================================================
|
|
// 8487101C
|
|
// 84+87+10=11B > 1B+1 = 1C
|
|
if (found==1) { // OSV1
|
|
int sum = osdata[0]+osdata[1]+osdata[2]; // max. value is 0x2FD
|
|
sum= (sum &0xff) + (sum>>8); // add overflow to low byte
|
|
if (osdata[3] != (sum & 0xff) ) {
|
|
//Serial.println("CRC Error");
|
|
break;
|
|
}
|
|
// -------------
|
|
temp = ((osdata[2]>>4) * 100) + ((osdata[1] & 0x0F) * 10) + ((osdata[1] >> 4));
|
|
if ((osdata[2] & 0x02) == 2) temp=temp | 0x8000; // bit 1 set when temp is negative, set highest bit on temp valua
|
|
// ----------------------------------
|
|
// Output
|
|
// ----------------------------------
|
|
sprintf(pbuffer, "20;%02X;", PKSequenceNumber++); // Node and packet number
|
|
Serial.print( pbuffer );
|
|
// ----------------------------------
|
|
Serial.print("OregonV1;"); // Label
|
|
sprintf(pbuffer, "ID=00%02x;", rc); // ID
|
|
Serial.print( pbuffer );
|
|
sprintf(pbuffer, "TEMP=%04x;", temp);
|
|
Serial.print( pbuffer );
|
|
Serial.println();
|
|
}
|
|
// ==================================================================================
|
|
// ea4c Outside (Water) Temperature: THC238, THC268, THN132N, THWR288A, THRN122N, THN122N, AW129, AW131
|
|
// TEMP + BAT + CRC
|
|
// ca48 Pool (Water) Temperature: THWR800
|
|
// 0a4d Indoor Temperature: THR128, THR138, THC138
|
|
// ==================================================================================
|
|
// OSV2 EA4C20725C21D083 // THN132N
|
|
// OSV2 EA4C101360193023 // THN132N
|
|
// OSV2 EA4C40F85C21D0D4 // THN132N
|
|
// OSV2 EA4C20809822D013
|
|
// 0123456789012345
|
|
// 0 1 2 3 4 5 6 7
|
|
if(id == 0xea4c || id == 0xca48 || id == 0x0a4d) {
|
|
byte sum=(osdata[7]&0x0f) <<4;
|
|
sum=sum+(osdata[6]>>4);
|
|
if ( checksum(2,6, sum) !=0) { // checksum = all nibbles 0-11+13 results is nibbles 15 <<4 + 12
|
|
//Serial.println("CRC Error");
|
|
break;
|
|
}
|
|
// -------------
|
|
temp = ((osdata[5]>>4) * 100) + ((osdata[5] & 0x0F) * 10) + ((osdata[4] >> 4));
|
|
if ((osdata[6] & 0x0F) >= 8) temp=temp | 0x8000;
|
|
// ----------------------------------
|
|
// Output
|
|
// ----------------------------------
|
|
sprintf(pbuffer, "20;%02X;", PKSequenceNumber++); // Node and packet number
|
|
Serial.print( pbuffer );
|
|
// ----------------------------------
|
|
Serial.print("Oregon Temp;"); // Label
|
|
sprintf(pbuffer, "ID=%02x%02x;", rc,osdata[2]); // ID
|
|
Serial.print( pbuffer );
|
|
sprintf(pbuffer, "TEMP=%04x;", temp);
|
|
Serial.print( pbuffer );
|
|
if ((osdata[3] & 0x0F) >= 4) {
|
|
Serial.print("BAT=LOW;");
|
|
} else {
|
|
Serial.print("BAT=OK;");
|
|
}
|
|
Serial.println();
|
|
} else
|
|
// ==================================================================================
|
|
// 1a2d Indoor Temp/Hygro: THGN122N, THGN123N, THGR122NX, THGR228N, THGR238, THGR268, THGR122X
|
|
// 1a3d Outside Temp/Hygro: THGR918, THGRN228NX, THGN500
|
|
// fa28 Indoor Temp/Hygro: THGR810
|
|
// *aac Outside Temp/Hygro: RTGR328N
|
|
// ca2c Outside Temp/Hygro: THGR328N
|
|
// fab8 Outside Temp/Hygro: WTGR800
|
|
// TEMP + HUM sensor + BAT + CRC
|
|
// ==================================================================================
|
|
// OSV2 AACC13783419008250AD[RTGR328N,...] Id:78 ,Channel:0 ,temp:19.30 ,hum:20 ,bat:10
|
|
// OSV2 1A2D40C4512170463EE6[THGR228N,...] Id:C4 ,Channel:3 ,temp:21.50 ,hum:67 ,bat:90
|
|
// OSV2 1A2D1072512080E73F2C[THGR228N,...] Id:72 ,Channel:1 ,temp:20.50 ,hum:78 ,bat:90
|
|
// OSV2 1A2D103742197005378E // THGR228N
|
|
// OSV3 FA28A428202290834B46 //
|
|
// OSV2 1A2D1002 02060552A4C
|
|
// 1A3D10D91C273083..
|
|
// 1A3D10D90C284083..
|
|
// OSV3 FA2814A93022304443BE // THGR810
|
|
// 01234567890123456789
|
|
// 0 1 2 3 4 5
|
|
// F+A+2+8+1+4+A+9+3+0+2+2+3+0+4+4=4d-a=43
|
|
if(id == 0xfa28 || id == 0x1a2d || id == 0x1a3d || (id&0xfff)==0xACC || id == 0xca2c || id == 0xfab8 ) {
|
|
if ( checksum(1,8,osdata[8]) !=0) break; // checksum = all nibbles 0-15 results is nibbles 16.17
|
|
// -------------
|
|
temp = ((osdata[5]>>4) * 100) + ((osdata[5] & 0x0F) * 10) + ((osdata[4] >> 4));
|
|
if ((osdata[6] & 0x0F) >= 8) temp=temp | 0x8000;
|
|
// -------------
|
|
hum = ((osdata[7] & 0x0F)*10)+ (osdata[6] >> 4);
|
|
// ----------------------------------
|
|
// Output
|
|
// ----------------------------------
|
|
sprintf(pbuffer, "20;%02X;", PKSequenceNumber++); // Node and packet number
|
|
Serial.print( pbuffer );
|
|
// ----------------------------------
|
|
Serial.print("Oregon TempHygro;"); // Label
|
|
sprintf(pbuffer, "ID=%02x%02x;", rc,osdata[2]); // ID
|
|
Serial.print( pbuffer );
|
|
sprintf(pbuffer, "TEMP=%04x;", temp);
|
|
Serial.print( pbuffer );
|
|
sprintf(pbuffer, "HUM=%02x;", hum);
|
|
Serial.print( pbuffer );
|
|
if ((osdata[3] & 0x0F) >= 4) {
|
|
Serial.print("BAT=LOW;");
|
|
} else {
|
|
Serial.print("BAT=OK;");
|
|
}
|
|
Serial.println();
|
|
} else
|
|
// ==================================================================================
|
|
// 5a5d Indoor Temp/Hygro/Baro: Huger - BTHR918
|
|
// 5a6d Indoor Temp/Hygro/Baro: BTHR918N, BTHR968. BTHG968
|
|
// TEMP + HUM + BARO + FORECAST + BAT
|
|
// NO CRC YET
|
|
// ==================================================================================
|
|
// 5A 6D 00 7A 10 23 30 83 86 31
|
|
// 5+a+6+d+7+a+1+2+3+3+8+3=47 -a=3d +8=4f +8+6=55
|
|
// 5+a+6+d+7+a+1+2+3+3=3c-a=32
|
|
// 0 1 2 3 4 5 6 7 8 9
|
|
if(id == 0x5a6d || id == 0x5a5d || id == 0x5d60) {
|
|
// -------------
|
|
temp = ((osdata[5]>>4) * 100) + ((osdata[5] & 0x0F) * 10) + ((osdata[4] >> 4));
|
|
if ((osdata[6] & 0x0F) >= 8) temp=temp | 0x8000;
|
|
// -------------
|
|
hum = ((osdata[7] & 0x0F)*10)+ (osdata[6] >> 4);
|
|
|
|
//0: normal, 4: comfortable, 8: dry, C: wet
|
|
int tmp_comfort = osdata[7] >> 4;
|
|
if (tmp_comfort == 0x00)
|
|
comfort=0;
|
|
else if (tmp_comfort == 0x04)
|
|
comfort=1;
|
|
else if (tmp_comfort == 0x08)
|
|
comfort=2;
|
|
else if (tmp_comfort == 0x0C)
|
|
comfort=3;
|
|
|
|
// -------------
|
|
baro = (osdata[8] + 856); // max value = 1111 / 0x457
|
|
|
|
//2: cloudy, 3: rainy, 6: partly cloudy, C: sunny
|
|
int tmp_forecast = osdata[9]>>4;
|
|
if (tmp_forecast == 0x02)
|
|
forecast = 3;
|
|
else if (tmp_forecast == 0x03)
|
|
forecast = 4;
|
|
else if (tmp_forecast == 0x06)
|
|
forecast = 2;
|
|
else if (tmp_forecast == 0x0C)
|
|
forecast = 1;
|
|
|
|
// ----------------------------------
|
|
// Output
|
|
// ----------------------------------
|
|
sprintf(pbuffer, "20;%02X;", PKSequenceNumber++); // Node and packet number
|
|
Serial.print( pbuffer );
|
|
// ----------------------------------
|
|
Serial.print("Oregon BTHR;"); // Label
|
|
sprintf(pbuffer, "ID=%02x%02x;", rc,osdata[2]); // ID
|
|
Serial.print( pbuffer );
|
|
sprintf(pbuffer, "TEMP=%04x;", temp);
|
|
Serial.print( pbuffer );
|
|
sprintf(pbuffer, "HUM=%02x;", hum);
|
|
Serial.print( pbuffer );
|
|
sprintf(pbuffer, "HSTATUS=%d;", comfort);
|
|
Serial.print( pbuffer );
|
|
sprintf(pbuffer, "BARO=%04x;", baro);
|
|
Serial.print( pbuffer );
|
|
sprintf(pbuffer, "BFORECAST=%d;", forecast);
|
|
Serial.print( pbuffer );
|
|
|
|
//below is not correct, and for now discarded
|
|
//if (((osdata[3] & 0x0F) & 0x04) != 0) {
|
|
// Serial.print("BAT=LOW;");
|
|
//} else {
|
|
// Serial.print("BAT=OK;");
|
|
//}
|
|
Serial.println();
|
|
} else
|
|
// ==================================================================================
|
|
// 2914 Rain Gauge:
|
|
// 2d10 Rain Gauge:
|
|
// 2a1d Rain Gauge: RGR126, RGR682, RGR918, PCR122
|
|
// 2A1D0065502735102063
|
|
// 2+A+1+D+0+0+6+5+5+0+2+7+3+5+1+0+2+0=3e-a=34 != 63
|
|
// ==================================================================================
|
|
if(id == 0x2a1d || id == 0x2d10 || id == 0x2914) { // Rain sensor
|
|
//Checksum - add all nibbles from 0 to 8, subtract 9 and compare
|
|
/*
|
|
int cs = 0;
|
|
for (byte i = 0; i < pos-2; ++i) { //all but last byte
|
|
cs += data[i] >> 4;
|
|
cs += data[i] & 0x0F;
|
|
}
|
|
int csc = (data[8] >> 4) + ((data[9] & 0x0F)*16);
|
|
cs -= 9; //my version as A fails?
|
|
Serial.print(csc);
|
|
Serial.print(" vs ");
|
|
Serial.println(cs);
|
|
*/
|
|
rain = ((osdata[5]>>4) * 100) + ((osdata[5] & 0x0F) * 10) + (osdata[4] >> 4);
|
|
raintot = ((osdata[7] >> 4) * 10) + (osdata[6]>>4);
|
|
// ----------------------------------
|
|
// Output
|
|
// ----------------------------------
|
|
sprintf(pbuffer, "20;%02X;", PKSequenceNumber++); // Node and packet number
|
|
Serial.print( pbuffer );
|
|
// ----------------------------------
|
|
Serial.print("Oregon Rain;"); // Label
|
|
sprintf(pbuffer, "ID=%02x%02x;", rc,osdata[3]); // ID
|
|
Serial.print( pbuffer );
|
|
sprintf(pbuffer, "RAIN=%04x;", rain);
|
|
Serial.print( pbuffer );
|
|
sprintf(pbuffer, "RAINTOT=%04x;", raintot);
|
|
Serial.print( pbuffer );
|
|
if ((osdata[3] & 0x0F) >= 4) {
|
|
Serial.print("BAT=LOW;");
|
|
} else {
|
|
Serial.print("BAT=OK;");
|
|
}
|
|
Serial.println();
|
|
} else
|
|
// ==================================================================================
|
|
// 2a19 Rain Gauge: PCR800
|
|
// RAIN + BAT + CRC
|
|
// ==================================================================================
|
|
// OSV3 2A19048E399393250010
|
|
// 01234567890123456789
|
|
// 0 1 2 3 4 5 6 7 8 9
|
|
// 2+A+1+9+0+4+8+E+3+9+9+3+9+3+2+5=5b-A=51 => 10
|
|
if(id == 0x2a19) { // Rain sensor
|
|
int sum = (osdata[9] >> 4);
|
|
if ( checksum(3,9,sum) !=0) { // checksum = all nibbles 0-17 result is nibble 18
|
|
//Serial.print("CRC Error, ");
|
|
break;
|
|
}
|
|
rain = ((osdata[5]>>4) * 100) + ((osdata[5] & 0x0F) * 10) + (osdata[4] >> 4);
|
|
//Serial.print(" RainTotal=");
|
|
//raintot = ((osdata[7] >> 4) * 10) + (osdata[6]>>4);
|
|
//Serial.print(raintot);
|
|
// ----------------------------------
|
|
// Output
|
|
// ----------------------------------
|
|
sprintf(pbuffer, "20;%02X;", PKSequenceNumber++); // Node and packet number
|
|
Serial.print( pbuffer );
|
|
// ----------------------------------
|
|
Serial.print("Oregon Rain2;"); // Label
|
|
sprintf(pbuffer, "ID=%02x%02x;", rc,osdata[4]); // ID
|
|
Serial.print( pbuffer );
|
|
sprintf(pbuffer, "RAIN=%04x;", rain);
|
|
Serial.print( pbuffer );
|
|
//sprintf(pbuffer, "RAINTOT=%04x;", raintot);
|
|
//Serial.print( pbuffer );
|
|
if ((osdata[3] & 0x0F) >= 4) {
|
|
Serial.print("BAT=LOW;");
|
|
} else {
|
|
Serial.print("BAT=OK;");
|
|
}
|
|
Serial.println();
|
|
} else
|
|
// ==================================================================================
|
|
// 1a89 Anemometer: WGR800
|
|
// WIND DIR + SPEED + AV SPEED + CRC
|
|
// ==================================================================================
|
|
// OSV3 1A89048800C026400543
|
|
// OSV3 1A89048800C00431103B
|
|
// OSV3 1a89048848c00000003e W
|
|
// OSV3 1a890488c0c00000003e E
|
|
// 1A89042CB0C047000147
|
|
// 0 1 2 3 4 5 6 7 8 9
|
|
// 1+A+8+9+0+4+8+8+0+0+C+0+0+4+3+1+1+0=45-a=3b
|
|
if(id == 0x1a89) { // Wind sensor
|
|
if ( checksum(1,9,osdata[9]) !=0) break;
|
|
Serial.print(" WINDIR=");
|
|
wdir=(osdata[4] >> 4);
|
|
wdir=wdir*225;
|
|
wdir=wdir/10;
|
|
Serial.print(wdir);
|
|
// -------------
|
|
wspeed = (osdata[6] >> 4) * 10;
|
|
wspeed = wspeed + (osdata[6] &0x0f) * 100;
|
|
wspeed = wspeed + (osdata[5] &0x0f);
|
|
// -------------
|
|
awspeed = (osdata[8] >> 4) * 100;
|
|
awspeed = awspeed + (osdata[7] &0x0f) * 10;
|
|
awspeed = awspeed + (osdata[7] >> 4);
|
|
// ----------------------------------
|
|
// Output
|
|
// ----------------------------------
|
|
sprintf(pbuffer, "20;%02X;", PKSequenceNumber++); // Node and packet number
|
|
Serial.print( pbuffer );
|
|
// ----------------------------------
|
|
Serial.print("Oregon Wind;"); // Label
|
|
sprintf(pbuffer, "ID=%02x%02x;", rc,osdata[2]); // ID
|
|
Serial.print( pbuffer );
|
|
sprintf(pbuffer, "WINDIR=%04x;", wdir);
|
|
Serial.print( pbuffer );
|
|
sprintf(pbuffer, "WINSP=%04x;", wspeed);
|
|
Serial.print( pbuffer );
|
|
sprintf(pbuffer, "AWINSP=%04x;", awspeed);
|
|
Serial.print( pbuffer );
|
|
if ((osdata[3] & 0x0F) >= 4) {
|
|
Serial.print("BAT=LOW;");
|
|
} else {
|
|
Serial.print("BAT=OK;");
|
|
}
|
|
Serial.println();
|
|
} else
|
|
// ==================================================================================
|
|
// 3a0d Anemometer: Huger-STR918, WGR918
|
|
// 1984 Anemometer:
|
|
// 1994 Anemometer:
|
|
// WIND DIR + SPEED + AV SPEED + BAT + CRC
|
|
// 3A0D006F400800000031
|
|
// ==================================================================================
|
|
if(id == 0x3A0D || id == 0x1984 || id == 0x1994 ) {
|
|
if ( checksum(1,9,osdata[9]) !=0) {
|
|
Serial.print("CRC Error, ");
|
|
//break;
|
|
}
|
|
wdir = ((osdata[5]>>4) * 100) + ((osdata[5] & 0x0F * 10) ) + (osdata[4] >> 4);
|
|
wspeed = ((osdata[7] & 0x0F) * 100) + ((osdata[6]>>4) * 10) + ((osdata[6] & 0x0F)) ;
|
|
awspeed = ((osdata[8]>>4) * 100) + ((osdata[8] & 0x0F) * 10)+((osdata[7] >>4)) ;
|
|
// ----------------------------------
|
|
// Output
|
|
// ----------------------------------
|
|
sprintf(pbuffer, "20;%02X;", PKSequenceNumber++); // Node and packet number
|
|
Serial.print( pbuffer );
|
|
// ----------------------------------
|
|
Serial.print("Oregon Wind2;"); // Label
|
|
sprintf(pbuffer, "ID=%02x%02x;", rc,osdata[2]); // ID
|
|
Serial.print( pbuffer );
|
|
sprintf(pbuffer, "WINDIR=%04x;", wdir);
|
|
Serial.print( pbuffer );
|
|
sprintf(pbuffer, "WINSP=%04x;", wspeed);
|
|
Serial.print( pbuffer );
|
|
sprintf(pbuffer, "AWINSP=%04x;", awspeed);
|
|
Serial.print( pbuffer );
|
|
if ((osdata[3] & 0x0F) >= 4) {
|
|
Serial.print("BAT=LOW;");
|
|
} else {
|
|
Serial.print("BAT=OK;");
|
|
}
|
|
Serial.println();
|
|
} else
|
|
// ==================================================================================
|
|
// ea7c UV Sensor: UVN128, UV138
|
|
// UV + BAT
|
|
// NO CRC YET
|
|
// ==================================================================================
|
|
if(id == 0xea7c) {
|
|
uv=((osdata[5] & 0x0F) * 10) + (osdata[4] >> 4);
|
|
Serial.print(uv);
|
|
// ----------------------------------
|
|
// Output
|
|
// ----------------------------------
|
|
sprintf(pbuffer, "20;%02X;", PKSequenceNumber++); // Node and packet number
|
|
Serial.print( pbuffer );
|
|
// ----------------------------------
|
|
Serial.print("Oregon UVN128/138;"); // Label
|
|
sprintf(pbuffer, "ID=%02x%02x;", rc,osdata[2]); // ID
|
|
Serial.print( pbuffer );
|
|
sprintf(pbuffer, "UV=%04x;", uv);
|
|
Serial.print( pbuffer );
|
|
if ((osdata[3] & 0x0F) >= 4) {
|
|
Serial.print("BAT=LOW;");
|
|
} else {
|
|
Serial.print("BAT=OK;");
|
|
}
|
|
Serial.println();
|
|
} else
|
|
// ==================================================================================
|
|
// da78 UV Sensor: UVN800
|
|
// UV
|
|
// NO CRC YET
|
|
// ==================================================================================
|
|
if( id == 0xda78) {
|
|
uv=(osdata[6] & 0xf0) + (osdata[5] &0x0f) ;
|
|
// ----------------------------------
|
|
// Output
|
|
// ----------------------------------
|
|
sprintf(pbuffer, "20;%02X;", PKSequenceNumber++); // Node and packet number
|
|
Serial.print( pbuffer );
|
|
// ----------------------------------
|
|
Serial.print("Oregon UVN800;"); // Label
|
|
sprintf(pbuffer, "ID=%02x%02x;", rc,osdata[2]); // ID
|
|
Serial.print( pbuffer );
|
|
sprintf(pbuffer, "UV=%04x;", uv);
|
|
Serial.print( pbuffer );
|
|
if ((osdata[3] & 0x0F) >= 4) {
|
|
Serial.print("BAT=LOW;");
|
|
} else {
|
|
Serial.print("BAT=OK;");
|
|
}
|
|
Serial.println();
|
|
} else
|
|
// ==================================================================================
|
|
// *aec Date&Time: RTGR328N
|
|
// NO CRC YET
|
|
// ==================================================================================
|
|
// 8AEA1378077214924242C16CBD 21:49 29/04/2014
|
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2
|
|
// 8+A+E+A+1+3+7+8+0+7+7+2+1+4+9+2+4+2+4+2+C+1+6+C=88 != BD
|
|
// Date & Time
|
|
//if( (id &0xfff) == 0xaea) {
|
|
// Serial.print("RTGR328N RC: ");
|
|
// Serial.print(osdata[3], HEX);
|
|
// Serial.print(" Date: ");
|
|
// Serial.print( (osdata[9] >> 4) + 10 * (osdata[10] & 0xf) );
|
|
// Serial.print(" - ");
|
|
// Serial.print( osdata[8] >> 4 );
|
|
// Serial.print(" - ");
|
|
// Serial.print( (osdata[7] >> 4) + 10 * (osdata[8] & 0xf) );
|
|
// Serial.print(" Time: ");
|
|
// Serial.print( (osdata[6] >> 4) + 10 * (osdata[7] & 0xf) );
|
|
// Serial.print(":");
|
|
// Serial.print((osdata[5] >> 4) + 10 * (osdata[6] & 0xf));
|
|
// Serial.print(":");
|
|
// Serial.print((osdata[4] >> 4) + 10 * (osdata[5] & 0xf));
|
|
// Serial.println();
|
|
// break;
|
|
//}
|
|
// ==================================================================================
|
|
// eac0 Ampere meter: cent-a-meter, OWL CM113, Electrisave
|
|
// ==================================================================================
|
|
if(id == 0xeac0) {
|
|
//Serial.println("UNKNOWN LAYOUT");
|
|
// ----------------------------------
|
|
// Output
|
|
// ----------------------------------
|
|
sprintf(pbuffer, "20;%02X;", PKSequenceNumber++); // Node and packet number
|
|
Serial.print( pbuffer );
|
|
// ----------------------------------
|
|
Serial.print("Oregon Unknown;"); // Label
|
|
for(byte x=0; x<13;x++) {
|
|
Serial.print( osdata[x],HEX );
|
|
Serial.print((" "));
|
|
}
|
|
Serial.println(";");
|
|
return success;
|
|
} else
|
|
// ==================================================================================
|
|
// 0x1a* / 0x2a* 0x3a** Power meter: OWL CM119
|
|
// ==================================================================================
|
|
// ==================================================================================
|
|
// 1a99 Anemometer: WGTR800
|
|
// WIND + TEMP + HUM + CRC
|
|
// ==================================================================================
|
|
if(id == 0x1a99) { // Wind sensor
|
|
//Serial.println("UNKNOWN LAYOUT");
|
|
// ----------------------------------
|
|
// Output
|
|
// ----------------------------------
|
|
sprintf(pbuffer, "20;%02X;", PKSequenceNumber++); // Node and packet number
|
|
Serial.print( pbuffer );
|
|
// ----------------------------------
|
|
Serial.print("Oregon Unknown;"); // Label
|
|
for(byte x=0; x<13;x++) {
|
|
Serial.print( osdata[x],HEX );
|
|
Serial.print((" "));
|
|
}
|
|
Serial.println(";");
|
|
return success;
|
|
} else
|
|
// ==================================================================================
|
|
if( (id&0xf00)==0xA00 ) { // Wind sensor
|
|
// ----------------------------------
|
|
// Output
|
|
// ----------------------------------
|
|
sprintf(pbuffer, "20;%02X;", PKSequenceNumber++); // Node and packet number
|
|
Serial.print( pbuffer );
|
|
// ----------------------------------
|
|
Serial.print("Oregon Unknown;"); // Label
|
|
for(byte x=0; x<13;x++) {
|
|
Serial.print( osdata[x],HEX );
|
|
Serial.print((" "));
|
|
}
|
|
Serial.println(";");
|
|
}
|
|
// ==================================================================================
|
|
RawSignal.Repeats=true; // suppress repeats of the same RF packet
|
|
RawSignal.Number=0;
|
|
success = true;
|
|
#endif // PLUGIN_048_CORE
|
|
return success;
|
|
}
|