Décodage des protocoles Oregon Scientific sur Arduino (3/3)

Suite et fin de cette série (Décodage des protocoles Oregon Scientific sur Arduino (1/3), Décodage des protocoles Oregon Scientific sur Arduino (2/3)). Je vous présente aujourd’hui une modification du décodeur lui permettant de traiter les informations de toutes les sondes Oregon v2, on parlera aussi du montage et de sa portée .

[adsGrandRectangleTexte]

Modification du décodeur Oregon Scientific

Dans l’article précédant, nous avons vu comment identifier à quelle sonde nous avons à faire. Nous allons utiliser ceci pour identifier les sondes au plus tôt, c’est à dire pendant la réception des trames. Ceci va nous permettre de savoir de quelle taille devrait être la trame que nous sommes en train de recevoir. On obtient ainsi une condition de sortie du décodeur qui marchera pour toutes les sondes.

Tailles des trames :

J’ai repris le tableau de l’article précédant en y indiquant pour chaque type de sonde, la taille des trames émises :

Code Taille des trames
0x0A4D 80
0xEA4C 68
0xCA48 ??
0x1A2D 80
0xFA28 80
0x*ACC 80
0xCA2C 80
0xFAB8 80
0x1A3D 80
0x5A5D 88
0x5A6D 96
0x2A1D 84
0x2A19 92
0x1A99 88
0x1A89 ??
0x3A0D 80
0xEA7C 120
0xDA78 72
0x*AEC 104
0xEAC0 ??

Par rapport au premier article de la série, nous allons modifier la fonction virtual void gotBit (char value). Pour que le décodeur fonctionne avec toutes les sondes Oregon v2, nous allons détecter à quelle type de sonde la trame en cours de décodage appartient afin de modifier à la volé la condition de sortie du décodeur (trame de longueur variable).
En effet, l’identifiant de sonde étant codé dans les deux premiers octets, il suffit de les lires dès qu’ils sont réceptionnés :

virtual void gotBit (char value) 
{
        if(!(total_bits & 0x01))
        {
            data[pos] = (data[pos] >> 1) | (value ? 0x80 : 00);
        }
        total_bits++;
        pos = total_bits >> 4;
        if(pos == 2)
        {
          // Taille de trame par défaut (utilisée dans la majorité des sondes)
          max_bits = 160;

          // Exceptions :
          if(data[0] == 0xEA)
          {
            if(data[1] == 0x4C) max_bits = 136; // TH132N : 68 * 2
            else if(data[1] == 0x7C) max_bits = 240; // UV138 : 120 * 2
          }
          else if(data[0] == 0x5A)
          {
            if(data[1] == 0x5D) max_bits = 176; // THGR918 : 88 * 2
            else if(data[1] == 0x6D)max_bits = 192; // BTHR918N : 96 * 2
          }
          else if(data[0] == 0x1A  && data[1] == 0x99)
            max_bits = 176; // WTGR800 : 88 * 2
          else if(data[0] == 0xDA  && data[1] == 0x78)
            max_bits = 144; // UVN800 : 72 * 2
          else if((data[0] == 0x8A || data[0] == 0x9A) && data[1] == 0xEC)
            max_bits = 208; // RTGR328N 104 * 2
          else if(data[0] == 0x2A)
          {  
            if(data[1] == 0x19) max_bits = 184; // RCR800 : 92 * 2
            else if(data[1] == 0x1d) max_bits = 168; // WGR918 : 84 * 2
          }
       }

       if (pos >= sizeof data)
       {
            Serial.println("sizeof data");
            resetDecoder();
            return;
       }
       state = OK;
}

Cette trame est elle valide ? … Calcul de la checksum

J’en ai profité pour ajouter le calcul de la checksum et pour être simple Oregon Scientific à choisi des calculs de checksum différents selon les types de sondes … forcement c’est plus drôle … humm :/

Il suffit d’ajouter ces fonctions au sketch précédant et de tester le retour de l’une ou l’autre (suivant le type de sonde) dans la fonction reportSerial(…) :

  • checksum(data) pour les sondes de type THN132N
  • et checksum2(data) pour les sondes de type THGR228N
byte checksum(const byte* data)
{
  int c = ((data[6]&0xF0) >> 4) + ((data[7]&0xF)<<4);
  int s = ((Sum(6, data) + (data[6]&0xF) - 0xa) & 0xff);
  return s == c; 
}

byte checksum2(const byte* data)
{
  return data[8] == ((Sum(8, data) - 0xa) & 0xff);
}

int Sum(byte count, const byte* data)
{
  int s = 0;

  for(byte i = 0; i<count;i++)
  {
    s += (data[i]&0xF0) >> 4;
    s += (data[i]&0xF);
  }

  if(int(count) != count)
    s += (data[count]&0xF0) >> 4;

  return s;
}

La portée

La portée est très variable selon le matériel utilisé. Dans mon cas, il dépend principalement de deux choses :

  • La tension aux bornes du récepteur RF433. Plus il est proche de 5v (pour mon récepteur) meilleure est la portée.
  • Au récepteur RF433 lui-même. Certains sont plus sensibles que d’autres au « bruit », d’où les _gros_ écarts de prix.

On peut ensuite jouer sur d’autres points :

  • L’antenne. J’avais réalisé quelques tests avec une antenne type Rfxcom et la portée était meilleure, à confirmer.
  • l’électronique. On peut ajouter un filtre en entrée du récepteur pour atténuer le bruit (condensateur de découplage).

Pour ma part, j’utilise un récepteur bas de gamme à ~4€. Ci-dessous un tableau récapitulant mes différents tests avec deux cartes Arduino et différentes méthodes d’alimentation. L’antenne utilisée est un simple fil de 17.3cm.

Carte Alimentation Voltage mesuré aux bornes 5v de la carte Arduino
Portée
Mega 5v USB 4.82v 10cm
Mega Adaptateur secteur 12V 4.94v 10m avec dalle béton ou mur parpaing/brique
Duemilanove 5v USB 4.92v 10m avec dalle béton ou mur parpaing/brique
Duemilanove Adaptateur secteur 12V 4.99v +15m avec dalle béton ou mur parpaing/brique

On voit que c’est super sensible, est ce dû à mon récepteur « cheap » ? Avec une bonne alimentation, on atteint quand même déjà de bonnes distances.

J’ai reçu quelques résultats de tests d’un lecteur qui malgré un bon 5v aux bornes du récepteurs obtient une mauvaise portée. si vous faites quelques expérimentations vos résultats m’intéresse, n’hésitez pas à poster un commentaire.

Je mettrai l’article à jour en fonction des éventuels retours et après quelques tests qu’il me reste à faire : meilleur récepteur et meilleure antenne entre autre.

Schéma de montage

Pour réaliser ce montage, il vous faudra un émetteur RF433Mhz (J’utilise personnellement celui-ci). Le schéma de câblage de l’émetteur en lui même est plutôt simple, je vous laisse en juger :

schema recepteur RF433 arduino

 

Condensateur de découplage

Le découplage capacitif consiste à mettre des capacités de diverses valeurs en parallèle au point à découpler. Son but est de nettoyer la tension à découpler. Il faut placer le condensateur au plus près du point à découpler, dans notre cas, entre le gnd et le +5v du récepteur. On m’avait conseillé un condensateur de 47nF.

Conclusion

Voila, nous avons tout ce qu’il faut pour réceptionner les informations de nos chères sonde Oregon Scientific :). Avec le code ci-dessus vous devriez récupérer les trames non décodées de toutes les sondes v2.1. Coté décodage j’en suis resté aux sondes THN132N et THGR228N auxquelles j’ai ajouté le calcul de la checksum.

Une librairie propres est en court d’écriture, j’en profiterai pour y ajouter le décodage des autres type de sondes. En attendant, je vous rappelle que vous pouvez trouver tout ce dont vous avez besoin dans les sources de xpl-perl.

Vous aimerez aussi...

26 réponses

  1. Julien dit :

    Salut Olivier,

    Ne manquerait-il pas un morceau dans la fonction Sum au niveau de la boucle for ?

  2. Erwan dit :

    Bonjour,
    Excellent article !

    Je développe ma propre solution domotique depuis quelque temps en delphi/php/mysql, basé sur un RFXTRX433 de rfxcom.

    Depuis peu je m’intéresse a l’arduino.

    J’ai donc voulu combiner arduino + rf433.
    Je galérais depuis quelques jours pour décoder mes trames oregon sur mon arduino (avec un recepteur fs1000a) et cet article m’a permis d’arriver à mes fins 🙂

    Pour info, une trame vu coté arduino et une trame coté rfxcom :

    OSV2 1A2D40C4512170463EE6[THGR228N,…] Id:C4 ,Channel:3 ,temp:21.50 ,hum:67 ,bat:90

    RFXTRX433 : 0A 52 01 54 C404 00D7 43 01 89
    len=10
    type=$52 (temp_hum) sub_type=1
    id=$c404 (50180)
    temp=21,50 ($00*256+$d7 /10)
    humidity=67 ($43)
    battery=8 (bit 0-3)
    rssi=9 (bit 4-7)

    Question : serait t il possible de publier un exemple pour envoyer une trame oregon?
    On peut acheter un arduino, un DS18B20 et un TX433 pour moins de 20€ ce qui représente une alternative intéréssante à une sonde oregon.

    Merci encore pour toute cette bonne littérature !

    Erwan

    • Erwan dit :

      j’aurais du mentionner que les trames ci dessous sont en fait une seule et meme trame vu par 2 périphériques differents (arduino vs rfxtrx433).

      /Erwan

    • Olivier dit :

      Bonsoir Erwan,
      Bravo 🙂 et merci. As tu réussi à obtenir une portée correcte ?

      Concernant l’émission je ne m’y suis pas encore penché mais j’aimerai bien essayer. On pourrait même descendre sous 10€ en utilisant un « arduino standalone » voir moins avec un plus petit uc.

    • Olivier dit :

      Bonjour Erwan,

      J.ai galéré tout le we pour lire les trames de mon RFXtrx433 USB sans succès ;(
      Pourrais-tu me montrer ton code et un diagramme de confection stp?
      Merci a toi pour cette info, je pensais plus y arriver. Même le supprort chez RFXCom m’a dit que c’était impossible à lire.

      Merci a Olivier, j’ai découverts un site passionnant, plein du trucs intéressant.

      Olivier

  3. jeanfrançois85 dit :

    Bonjour, tout d’abord merci pour votre TUTO, ceci m’a permis de mettre en réseau les capteurs orégons situés dans les différentes pièces de la maison. J’ai un problème lorsque je débranche l’USB et passe en alimentation 5Volts sur l’arduino UNO. il n’y a plus de décodage.
    Pourriez vous me renseigner si dans le programme le port série doit être activé, pour la réception du signal, ou si ça vient de mon alimentation qui pourrait être trop faible.
    Et encore un grand merci .

  4. Cyril dit :

    Sinon pour faire ses propres sondes il y a les jnode, cela semble pas mal fichu et pas cher en plus (avec beaucoup de possibilité également).

  5. jeanfrançois85 dit :

    J’ai ma réponse, ça fonctionne très bien avec une alimentation 12V 1A.
    Merci

  6. DucLeto dit :

    Bonjour, merci pour ce tuto. Je suis en train de tester et j’ai des soucis de fiabilité. J’ai 3 sondes Oregon THGR122NX. Au delà de 3 mètres plus aucune trame n’est décodée, donc question portée bof bof. Mais même en mettant une sonde juste à côté du récepteur j’ai un taux de réussite sous les 50%. Je me demande s’il n’y a pas moyen de rendre le code plus « tolérant » en jouant sur le nombre de bits de préambule ou bien sur les délais? D’autant plus que j’ai mis une led sur la pin logique et je « vois » bien les trames qui viennent des sondes même lorsqu’elles sont éloignées.

  7. Roland dit :

    Bonjour Olivier,
    je découvre tes explications (billet 1-2-3) avec beaucoup d’attention car je voudrais récupérer les infos de ma sonde THR128 avec mon Arduino Uno.
    Malheureusement je suis carrément nul en programmation et ici, je ne trouve que des « morceaux » de code. Je n’arrive pas à mettre tout en place.
    Serait-il possible de poster un lien vers le code complet et fonctionnel (qu’il me suffirait de téléverser dans l’arduino) ?
    Ceci en attendant d’améliorer mes connaissances…
    Merci d’avance et bravo pour tout ce beau travail.

    • Olivier dit :

      Salut,
      Normalement tu peux prendre le code du premier article (il est complet) puis ajouter les fonctions de l’article 2 où tu veux dans le code et enfin remplacer ou ajouter celles présente dans l’article 3 … c’est vrai qu’en le disant comme ça, ça fait un peu bordélique 😉 … j’essaie de te poster ici rapidement le code complet de l’article 3.

      ++

  8. Galen dit :

    Bonjour,

    Bravo pour le boulot réalisé, je ne suis guère calé sur le sujet et je me suis pas lancé encore dans la réalisation de la chose

    je me posais une question, j’ai vu ceci http://shop.openenergymonitor.com/rfm12pi-v2-raspberry-pi-expansion-board-433-mhz/

    http://wiki.openenergymonitor.org/index.php?title=RFM12Pi_V2#Hacks.2C_Modifications_.26_Extensions

    la carte comporte un atmega128, pour renvoyer en serie vers un raspberry pi est ce que cela peut être possible d’utiliser ce hard avec le code de l’article moyennant adaptation ?

    je découvre les arduinos mais je pense que c’est jouable ?
    le but étant d’envoyer les infos de mes sondees oregon vers emoncms

    Merci de vos réponses éclairées

  9. Renaud dit :

    Salut,

    Merci pour le tuto. J’ai réussi à tout faire fonctionner avec un Compatible Uno (XDRduino) et un récepteur à quelques euros sur Ebay. Ma sonde est une THGR122NX.
    Il ne me reste plus qu’à le rendre autonome et à archiver les données.

    Encore merci

    • Renaud dit :

      Au fait, je ne vois pas le condensateur sur le schéma. Est-il vraiment nécessaire ?

    • Olivier dit :

      De rien 🙂
      J’emménage bientôt dans ma nouvelle maison et je vais donc tout reprendre ça de plus près.
      Je pense faire des versions autonomes également, je mettrai ma solution ici mais si tu avance n’hésite pas à donner des nouvelles 🙂

  10. Charly86 dit :

    Salut,
    Merci pour ces articles très intéressants, je les avait mis sous le coude et j’ai pris le temps de les tester aujourd’hui. Aurais-tu la possibilité de poster le sketch complet ? Car jusqu’à la partie 1 et 2 çà fonctionne mais la fonction gotBit() de la partie 3 çà coince chez moi. J’imagine que c’est celle de la classe OregonDecoderV2 qu’il faut modifier ?
    seulement la nouvelle variable max_bits que tu préconises n’est pas déclarée, j’ai donc regardé aussi ce qu’elle faisait, mais à part sont affection je ne vois pas à quoi elle sert et quand est testé cette variable ?
    J’ai raté un truc ou c’est une coquille ?
    Merci par avance pour ton aide

    • Olivier dit :

      Salut,
      Bien vu, si je ne dis pas de bêtises il faut le déclarer dans la classe DecodeOOK

      class DecodeOOK {
      protected:
      byte total_bits, max_bits, bits, flip, state, pos, data[25];
      [...]

      et modifier la condition de sortie du décodeur, et cette partie n’apparait pas … un oubli de ma part. Il faut que je remette la main sur le code complet.
      Je le post ce soir ici même.

      • Olivier dit :

        je viens de voir que j’ai fais la même promesse l’année dernière … pas bien 😉 … je me m’auto-flagellerai une fois le code en ligne!

  11. Charly86 dit :

    Ahhh, tu me rassures, je vois qu’il n’y a pas que moi qui peine avec mes lignes codes epparpillés un peu partout, c’est pas bien bouhhhh :-):-)

    Merci pour tes éclaircissements, pour le moment je suis passé sur autre chose, mon récepteur doit être pas terrible car je ne vois que 10% de mes sondes passer, c’est pour ça que je voulais essayer la partie 3 avec les autres types de sondes pour vérifier si je les recevais. J’attends donc pour essayer à nouveau.

    Pour le code si tu veux, je peux l’héberger sur mon github, je trouve que çà reste quand même très simple et pratique, et de plus on peu tous travailler dessus pour les mises à jour. Bon si tu t’auto-flagelles une fois le code en ligne, je ne suis plus sur de ta motivation ;-);-)

  12. SEB dit :

    Bonjour et merci pour ton travail .

    Est-il possible d’avoir le code intéral modifié comme tu le dis plus haut stp ?

    Merci par avance.

  13. marc dit :

    salut ,
    Ou peut on trouver le code complet ?

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *