Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5

Oregon to WeatherDuino gateway
#2

Hi,

Hardware is very basic: Arduino Nanao, Rx module, Tx module. Same as in WD project.

RX data connected to D3, RX led (with apropriate resistor) connected to D4, TX data connected to A0.
proto board :
   

Only Oregon V2 RF protocol is decoded (not all sensors).
OD soft:
Code:
// Oregon V2 decoder modfied - Olivier Lebrun // Oregon V2 decoder added - Dominique Pierre // New code to decode OOK signals from weather sensors, etc. // 2010-04-11 <jcw@equi4.com> http://opensource.org/licenses/mit-license.php // $Id: ookDecoder.pde 5331 2010-04-17 10:45:17Z jcw $ #include <Wire.h> //#include <LiquidCrystal.h> #include <LiquidCrystal_I2C.h> // Library for LCD #include <VirtualWire.h> // library for RF RX/TX //LiquidCrystal lcd(15, 14, 7, 6, 5, 4); //LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // Set the LCD I2C address LiquidCrystal_I2C lcd(0x27, 20, 4); #define StationID 0xA1 char DataPacket[32]; int T_Out; int H_Out; bool new_data; int GustNow=-999; int AverageNow=-999; int DirectionNow=-999; int BarometerNow=-999; int WindBat=100; int RainRateNow, RainBat; int RainTotal = -1; const char ExtraSensors[6][9]= { "Shirla:","Etage:","Chamb.:","Cave:","Cellier:","Ext.:" }; //const byte ExtraSensor[5][2] = ExtraSensors; int T_Ext[10]; int H_Ext[10]; byte count = 0; unsigned long last_UpdateDisplay; class DecodeOOK { protected: byte total_bits, Min_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 buffer 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; } }; class OregonDecoderV2 : public DecodeOOK { public: OregonDecoderV2() { Min_bits = 160; } // add one bit to the packet data buffer virtual void gotBit (char value) { if(!(total_bits & 0x01)) { data[pos] = (data[pos] >> 1) | (value ? 0x80 : 00); } total_bits++; pos = total_bits >> 4; if(2 == pos) { // 80 * 2 Min_bits = 160; if(0xEA == data[0]) Min_bits = 136; if(0x5A == data[0]) Min_bits = 176; //if(0x2A == data[0]) Min_bits = 168; } if (pos >= sizeof data) { resetDecoder(); return; } state = OK; } virtual char decode (word width) { if (200 <= width && width < 1200) { byte w = width >= 700; switch (state) { case UNKNOWN: if (w != 0) { // Long pulse ++flip; } else if (16 <= flip) { // Short pulse, start bit flip = 0; state = T0; } else { // Reset decoder return -1; } break; case OK: if (w == 0) { // Short pulse state = T0; } else { // Long pulse manchester(1); } break; case T0: if (w == 0) { // Second short pulse manchester(0); } else { // Reset decoder return -1; } break; } } else { return -1; } return total_bits == Min_bits ? 1: 0; } }; OregonDecoderV2 orscV2; volatile word pulse; void ext_int_1(void) { static word last; // determine the pulse length in microseconds, for either polarity pulse = micros() - last; last += pulse; } float temperature(const byte* data) { int sign = (data[6]&0x8) ? -1 : 1; float temp = ((data[5]&0xF0) >> 4)*10 + (data[5]&0xF) + (float)(((data[4]&0xF0) >> 4) / 10.0); return sign * temp; } byte humidity(const byte* data) { return (data[7]&0xF) * 10 + ((data[6]&0xF0) >> 4); } int barometer(const byte* data) { return (data[8])+856+28;//28=correction altitude } // Ne retourne qu'un apercu de l'etat de la baterie : 10 = faible byte battery(const byte* data) { return (data[4] & 0x4) ? 10 : 90; } byte channel(const byte* data) { byte channel; switch (data[2]) { case 0x10: channel = 1; break; case 0x20: channel = 2; break; case 0x40: channel = 3; break; } return channel; } void reportSerial_new (const char* s, class DecodeOOK& decoder) { byte bid = 0; byte bid1 = 0; byte PacketID, UnitID; byte pos; const byte* data = decoder.getData(pos); Serial.print(s); Serial.print(' '); for (byte i = 0; i < pos; ++i) { Serial.print(data[i] >> 4, HEX); Serial.print(data[i] & 0x0F, HEX); } Serial.println(); UnitID = 2; PacketID = UnitID << 4 | 1; // Hi nibble UnitID, Lo nibble SensorID // Inside Temp-Hygro : THGR228N,... if(data[0] == 0x1A && data[1] == 0x2D) { switch (data[3]) { case 0xA3: { T_Ext[0] = int(temperature(data) * 100.0); H_Ext[0] = int(humidity(data) * 100.0); sendData(StationID, PacketID, T_Ext[0], H_Ext[0], 3, 0); Serial.print("Shirla, Id:"); break; } case 0xE4: { T_Ext[1] = int(temperature(data) * 100.0); H_Ext[1] = int(humidity(data) * 100.0); Serial.print("Etage, Id:"); break; } case 0xF1: { T_Ext[2] = int(temperature(data) * 100.0); H_Ext[2] = int(humidity(data) * 100.0); sendData(StationID, PacketID, T_Ext[2], H_Ext[2], 2, 0); Serial.print("Chambre, Id:"); break; } case 0x32: { T_Ext[3] = int(temperature(data) * 100.0); H_Ext[3] = int(humidity(data) * 100.0); sendData(StationID, PacketID, T_Ext[3], H_Ext[3], 0, 0); Serial.print("Cave, Id:"); break; } case 0x7D: { T_Ext[4] = int(temperature(data) * 100.0); H_Ext[4] = int(humidity(data) * 100.0); sendData(StationID, PacketID, T_Ext[4], H_Ext[4], 1, 0); Serial.print("Cellier, Id:"); break; } case 0x45: { T_Ext[5] = int(temperature(data) * 100.0); H_Ext[5] = int(humidity(data) * 100.0); Serial.print("Extérieur, Id:"); break; } case 0xC3: { T_Ext[6] = int(temperature(data) * 100.0); H_Ext[6] = int(humidity(data) * 100.0); sendData(StationID, PacketID, T_Ext[6], H_Ext[6], 4, 0); Serial.print("Soute, Id:"); break; } } //Serial.print("[THGR228N,...] Id:"); Serial.print(data[3], HEX); Serial.print(" ,Channel:"); Serial.print(channel(data)); Serial.print(" ,temp:"); Serial.print(temperature(data)); Serial.print(" ,hum:"); Serial.print(humidity(data)); Serial.print(" ,bat:"); Serial.print(battery(data)); new_data = true; Serial.println(); } // inside Temp-Hygro-Baro : BTHR918 else if (data[0] == 0x5A && data[1] == 0x6D) { Serial.print("Rdc, Id:"); //Serial.print("[BTHR918,...] Id:"); Serial.print(data[3], HEX); Serial.print(" ,Channel:"); Serial.print(channel(data)); Serial.print(" ,temp:"); Serial.print(temperature(data)); Serial.print(" ,hum:"); Serial.print(humidity(data)); Serial.print(" ,baro:"); Serial.print(barometer(data)); Serial.print(" ,bat:"); Serial.print(battery(data)); Serial.println(); T_Ext[7] = int(temperature(data) * 100.0); H_Ext[7] = int(humidity(data) * 100.0); BarometerNow = barometer(data); new_data = true; } // outside Temp-Hygro : THGR918,... else if(data[0] == 0x1A && data[1] == 0x3D) { Serial.print("EXT Id:"); Serial.print(data[3], HEX); Serial.print(" ,Channel:"); Serial.print(channel(data)); Serial.print(" ,temp:"); Serial.print(temperature(data)); Serial.print(" ,hum:"); Serial.print(humidity(data)); Serial.print(" ,bat:"); Serial.print(battery(data)); Serial.println(); T_Out = int(temperature(data) * 100.0); H_Out = int(humidity(data) * 100.0); } // Rain else if(data[0] == 0x2A && data[1] == 0x1D) { bid = 8; Serial.print("[RGR918,...] Id:"); Serial.print(data[3], HEX); Serial.print(" Rr:"); RainRateNow = ((data[5]>>4) * 100) + ((data[5] & 0x0F) * 10) + (data[4] >> 4); Serial.print(RainRateNow); RainTotal = ((data[8] & 0x0F) * 1000)+ ((data[7] >> 4) * 100) + ((data[7] & 0x0F) * 10)+ (data[6]>>4); Serial.print(" ,To:"); Serial.print(RainTotal); Serial.print("mm ,bat:"); RainBat=battery(data); Serial.print(RainBat); Serial.println(); } // Wind else if(data[0] == 0x3A && data[1] == 0x0D) { Serial.print("Vent Id:"); Serial.print(data[3], HEX); Serial.print(" Direction "); DirectionNow = ((data[5]>>4) * 100) + ((data[5] & 0x0F) * 10) + (data[4] >> 4); Serial.print(DirectionNow); Serial.print(" degrees Rafale:"); GustNow = ((data[7] & 0x0F) * 100) + ((data[6]>>4) * 10) + ((data[6] & 0x0F)) ; Serial.print(float(GustNow)/10,1); Serial.print("m/s Moyenne:"); AverageNow = ((data[8]>>4) * 100) + ((data[8] & 0x0F) * 10)+((data[7] >>4)) ; Serial.print(float(AverageNow)/10,1); Serial.print("m/s Bat:"); WindBat=battery(data); Serial.print(WindBat); //Serial.println("%"); Serial.println(); } // THN132 else if(data[0] == 0xEA && data[1] == 0x4C) { switch (data[3]) { case 0xBB: { T_Ext[8] = int(temperature(data) * 100.0); //sendData(StationID, PacketID, T_Ext[8], 0, 7, 0); Serial.print("Congel, Id:"); break; } } Serial.print("[THN132,...] Id:"); Serial.print(data[3], HEX); Serial.print(" ,Channel:"); Serial.print(channel(data)); Serial.print(" ,temp:"); Serial.print(temperature(data)); Serial.print(" ,bat:"); Serial.print(battery(data)); Serial.println(); } decoder.resetDecoder(); } // ----------------------------------------------------------------------------------------- // -------- Function to send data to RF Module --------------------------------------------- void sendData (int data0, int data1, long data2, long data3, long data4, long data5) { memset(DataPacket,0,sizeof(DataPacket)); // clean str array sprintf(DataPacket, "%d,%d,%ld,%ld,%ld,%ld", data0, data1, data2, data3, data4, data5); PORTC |= B10; //digitalWrite(TX_Power_PIN, HIGH); - Turn on power from TX module delay(50); // Wait for power to stabilize vw_send((uint8_t *)DataPacket, strlen(DataPacket)); vw_wait_tx(); } // ---------------------- Update Display ------------------------- void Update_Display() { byte PacketID, UnitID; lcd.setCursor(0, 0); lcd.print(" "); lcd.setCursor(0, 0); lcd.print(ExtraSensors[count]); lcd.print(T_Ext[count]/100.0,1); lcd.write(B11011111); lcd.print(";"); lcd.print(H_Ext[count]/100); switch (count){ case 0 : { lcd.setCursor(0, 1); lcd.print(" "); lcd.setCursor(0, 1); lcd.print("Out:"); lcd.print(T_Out/100.0,1); lcd.write(B11011111); lcd.print(";"); lcd.print(H_Out/100); break; } case 1 : { lcd.setCursor(0, 1); lcd.print(" "); lcd.setCursor(0, 1); lcd.print("Pression:"); lcd.print(BarometerNow,1); break; } case 2 : { lcd.setCursor(0, 1); lcd.print(" "); lcd.setCursor(0, 1); lcd.print("Vent:"); lcd.print(DirectionNow); lcd.print(";"); lcd.print(GustNow/10.0,1); lcd.print("/"); lcd.print(AverageNow/10.0,1); lcd.print(" m/s"); break; } case 3 : { lcd.setCursor(0, 1); lcd.print(" "); lcd.setCursor(0, 1); lcd.print("Pl.:"); if (RainTotal != -1){ lcd.print(RainTotal); lcd.print("mm; "); lcd.print(RainRateNow); } else{ lcd.print("NADA"); } break; } case 5 : { break; } } count ++; if (count > 4) count = 0; last_UpdateDisplay = millis(); } // --------------------------------------------------------------- void setup () { Serial.begin(115200); Serial.println("\n[ookDecoder]"); attachInterrupt(1, ext_int_1, CHANGE); // 0=>pin2 1=> pin3 //------------------------------------------------------------ // Setup the transmitter //------------------------------------------------------------ //DDRC = DDRC | B11; // pinMode(TX_Power_PIN, OUTPUT); & pinMode(TX_PIN, OUTPUT); pinMode(14, OUTPUT); pinMode(4, OUTPUT); vw_set_ptt_pin(4); // Transmitter ptt connected to pin A1 vw_set_tx_pin(14); // Transmitter connected to pin A0 vw_setup(1000); // Bits per second //------------------------------------------------------------ lcd.begin(); lcd.print("Coucou"); delay(1000); lcd.setCursor(0, 0); lcd.print(" "); } void loop () { static int i = 0; cli(); word p = pulse; pulse = 0; sei(); if (p != 0) { if (orscV2.nextPulse(p)) reportSerial_new("OSV2", orscV2); } //if (millis() - last_UpdateDisplay > 4000) //Update_Display(); }

Only Temp/hum sensors can be send to WeatherDuino

In
reportSerial_new subroutine you have select which sensor type and ID you like to send to WD. The function call is :


sendData(StationID, PacketID, Temp, Hum, Extra_sens_N, 0);

StationID is basically 0xA1
PacketID = UnitID << 4 | 1; // Hi nibble UnitID, Lo nibble SensorID
UnitID should be an unused TX ID (<=3)
Lo nibble = 1 = SensorID (not used in WD RX software)
0 < Extra_sens_N < 5 (N°-1 of extra sensor in CMX)


To see the OS V2 sensors that are decoded, just use a serial monitoring software (115200 bauds). you have to retain the ID of the sensors you want to send to WeatherDuino.
Serial output :
   
highlighted is a new OS temp sensor not yet recognised by the software.
that happens when battery is changed.

WD RX software modification
I use SensorID 1 in RX software to write the T° and RH % in loopdata to have Extra sensor 1 to 5 available in Cumulus.
V2.00 RX_TX.ino modification :
~line 95
change
Code:
#else else if (SensorID == 2 && UnitID == WIND_OutUnit ) #endif
to :
Code:
#else // LM Oregon sensor to loopdata extra 1-5 sensors for Cumulus else if (SensorID == 1) { //-------------- Process data from SensorID 1 -------------------------------------- byte ExtraSensorNum = RX_Data[4]; if (ExtraSensorNum < 5) { if (RX_Data[3] <= 9990) loopData.extraHumidities[ExtraSensorNum] = RX_Data[3] / 10 * 0.1; else loopData.extraHumidities[ExtraSensorNum] = 999; loopData.extraTemperatures[ExtraSensorNum] = (RX_Data[2] / 10 * 0.18) + 122.5; #if Relay_Data == 1 sendData(Relay_ID, 140 + ExtraSensorNum, RX_Data[2] / 10, RX_Data[3] / 10, 0, 0); #endif } } // -------- End processing Sensors ID1 ------------------------------------ //LM else if (SensorID == 2 && UnitID == WIND_OutUnit ) #endif

No modification in config_RX.h required

Result in CMX
   

Laurent
Reply


Messages In This Thread
Oregon to WeatherDuino gateway - by laulau - 24-12-2015, 10:27
RE: Oregon to WeatherDuino gateway - by laulau - 15-04-2016, 15:54
RE: Oregon to WeatherDuino gateway - by laulau - 21-05-2016, 00:05
RE: Oregon to WeatherDuino gateway - by werk_ag - 21-05-2016, 19:23



Users browsing this thread: 1 Guest(s)