Oregon Scientific sensors with Raspberry PI

After mixing different source of information, I was able to decode some Oregon Scientific sensors to get Temperature and Humidity indication, over the air, on 433.92MHz, with a Raspberry PI system. This article gives some details of this adventure …

You follow this implementation at your own risk…

If you are interrested in this article, you could also take a look here where you can find a RF433 shield and the associated code

 

RPI B+ & 2

With RPI B+ and RPI 2 the access to the Interrupt at user level is a problem as the response time is changing due to schedulling policy. For this reason the best way is to use a kernel driver : here you can find the elements to make a kernel driver for RF433 to do this.

By the way, this post have all the information you need to get start but basically you should loose some of the message due to scheduling. Kernel driver should fix that.

Hardware stack

The hardware is a simple raspberry PI with a 433Mhz receiver like this one. The reception quality is not the best you can get, but the price is really low cost. I’ll test different receivers in a future paper, so follow my feed to get these results. The rule is to get an AM/ASK receiver for 433,92Mhz (usually call 433 receiver). This article compares the different receivers I used.

The receiver is working in 5V, as the RPI GPIO are 3.3V I had a voltage division on the output. You can also use a 3.3V receiver which is what I’m doing now. You can optionally add the led on the reception pin to see data and noise reception.

GPIO used is the wiringPi GPIO0 corresponding to PIN 11 (GPIO17)

400px-RaspberryPi_GIP_WiringPi_pinout

 

 

 

 

 

Here is some schema of what I made.

photo(2)The 10K and 15K resistor are transforming a +5V output into a +3.3V to be GPIO compliant.

The 1K resistor and Led can be removed they just indicate what is received from the 433 receiver.

The strange stuff on the left side is the antenna.

 

Low level software stack

The interrupt management is coming from RCSwitch project, but as the decoding function differ, I mostly reuse the Interrupt handler. The GPIO / Interrupt mechanism are based on wiringPI library. RCSwitch as been simplified, the encoding/decoding part has been externalized to join the other codec library:

The initialization is confiuring pins & interrupt handler

RCSwitch::RCSwitch(int rxpin, int txpin) {

        RCSwitch::OokAvailableCode = false;
        RCSwitch::OokReceivedCode[0] = '\0';
        rcswp1.configure(1,this);

        if (rxpin != -1 ) {
                this->enableReceive(rxpin);
        } else this->nReceiverInterrupt = -1;

        if (txpin != -1 ) {
                this->enableTransmit(txpin);
        } else this->nTransmitterPin = -1;

}
/**
 * Enable transmissions
 *
 * @param nTransmitterPin    Arduino Pin to which the sender is connected to
 */
void RCSwitch::enableTransmit(int nTransmitterPin) {
  this->nTransmitterPin = nTransmitterPin;
  pinMode(this->nTransmitterPin, OUTPUT);
  digitalWrite(this->nTransmitterPin, LOW);
}
/**
 * Enable receiving data
 */
void RCSwitch::enableReceive(int interrupt) {
  this->nReceiverInterrupt = interrupt;
  this->enableReceive();
}

void RCSwitch::enableReceive() {
  if (this->nReceiverInterrupt != -1) {
    wiringPiISR(this->nReceiverInterrupt, INT_EDGE_BOTH, &handleInterrupt);
  }
}

The interrupt handler manage signal by computing duration between two signal fronts and transfer it to the different codec you want to involved :

// ==============================================
// Interrupt Handler to manage the different protocols
void RCSwitch::handleInterrupt() {

  static unsigned int duration;
   static unsigned long lastTime;

  long time = micros();
  duration = time - lastTime;
  lastTime = time;
  word p = (unsigned short int) duration;

  // Avoid re-entry
  if ( !OokAvailableCode ) {            // avoid reentrance -- wait until data is read
          if (orscV2.nextPulse(p))      { RCSwitch::OokAvailableCode = true; orscV2.sprint("OSV2 ",RCSwitch::OokReceivedCode); orscV2.resetDecoder(); }
          if (orscV3.nextPulse(p))      { RCSwitch::OokAvailableCode = true; orscV3.sprint("OSV3 ",RCSwitch::OokReceivedCode); orscV3.resetDecoder(); }
          if (rcswp1.nextPulse(p))      { RCSwitch::OokAvailableCode = true; rcswp1.sprint("ALRM ",RCSwitch::OokReceivedCode); rcswp1.resetDecoder(); }

        //  if (cres.nextPulse(p))      { cres.print("CRES"); cres.resetDecoder(); }
        //  if (kaku.nextPulse(p))      { kaku.print("KAKU"); kaku.resetDecoder(); }
        //  if (xrf.nextPulse(p))       { xrf.print("XRF"); xrf.resetDecoder(); }
        //  if (hez.nextPulse(p))       { hez.print("HEZ"); hez.resetDecoder(); }
        //  if (viso.nextPulse(p))      { viso.print("VISO"); viso.resetDecoder(); }
        //  if (emx.nextPulse(p))       { emx.print("EMX"); emx.resetDecoder(); }
        //  if (ksx.nextPulse(p))       { ksx.print("KSX"); ksx.resetDecoder(); }
        //  if (fsx.nextPulse(p))       { fsx.print("FSX"); fsx.resetDecoder(); }
  }

}

The full modified RCSwitch.cpp and RCSwitch.h are available for download here :

RCSwitch

The specific Oregon Scientific decoding is operated by another library RcOok made for Arduino, I mostly update this library to make cleaner code and adapt it for C++ and RapsberryPi and add the RCSwitch codec in it.

The library can be found here :

RcOok

 

High level software stack

A thread is waiting for the Interrupt flags to get the decoded data and analyse these data to extract sensor element from it.

The kind of message received from my TNGR222 are like

OSV2 1A2D1002 502060552A4C

The first step is to reverse order of quartet in each byte to get :

OSV2 A 1D20 1 20 0 502 0 655 2A 4C

Last 4 bytes are not swapped. Here is the interpretation of these data:

  • OSV2 – is a string added by decoder to identify the protocol
  • A – is a sync quartet, it is not to be considered a data
  • 1D20 – is the Oregon device ID (here THGR122NX)
  • 1 – is the channel, values are 1,2,4 for channel 1,2,3
  • 20 – is a rolling and random value changed after each reset
  • 0 – is battery flag, battery is low when flag have bit 2 set (&4)
  • 502 – is reversed BCD temperature value (here 20.5°C)
  • 0 – is temperature sign, here “+”
  • 655 – is reversed BCD humidity value (here 55.6%)
  • 2A – is a quartet checksum starting at deviceID
  • 4C – is the crc value starting at deviceID

Validate the received frame with CRC & CheckSum

  • CheckSum is calculated on the following sub string
1D20 1 20 0 502 0 655

The result is the sum of each quartet (1+D+2+0+1+2+0+0+5+0+2+0+6+5+5) = 42 = 0X2A.

  • CRC is a CRC8 calculated with init 0x43 and CrcPoly 0x07. The CRC is taking into consideration not all the fields : rolling id avoid in the computation. so it is based on :
1D20 1 0 502 0 655

As the number of quartet is odd, the program add a CRC8 quartet computation at the end.

This CRC is working correctly on this device, but on a second sensor THGN132N this is not working. That’s why the check has been removed in the code.

See attached Sensor class for details

Exposing the values

The last part is to extract the values from the received data. The included library manage 3 type of sensors :

  • THGR122NX
  • THGN132N
  • THN132N

The decoding process looks like this :

 bool OregonSensorV2::decode_THN132N(char * pt) {

                char channel; int ichannel;                             // values 1,2,4
                char rolling[3]; int irolling;
                char battery; int ibattery;                             // value & 0x4
                char temp[4]; double dtemp;                             // Temp in BCD
                char tempS;     int itempS;                                     // Sign 0 = positif
                char checksum[3]; int ichecksum;
                int  len = strlen(pt);

                if ( len == 16 ) {
                        channel = pt[4];
                        rolling[0]=pt[7]; rolling[1]=pt[6]; rolling[2]='\0';
                        battery = pt[9];
                        temp[0] = pt[10] ; temp[1] = pt[11] ; 
                         temp[2] = pt[8] ; temp[3] = '\0';
                        tempS = pt[13];
                        checksum[0] = pt[15];   checksum[1] = pt[12]; 
                         checksum[2] = '\0';

                        // Conversion to int value
                        ichannel = getIntFromChar(channel);
                        irolling = getIntFromString(rolling);
                        ibattery = getIntFromChar(battery) & 0x04;
                        itempS = getIntFromChar(tempS) & 0x08;
                        ichecksum = getIntFromString(checksum);
                        dtemp = getDoubleFromString(temp);

                        // Check SUM
                        int _sum = getIntFromChar(pt[0]);
                        for ( int i = 2 ; i <= 11 ; i++ ) _sum += getIntFromChar(pt[i]);
                        _sum += getIntFromChar(pt[13]);

The full decoding class can be downloaded here :

Sensor

This entry was posted in Hardware and tagged , , . Bookmark the permalink.

65 Responses to Oregon Scientific sensors with Raspberry PI

  1. Romus says:

    Thank you for the post! I tried your code, but it was not working. I had no interrupt (((

    • Paul says:

      Check if the GPIO configuration is the right one depending on your schematics. you can also add a led on the Receive PIN. if not blinking, it means your receiver is not receiving anything. If blinking, you should have some interrupts.
      Hope it helps

      • Romus says:

        Ok, I had all interrupts, but decoding is not working. In RcOok library the variable “state” is always UNKNOWN. But I found the true code from the 433 MHz module with my oscilloscope.
        Also you should add, that 5V output in Rasspberry is very noisy. The most of modules can work with 3.3 V power supply.

      • Paul says:

        Personally i’m using a 3.3V receiver but I experience good results also with other 5V receivers. If not decoded, did you use one of the Oregon devices listed as supported in my source code ? I did not test all the Oregon protocol (V1,V2,V3) but I did not had any issue with the one used by the tested devices.

  2. Galen says:

    Thanks for the post

    Merci beaucoup pile poil ce que je cherchais :d

  3. Stefan says:

    Hi, thanks for your post.
    Can you give me a hint how to compile your modification? I get an compiler exception based on constructor with 0 arguments in send.cpp. Against which version did you modify the sources?

    and the other question is how to use your sensor decoder? compile it as an output file?

    thanks in advance
    stefan

    • Paul says:

      Hi Stefan, my source code is not a global project but an extract from a bigger one i can ´t provide entirely. So you have to build your own main file / call the function provided.
      I m really busy by the global project but soon as i will have some free time I will publish a fully usable package.
      Paul

  4. Romaric says:

    Hello,

    I have tried your code (with some adaptations) and it works like a charm.
    I will update it in terms of OS v3 decoding capacities.
    By the way, the code is quite CPU consuming: do you have the same experience and hints to limit that consumption ?
    Regards.

    • Paul says:

      Assuming cpu consumption is related to irq frequency the quality of the receiver is important to reduce noise. By the way, I did not look at this so much.

  5. Eric says:

    Bonjour, comment appeller la classe Sensor depuis
    une fonction main()
    j’ai une connaissance limité de c++

    quand je cree une instance de sensor j’ai une erreur a la compilation du
    style
    ” error: invalid abstract return type for function ‘Sensor mysensor(char*)’
    Sensor.h:22:7: note: because the following virtual functions are pure within ‘Sensor’:
    je dois surement pas l’appeler correctement,
    merci

    • Eric says:

      pour le moment j’arrive a afficher les trames,
      j’aimerais chainer avec la casses sensor pour interpreter,ls valeurs

      root@raspberrypi:~/wiringPi/433Utils/RPi_utils# ./RecfOregon
      * DecodeOOK::sprint() – received [OSV2 3A0D006F400800000031]
      * DecodeOOK::sprint() – received [CRES AEEEFFFFEFAFFBFFFAEBFFFFFFFFFFFFAFEFAEBB0E]
      * DecodeOOK::sprint() – received [HEZ FFC9E79C9C9303]
      * DecodeOOK::sprint() – received [OSV2 5A6D00EE442140449E31]
      * DecodeOOK::sprint() – received [CRES AABAEEFFFFBEBEEBABFEFAFFEBEBEBFEEEBEFBEEEEBA3B]
      * DecodeOOK::sprint() – received [HEZ CEE79C7372CE01]
      * DecodeOOK::sprint() – received [OSV2 5A6D00EE442140449E31]
      * DecodeOOK::sprint() – received [CRES AABAEEFFFFBEBEEBABFEFAFFEBEBEBFEEEBEFBEEEEBA3B]
      * DecodeOOK::sprint() – received [HEZ CEE79C7372CE01]
      * DecodeOOK::sprint() – received [OSV2 EA4C2028142010730000]
      * DecodeOOK::sprint() – received [OSV2 3A0D006F400800000031]
      * DecodeOOK::sprint() – received [CRES AEEEFFFFEFAFFBFFFAEBFFFFFFFFFFFFAFEFAEBB0E]
      * DecodeOOK::sprint() – received [HEZ FFC9E79C9C9303]

      • Paul says:

        First thing : in your trace I see HEZ + CRES + OSV2 Frame detection, it means that you have activated all the decoding system. It seams that the same message can be interpreted different way depending on decoding engine. If you are using Oregon, you can activate only orscv2 to simplify and optimize.

    • Paul says:

      main could look something like :

      main() {
      RCSwitch * rc = new RCSwitch(RXPIN,TXPIN);
      while ( 1 ) {
      if ( rc->OokAvailable() ) {
      char message[512];
      rc->getOokCode(message);
      Sensor * s = Sensor::getRightSensor(message);
      if ( s != NULL ) {
      printf("Temp : %f\n",s->getTemperature());
      }
      delete s;
      }
      usleep(1000);
      }
      }

      As I wrote it w/o had compiled this peace of code, don’t hesitate to correct my bugs !

      • Eric says:

        Hi Paul,
        Thanks for your exemple code,
        i try it this afternoon,
        my projet is just make a graphic web page, like Oregon weather station
        with the sensor’s Values
        i, Will deactivate all other decoder , than Oregon.

      • Eric says:

        Oooopss ! Paul i have this error at line:
        Sensor * s = Sensor.getRightSensor(mesage);

      • Paul says:

        example code updated.

      • dk says:

        Dear Paul,
        I added the needed includes and tried to complie your code, but unfrotunately I get this error:


        $ gcc oregon.cpp -o oregon
        In file included from oregon.cpp:1:0:
        Sensor.h:41:2: error: âtime_tâ does not name a type
        Sensor.h:70:2: error: âtime_tâ does not name a type

        What should I do to fix this please?
        Another question RXPIN and TXPIN are the pins used following the wiringpi numbering?
        Thank you for your kind answer,
        dk

      • Paul says:

        Take a look to the RFRPI post. It should also work with you design and the githum code is containing the Makefile to build it. I think this should solve your issue. For RXPIN & TXPIN you right.

  6. Eric says:

    Hi, Paul, It’s perfect, it works,
    Thanks
    I Think juste change,

    RCSwitch rc = new RCSwitch(RXPIN,TXPIN); to

    RCSwitch * rc = new RCSwitch(RXPIN,TXPIN);

  7. Daniele says:

    Hi,

    first at all thanks to share your work 😉

    could you tell me if it is supposed to work with the temperature and humidity sensors of Ninjablocks ?
    (http://ninjablocks.com/collections/all/products/temperature-and-humidity-sensor)

    Thanks

  8. Matteo says:

    Paul excelent work !

    The ericnosense code has some problems in getIntFromChar() function. Paul, when do you think you will publish the new version ?

  9. Dave Black says:

    Hi

    this is great work, many thanks; I managed to get everything working and wanted to give something back. So I did a little modification and added json file output to test.cpp (so you can now build a webpage with a dials etc.).

    The files are all up on github:

    git clone https://github.com/daveblackuk/RPI_Oregan.git
    cd RPI_Oregan
    Make
    ./test jsonfile.txt

    This is unsupported but hopefully will help some people get this working

    /DB

    • Paul says:

      Thank you Dave for your input.
      I planned to do something like this soon, so you’ve made most of the work ! thank you.

  10. AndyLicht says:

    Hi,
    thanks for these great webpresentation. I allso want to receive the signal of a 433MHz weathersensor. I´ve installed thewiringPi and 433Utils and it looks great. So now, i do not understand how i can use your libs, i´ve replaced the origin files of RCSwitch with yours and I also copied the Rc0ok-Files to these directory, but how can i use it?
    with best regards andy

  11. Olivier says:

    Hi,

    is this a new version of your tested receiver? http://de.rs-online.com/web/p/low-power-funkmodule/7424484/ And can this be used by the PI, too?! THX.

  12. choco62 says:

    Hello !
    Good job…
    Je cherche à décoder les indications de température et humidité de mes sondes THGR328N, mais pour l’instant, je n’y suis pas parvenu.
    La raison principale étant sûrement que je n’y connais rien en C/C++.
    J’ai tenté un “git clone”, suivi d’une modification de numéro de GPIO dans le test.cpp avant de faire un “make”… Mais lorsque je lance un ./test json.txt, j’obtiens juste :
    “datetime,temperature,humidity,channel”
    … et pis c’est tout.
    Où est (sont) l'(les) erreur(s) ?
    Merci.

  13. Seb D says:

    Hello !
    Thanks a lot for this good job.
    J’ai cloné le dépot sur github, mais malheureusement, mes sondes THGR328N ne semblent pas reconnues par le décodeur… Voici ce que j’obtiens en mode sensor_debug + sensor_trace :

    Seb@raspberrypi:~/RPI_Oregan$ sudo ./test json.txt
    datetime,temperature,humidity,channel
    Sensor::getRightSensor – create of (OSV2 AACC435A8024604454BE)
    Sensor::getRightSensor – create OregonSensorV2
    OSV2 – decode : id(ACC3)(0xACC3)
    2014-07-01 13:53:05,0.000000,0.000000,-1
    Sensor::getRightSensor – create of (OSV2 9ACC435A8024604453D8)
    Sensor::getRightSensor – create OregonSensorV2
    OSV2 – decode : id(9CC3)(0x9CC3)
    2014-07-01 13:54:12,0.000000,0.000000,-1

    • Paul says:

      Hello, THGR328N is not yet supported in the code, do not hesitate to add it and create a pull request. I assume it should be something like another thermal/hygro sensor. I do not have this sensor to add it so if you offer me one, I’ll add the code.
      Paul

      • choco62 says:

        Hi !
        En suivant les indications, j’ai essayé d’interpréter mes trames.
        Par exemple :
        create of (OSV2 9ACC435A8024604453D8).
        First i reverse order…
        A 9CC3 4 A5 0 842 0 64 4 35 8D
        ID : 9CC3 (change à chaque émission *CC3)
        Channel : 4
        Rolling code : A5
        Battery : 0
        Temp : 24,8°C
        Signe : 0
        Hygro : 46%
        ???? : 4 (me demande bien à quoi cela peut correspondre).
        Checksum : 35
        CRC: 8D

        J’en suis là.
        Si cela peut aider…

      • Paul says:

        Thank you for your feed back, do not hesitate to create a pull request or sending me your code back to merge it in the main for other users.

      • Seb D says:

        Salut !
        …et sincèrement désolé pour les posts multiples… ai pas tout compris.
        J’ai un peu avancé dans le décodage des trames des THGR328N.
        En fait, mis à part le code “Device Id” dont le premier caractère change à chaque émission, la structure globale semble identique à celle des trames des THGR122NX.
        En ajoutant quelques “case 0x?CC3 …”, dans lesquels le ? est remplacé par l’un des caractères apparaissant le plus souvent dans ce device Id (à savoir A, B, C, D, ou 9) dans le switch(iSensorId), appelant la fonction decode_ THGR122NX(pt), je récupère bien la température et l’hygrométrie.
        …mais je n’ai encore aucune idée de l’utilité du caractère précédant le checksum.
        Voilà… et merci encore pour tout ça !

  14. Alexcat says:

    Good work Paul!
    I have an Oregon sensor RTHN318, that broadcast temperature, humidity and the atomic clock time received from the DCF77 signal.
    Below there is an output of your software.

    Version (0.1) Branch (beta) Build date(20141030)
    EventManager::enqueue() – enqueue ((null))
    EventManager::eventLoop() – proceed INIT
    * Core_433::receptionLoop() – received message [OSV2 AADC238A3020F083]
    EventManager::enqueue() – enqueue (OSV2 AADC238A3020F083)
    EventManager::eventLoop() – proceed GETSENSORDATA
    * Core_433::receptionLoop() – received message [OSV2 AADC238A3020F083]
    EventManager::enqueue() – enqueue (OSV2 AADC238A3020F083)
    EventManager::eventLoop() – proceed GETSENSORDATA
    * Core_433::receptionLoop() – received message [OSV2 9ADC238A3020E0E3]
    EventManager::enqueue() – enqueue (OSV2 9ADC238A3020E0E3)
    EventManager::eventLoop() – proceed GETSENSORDATA
    * Core_433::receptionLoop() – received message [OSV2 9ADC238A3020E0E3]
    EventManager::enqueue() – enqueue (OSV2 9ADC238A3020E0E3)
    EventManager::eventLoop() – proceed GETSENSORDATA
    * Core_433::receptionLoop() – received message [OSV2 0AFC238A82748110A345]
    EventManager::enqueue() – enqueue (OSV2 0AFC238A82748110A345)
    * Core_433::receptionLoop() – received message [OSV2 0AFC238A92748110A345]
    EventManager::enqueue() – enqueue (OSV2 0AFC238A92748110A345)
    EventManager::eventLoop() – proceed GETSENSORDATA
    EventManager::eventLoop() – proceed GETSENSORDATA
    * Core_433::receptionLoop() – received message [OSV2 DADC238A30202064]
    EventManager::enqueue() – enqueue (OSV2 DADC238A30202064)
    EventManager::eventLoop() – proceed GETSENSORDATA
    * Core_433::receptionLoop() – received message [OSV2 DADC238A30202064]
    EventManager::enqueue() – enqueue (OSV2 DADC238A30202064)
    EventManager::eventLoop() – proceed GETSENSORDATA
    * Core_433::receptionLoop() – received message [OSV2 CADC238A30201044]
    EventManager::enqueue() – enqueue (OSV2 CADC238A30201044)
    EventManager::eventLoop() – proceed GETSENSORDATA
    * Core_433::receptionLoop() – received message [OSV2 CADC238A30201044]
    EventManager::enqueue() – enqueue (OSV2 CADC238A30201044)
    EventManager::eventLoop() – proceed GETSENSORDATA
    * Core_433::receptionLoop() – received message [OSV2 BADC238A302000A4]
    EventManager::enqueue() – enqueue (OSV2 BADC238A302000A4)
    EventManager::eventLoop() – proceed GETSENSORDATA
    * Core_433::receptionLoop() – received message [OSV2 BADC238A302000A4]
    EventManager::enqueue() – enqueue (OSV2 BADC238A302000A4)
    EventManager::eventLoop() – proceed GETSENSORDATA
    * Core_433::receptionLoop() – received message [OSV2 AADC238A3020F083]
    EventManager::enqueue() – enqueue (OSV2 AADC238A3020F083)
    EventManager::eventLoop() – proceed GETSENSORDATA
    * Core_433::receptionLoop() – received message [OSV2 AADC238A3020F083]
    EventManager::enqueue() – enqueue (OSV2 AADC238A3020F083)
    EventManager::eventLoop() – proceed GETSENSORDATA
    * Core_433::receptionLoop() – received message [OSV2 9ADC238A3020E0E3]
    EventManager::enqueue() – enqueue (OSV2 9ADC238A3020E0E3)
    EventManager::eventLoop() – proceed GETSENSORDATA
    * Core_433::receptionLoop() – received message [OSV2 9ADC238A3020E0E3]
    EventManager::enqueue() – enqueue (OSV2 9ADC238A3020E0E3)

    The output was captured the 31 October 2014.
    Do you have a plan to integrate the decoder of this type of sensor?
    If you want, I can post more output logs.
    Thank you

    • Paul says:

      Will not doing soon, but if someone else can, I’ll integrate the code to the main branch 😉

    • Andy says:

      I’m 3 years late but I came across this post whilst searching to find out if I could avoid spending 50euros on a replacement RTHN318. Unfortunately, I transmitted the codes you gave above but nothing happened so I was forced to spend that 50euros 🙁 However, once I had the replacement I could decode it and that’s when I saw the problem. Your codes are truncated. The temperature codes are 17 nibbles long whilst the time codes are 26. I’ve not looked at the code so I don’t know why it is truncated. But here’s the decoding:

      Temp codes: 9DC3 – DDC3

      A[ID:4][Channel:1][Code:2][Flags:1][Temp:4][Sum:2][CRC:2]
      Flags: Bit 3 = Recently reset, Bit 2: Low Battery, Bits 1:0: Unknown at present
      Temp: Nibbles 0-2, BCD coded temp in high to low digit order, Nibble 3 Bit 3 is set if -ve
      Sum: Sum of all nibbles except preamble
      CRC: CRC-8-CCITT. The Code/preamble nibbles aren’t considered

      OSV2 DADC238A30202064 = ID:DDC3, Channel 2, Code A8, Temp 20.3, Sum 42, CRC = ?6 (Should be 56)

      Time code: 0CF3

      A[ID:4][Channel:1][Code:2][Flags:1][Sec:2][Min:2][Hour:2][Day:2][Month:1][Weekday:1][Year:2][Code2?:1][Sum:2][CRC:2]
      Flags: Bit 3 = Recently reset, Bit 2: Low Battery, Bit 1: Unknown at present, Bit:0 DST (I think)
      Time values are BCD coded high to low digit order
      Weekday: 1=Sunday, 7=Saturday
      Code2: Seems to be static until reset so I think it’s another rolling code. 2 nibbles long and therefore transmitted over 2 messages
      Sum: Sum of all nibbles except preamble
      CRC: CRC-8-CCITT. The Code/preamble nibbles aren’t considered

      OSV2 0AFC238A82748110A345 = ID:0CF3, Channel 2, Code A8,Time (No DST)=08:17:48 Fri 31/10/1? Then it stops

      Hope this saves someone 50euros.

      Andy

  15. Martin Raatz says:

    THGR328N : Temp + Humidity

    same as THGRN228NX with Channel 1-5

    to get the channel:
    this->channel = ichannel;

  16. francis says:

    Bonjou
    Je viens de découvrir votre site, c’est une mine d’or 🙂

    La tension du signal sur la broche data du recepteur dont vos mettez le lien serait de 2.5v (hackspark, Receiver Data Output: High – 1/2 Vcc, Low – 0.7v) est-ce qu’il faut quand même convertir en 3.3v ?

    Merci
    Francis.

    • Paul says:

      Thank you francis for your feedback. No need to convert to 3.3V as 2.5V is equal to HIGH as 3.3V in the GPIO point of view.

  17. martin says:

    Anyone manage to decode the OSV3 rf signal. Does this seems right?

    OSV3 00000000E0FFFF010000
    OSV3 FA281435602280834330
    OSV3 FEFFFF1F000000FCFFFF
    OSV3 00000000000000000000
    OSV3 000000C0FFFFFF070000
    OSV3 00000000000000000000
    OSV3 000000E0FFFFFF010000

    Thanks.

  18. philippe hervier says:

    I just found the correct code to compute the CRC8 at the end of the THGR122NX message. There was an error in the function : the instruction “oCRC ^= c;” should be after the test, so the ID is completely ignored. With the init value of 0x3c the correct CRC8 is compluted for all my sensors.

  19. Claudio says:

    Ciao,
    I’ve a THGR132N sensor, a cheap 433MH reciever and a Raspberry PI B+. I’ve compiled your sources (and DaveBlack one) but I don’t have any output: led is blinking, interrupt is working but it seems that there are any message to detect.
    I’ve uncommented #define SENSORDEBUG and #define SENSORTRACE without effect.
    Do you know if with B+ model RcOok timing is working?

    • Paul says:

      With RPI B+ and RPI2 you may have trouble as the scheduler is acting during the reception of the frame and in many case it will disturb emission and reception. I do not recommend to use my code on RPI2 and RPIB+ By the way, it should work but not every time, so your problem can be somewhere else. I started working on a kernel module and another solution but yet not finished as I have many thing to work on in parallel. I’ll update the post when a solution will be here.

  20. ced says:

    Hi,
    Thanks for your great job Dave.
    I managed to get it work on my RPi B 2.
    I dream that someone can adapt this to a jeedom plugin or domoticz 😉
    Another question, which kind of antenna do you use for RF 433 cheap module (433MHz-Superheterodyne-3400-RF-Transmitter-and-Receiver-link).
    I got this one from ebay but I only have a 1 meter signal range with a simple wire plugged to the antenna pin.
    Thanks in advance for your help.
    Regards

  21. Lars Klassen says:

    Something to keep in mind:

    I’m testing this with a THN802 Oregon Temperature Sensor which doesn’t send Humidity. It runs on OoK OSV3 but the data length isn’t 80 bits long. I notice in the RcOok Class that for the V3 pulse function, the function expects 80 bits of data to enable the OokAvailable flag. This is not the case for the THN802 sensor which doesn’t send Humidity data, so the length for this sensor is 68 bits (the BCD values are 12 bits long, so 12 bits less in this case).

    Someone might come across this too, with sensors that have more or less data.

  22. Guillaume says:

    Hi,
    Very nice article

    Does it work with a rpi pi Zero ?

    Regards

  23. Matthew says:

    Hi Paul, thank you for posting up this detail.
    I’ve implemented this on an RPI2 (well, I got it from github OregonPi, looks the same though), and can successfully read from a OS sensor:
    OSV2 1A2D103700500C05319C
    The sensor is on it’s way out (as you may be able to tell), I’m wondering if you have been able to successfully encode any of these sensors (probably in C++, similar to your above work)? I’m trying to perform it in Python, but from the transmitted waveform, it looks like I’m running into hardware issues, where during transmission the IO misses a few beats, which corrupts the signal. Have you had any luck at this? Happy to share this python code if you want to bounce some ideas.
    Thanks in advance,
    -Matthew

    • Matthew says:

      Following up on my note; I remembered how I accomplished this for other RF devices (powerpoints, fans) and the workaround was to send the code multiple times (I’m told this is also called “repetition coding”) as the hardware doesn’t form the signal properly every time. So using your decoder, I was able to successfully read the code sent from the RPi [finally!]. I sent it around 20 times (that’s 20 pairs of code, as each code is sent twice with a 10.9ms spacing), and received it 4 times. This send/receive ratio didn’t change by much over testing this in multiple ways (eg. changing channel, changing temp/humidity/rolling code), but right now I can only assume it is indicative of the very cheap RF transmitter I’ve bought, as I know (and can see) the GPIO can run much faster than 1024Hz without losing quality.
      Best regards,
      -Matthew

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.