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)