Ubiquitous Computing

Aller au contenu | Aller au menu | Aller à la recherche

Décodage de sondes de températures TFA Dostmann 30.3208.02 avec Arduino

Voici donc mon premier billet pour un projet Arduino, en l’occurrence le décodage et exploitation de sondes de températures. Il S'agit d'un module faisant partie d'un ensemble de quatre :

  1. Radio-pilotage DCF77 d'une horloge I2C DS3221. Mise à jour : Le DCF77 tout en monopolisant beaucoup de ressources est loin de garantir des résultats. Mais comme le projet est branché sur l'Internet, rien de plus facile d'obtenir le temps Internet via le NTP.
  2. Affichage sur une matrice LED de l'heure de cette horloge I2C et des éphémérides.
  3. Réception, décodage et réémission en I2C des sondes de températures. (le module présenté ici).
  4. Exploitation de ces températures reçues en I2C (affichages LCD et Matrice, stockage SD et envoi FTP).

Les trois premiers modules autour de µC Nano, le quatrième en Méga, tous reliés en I2C (horloge, températures et humidité)

À noter qu'il y a moyen de tout faire ou presque avec un seul module Mega, mais les affichages sur matrices seront fixes. En effet, ces animations consomment du temps machine incompatible avec celui pris pour la réception des valeurs.

Autre remarque : je ne vais pas vous apprendre à programmer de l'Arduino : je partage.

Les sondes, ou satellites

J'avais donc des sondes que l'on trouve (encore) facilement chez Amazon [1] [2]

Thermo-hygromètre sans fil TFA Klima-Monitor + 3 capteurs.jpg, déc. 2019 
TFA Dostmann 30.3208.02.jpg, déc. 2019


Vous remarquerez qu'il vaut mieux acheter un ou des ensembles que les sondes séparément : La sonde seule fait +/- €20, mais acheter 3 ensembles ramène la sonde à €16 plus 3 « centrales d'affichage gratuites ».
Les sondes possèdent des micro-interrupteurs DIP permettant de choisir 8 canaux (3 bits) . Les relevés 4 à 8 sont, en plus de la température locale, affichées alternativement sur la dernière ligne de ces récepteurs.

Le décodage des trames

La première difficulté a été de trouver comment fonctionne ces sondes. Un petit tour sur quelques forum m'ont permis de trouver qu'elles utilisent le codage Manchester[3]
Heureusement, il existe un excellent travail commis en 2015 par Rob Ward, permettant d'écouter ce type de satellites [4] et puis de chercher à comprendre la suite des chiffres binaires.
Donc, il faut commencer par brancher un récepteur 433 MHz, et pour le bien superhétérodyne, surtout si vous avez des grandes distances ou/et des murs épais. Vous l'achetez où vous voulez, Amazon, eBay, Ali ou ailleurs. Je dois dire que je ne suis pas déçu par le matériel chinois, d'autant plus que j'ai des conditions environnementales difficiles : parfois deux ou trois murs dont certains d'une trentaine de centimètres et 15 ou 20 mètres de distance. Il est aussi important de placer une bonne antenne sur le récepteur. Aucune difficulté pour le raccordement, la broche data est en 8. Vous pouvez ajouter une LED sur la broche 13. Vu qu'elle ne reste allumée quie quelques fractions de secondes, elle flashe, je n'ai pas mis de résistance en série. Sinon, placez-en une de 220 Ohms.

Le tableur

Puis, une fois que j'ai eu des suites de 0 et 1, j'ai utilisé un tableur pour m'aider à décoder la trame binaire. D'abord une seule sonde avec des relevés différents, et ensuite une deuxième et plus encore. Il faut faire des comparaison, noter où cela change, où c'est fixe. J'ai fait de très nombreux relevés, mais gardés ici que quelques uns pour l'exemple.
Il peut bien entendu être utilisé pour d'autres appareil et il est tout à fait compatible en MS-Excel et Open/Libre Office


Rien de tel qu'un bon dessin au lieu d'un long discours, voici quelques copies d'écran :

vue complète de l'analyse.png
Il suffit de copier/coller les trames à partir de la cellule A11, puis de les décomposer dans les colonnes C à au grand maximum P en indiquant le nombre de bits en ligne 8.
Par exemple, ici les 10 bits de l'entête sont indiqués en C7. J'utiliserai le 1er octet pour filtrer que ces sondes. Puis je décomposais de 4 en 4 (à cause du supposé BCD[5] ), Mais je me suis rendu compte avec l'humidité qu'il n'était pas utilisé, car elle était transmise en binaire pur sur 8 bits. D'autres exceptions en colonnes F et G où j'ai repéré l'état de la batterie (?) et les 3 bits du canal.

Décomposition de la trame, déc. 2019

Pourquoi faire simple ...

Cela s'est nettement corsé pour la température et là encore Internet m'a aidé. J'avais bien repéré 12 bits (!) pour la température mais pas moyen de comprendre comment c'était codé. J'ai écumé la toile assez profondément et je suis tombé sur une formule à tomber par terre : T = (X - 720) * 0.0556 chez « Andrew's WIP sketch for capturing data from Ambient F007th Thermo-Hygrometer »

Et du binaire en décimal ..., déc. 2019

C'est parti, le croquis !

1. L'Étalonnage !

Hé bien là, c'est pas compliqué. Vous mettez toutes vos sondes dans une boite pendant une paire d'heures, et vous faites le relevé des température et humidité, vous faites la moyenne et notez les différences.
Un petit fichier tableur pour vous aider.

// Étalonnage (mesures dans un endroit confiné et différence par rapport à la moyenne)
const float EtalonT[MxCnl] = { -0.3, -0.3, 0.2, 0.2, 0.1, 0, 0.3, -0.4};
const int EtalonH[MxCnl] = { -2, 0, 2, -2, -4, -2, 2, 3};

(MxCnl est le nombre de satellites que vous avez)

2. Manchester

Le code est donc articulé autour de l'excellent travail de Rob Ward. L'original est abondamment documenté, je vous le laisse découvrir. J'ai cependant effectué quelques changements :

  • En ligne 54, j'ai modifié word sDelay = 220; car cette valeur, donnée par le croquis Debug_Auto.ino, semble donner de bons résultats.
  • En ligne 67, byte maxBytes = 6; // Attention, 6 et pas 5, sinon, la trame ne sera pas complète.
  • la série est remplacée En ligne 72 par byte manchester20; En fait, je n'utilise que le 1er élément pour discerner nos satellites des autres appareils présents dans l'environnement ( ligne 174 if (manchester0 == 81) {// ce sont bien nos sondes (signature, identification dans le 1er octet du header

Du coup, des éléments de code ont été modifiés, comme ci-dessous

2.1. void hexBinDump()

La procédure a été modifiée pour stocker dans l'objet String Spaquet les '0' et '1' qui seront analysés (void analyseData()) une fois les 6 octets reçus.

2.2. void analyseData()

Comme déjà indiqué plus haut, on vérifie d'abord que ce sont les bons satellites. Vous comprenez ensuite pourquoi j'utilise l'objet String, car il me permet d'extraire facilement une sous-chaîne (binaire) remise en décimal avec une fonction maison Bin2Dec
Les réceptions consécutives (très rapprochées) sont comparées. Si elles sont pareilles, on corrige selon l'étalonnage, et on transmet.
Durant cette procédure, des Serial.print de contrôle sont envoyés au moniteur comme suit :

START Module 3 Prod v1 : TFA >=> I2C
Décodage : 3 10.40 65
Décodage : 3 10.40 65
3 10.60 63 transmis
Décodage : 2 17.70 53
Décodage : 2 17.70 53
2 17.90 55 transmis
Décodage : 7 17.90 53
Décodage : 7 17.90 53
7 17.50 56 transmis
Décodage : 6 10.20 65
Décodage : 6 10.20 65
6 10.50 67 transmis
Décodage : 4 16.80 64
Décodage : 1 187.50 69
Décodage : 1 19.30 46
Décodage : 2 17.70 53
Décodage : 2 17.70 53
2 17.90 55 transmis

Voici le croquis :

Bon amusement !

/***********************************************
  Auteur :      Pascal Cambier
  Nom :         TFA & Cie, Module 3 
  Version :     Prod v1 décembre 2019
  Description : - Réception satellites TFA Dostmann 30.3208.02 basé sur https://github.com/robwlakes/ArduinoWeatherOS
                - Réemmission en I2C après contrôle validité réception
                    (les satellites émettant deux fois de suite +/- toutes les minutes,
                     il suffit de vérifier si les 2 transmissions sont égales.)
  Références :  https://github.com/robwlakes/ArduinoWeatherOS
                https://github.com/madsci1016/Arduino-EasyTransfer/tree/master/EasyTransferI2C
*/

#include <Wire.h>
#include <EasyTransferI2C.h>
//create object
EasyTransferI2C ET;

// RTC
#include <DS1307RTC.h>
tmElements_t dt;

//==================================
const byte MxCnl = 8 ; // Nombre max de canaux / satellites
int iCanal ; //le canal du satellite
String Spaquet; //tous les bits dans une String
float fTemp; // Température
int iHum; // humidité
byte Nr = 0; // 0 = 1ère mesure


struct ST_TFA { // Réception / Émission même schéma chez l'esclave (module 4)
  int Canal ;
  float Temp;
  byte Hum;
};

ST_TFA mydata ; // pour émission i2c
ST_TFA Premier ;

// Étalonnage (mesures dans un endroit confiné et différence par rapport à la moyenne)
const float EtalonT[MxCnl] = { -0.3, -0.3, 0.2, 0.2, 0.1, 0, 0.3, -0.4};
const int EtalonH[MxCnl] = { -2, 0, 2, -2, -4, -2, 2, 3};


//############### MANCHESTER ################

//Interface Definitions
int RxPin           = 8;   //The number of signal from the Rx
int ledPin          = 13;  //The number of the onboard LED pin

// Variables for Manchester Receiver Logic:
//word    sDelay     = 250;  //Small Delay about 1/4 of bit duration  try like 250 to 500
//220 semble donner de meilleurs résultats
word    sDelay     = 220;
word    lDelay     = 500;
byte    polarity   = 1;
byte    tempBit    = 1;
byte    discards   = 0;
boolean firstZero  = false;
boolean noErrors   = true;

byte    headerBits = 10;
byte    headerHits = 0;

byte    dataByte   = 0;
byte    nosBits    = 0;
byte    maxBytes   = 6; // Attention, 6 et pas 5
byte    nosBytes   = 0;

byte    nosRepeats = 0;

byte  manchester[20];


void setup() {

  Serial.begin(115200);

  Wire.begin();
  //start the library, pass in the data details and the name of the serial port. Can be Serial, Serial1, Serial2, etc.
  ET.begin(details(mydata), &Wire);

  pinMode(RxPin, INPUT);
  pinMode(ledPin, OUTPUT);
  lDelay = 2 * sDelay;
  eraseManchester();



  Serial.println(F("START Module 3 Prod v1 : TFA >=> I2C"));

}


void loop() {
  // Routine épurée basé sur https://github.com/robwlakes/ArduinoWeatherOS
  tempBit = polarity ^ 1;
  noErrors = true;
  firstZero = false;
  headerHits = 0;
  nosBits = 0;
  nosBytes = 0;
  digitalWrite(ledPin, 0);
  tempBit = polarity ^ 1;
  noErrors = true;
  firstZero = false;
  headerHits = 0;
  nosBits = 0;
  nosBytes = 0;
  digitalWrite(ledPin, 0);
  while (noErrors && (nosBytes < maxBytes)) {
    while (digitalRead(RxPin) != tempBit) {
    }
    delayMicroseconds(sDelay);
    digitalWrite(ledPin, 0);
    if (digitalRead(RxPin) != tempBit) {
      noErrors = false;
    }
    else {
      byte bitState = tempBit ^ polarity;
      delayMicroseconds(lDelay);
      if (digitalRead(RxPin) == tempBit) {
        tempBit = tempBit ^ 1;
      }
      if (bitState == 1) {
        if (!firstZero) {
          headerHits++;
          if (headerHits == headerBits) {
            digitalWrite(ledPin, 1);
          }
        }
        else {
          add(bitState);
        }
      }
      else {
        if (headerHits < headerBits) {
          noErrors = false;
        }
        else {
          if ((!firstZero) && (headerHits >= headerBits)) {
            firstZero = true;
          }
          add(bitState);
        }
      }
    }
  }
  digitalWrite(ledPin, 0);
}

void hexBinDump() {
  for ( int i = 0; i < maxBytes; i++) {
    byte mask = B10000000;
    if (manchester[i] < 16) {
    }
    for (int k = 0; k < 8; k++) {
      if (manchester[i] & mask) {
        Spaquet += '1'; 
      }
      else {
        Spaquet += '0';
      }
      mask = mask >> 1;
    }
  }
}

void analyseData() {
  // Décodage propre aux satellites TFA Dostmann 30.3208.02
  char cTp[5];

  if (manchester[0] == 81) {// ce sont bien nos sondes (signature, identification dans le 1er octet du header
    //Serial.println(Spaquet);
    iCanal = Bin2Dec(Spaquet.substring(19, 22));
    fTemp = (Bin2Dec(Spaquet.substring(22, 34)) - 720) * 0.0556;
    fTemp *= 10;
    fTemp = int(fTemp + 0.5);
    fTemp /= 10;
    iHum = Bin2Dec(Spaquet.substring(34, 42));
    Serial.print("Décodage : ");
    Serial.print(iCanal);
    Serial.print(" " );
    Serial.print(fTemp);
    Serial.print(" " );
    Serial.println(iHum);
    Spaquet = "";
    //À ce stade, c'est décodé
    if (Nr == 0) { // 1ère réception, mise en mémoire
      Premier.Canal = iCanal;
      Premier.Temp = fTemp;
      Premier.Hum = iHum;

      Nr = 1;
    } else { // 2ème réception,
      if (iCanal == Premier.Canal ) { // Même satellite
        if (fTemp == Premier.Temp && iHum == Premier.Hum) {
          // Ok, Transmission
          mydata.Canal = iCanal ;
          // correction étalonnage
          mydata.Temp = fTemp + EtalonT[iCanal] ;
          mydata.Hum = iHum + EtalonH[iCanal];

          Serial.print(mydata.Canal);
          Serial.print(" " );
          Serial.print(mydata.Temp);
          Serial.print(" " );
          Serial.print(mydata.Hum);
          ET.sendData(4); // vers le module (esclave) 4
          Serial.println(" transmis");
          Nr = 0;
        } else {
          // pas identique, on reprend à zéro
          Nr = 0;

        }
      }// fin bon satellite
      else {
        // Pas le bon satellite
        Premier.Canal = iCanal ;
        Premier.Temp = fTemp ;
        Premier.Hum = iHum ;
      }
    }// fin 2nd réception

  }
}

void add(byte bitData) {
  if (discards > 0) { //if first one, it has not been found previously
    discards--;
  }
  else {
    dataByte = (dataByte << 1) | bitData;
    nosBits++;
    if (nosBits == 8) {
      nosBits = 0;
      manchester[nosBytes] = dataByte;
      nosBytes++;
    }
    if (nosBytes == maxBytes) {
      hexBinDump();
      analyseData();//later on develop your own analysis routines
    }
  }
}

void eraseManchester() {
  //Clear the memory to non matching numbers across the banks
  //If there is only one packet, with no repeats this is not necessary.

  for ( int i = 0; i < 20; i++) {
    manchester[i] = 0;
  }
}

int Bin2Dec(String Sbin) {
  int iDec = 0;
  int iBit = 0;
  int iRang = 0;
  for (int i = Sbin.length(); i >= 1; i--) {
    iBit = Sbin.substring(i - 1, i).toInt();
    iDec += (iBit * int(pow(2, iRang) + .5));
    iRang++;
  }
  return iDec;
}

Notes

[1] https://www.amazon.fr/gp/product/B00SIZZBDK

[2] https://www.amazon.fr/Transmetteur-temp%C3%A9rature-dhumidit%C3%A9-3054-3208/dp/B011IMRIZS

[3] https://fr.wikipedia.org/wiki/Codage_Manchester

[4] en anglais : https://github.com/robwlakes/ArduinoWeatherOS

[5] Le binary coded decimal, est un système de numération utilisé en électronique (...) pour coder des nombres dont les chiffres sont codés sur quatre bits :

Commentaires

1. Le mercredi 10 mars 2021, 18:17 par Instagram services

It is perfect time to make some plans for the future and it's
time to be happy. I have read this post and if I could I want to
suggest you few interesting things or advice. Perhaps you could write next articles referring
to this article. I desire to read even more things about
it!

2. Le lundi 29 mars 2021, 00:45 par satellite

I just could not leave your wеb site pгior to sugցesting that I extremely enjoyed tһe usual info an іndividual provide to your
ɡuestѕ? Is going to be again regularly in orԀer
to inspect new posts

3. Le jeudi 15 avril 2021, 22:15 par lpe88 android

You ought to be a part of a contest for one of the most useful blogs on the web.
I am going to recommend this web site!

4. Le vendredi 16 juillet 2021, 12:10 par ทดเล่นเล่นสล็อต

Hello mates, its enormous article regarding cultureand
completely defined, keep it up all the time.

5. Le samedi 31 juillet 2021, 12:14 par Pascal

Merci Ipe88 android.

Prenez soin de vous !

6. Le vendredi 8 octobre 2021, 03:35 par obeys

Riցht here is the perfect wеbsitе for anybody who really wants to find out about this topic.
You know so much its almost toսgh to argue ᴡith you (not that I personaⅼly will need to…HaHa).

You definitely put a new spin on a subject that has been discussed for ages.
Great stuff, just excellent!

7. Le dimanche 7 novembre 2021, 08:24 par polemic

My brother recommended I would poѕsibly like this website.
He used to be totally right. This put սp truly made my
day. You cann't imagine simpⅼy how much time Ι һad ѕpent for this information!
Thаnks!

8. Le mercredi 10 novembre 2021, 18:19 par Gervin

This is really great! Your code works out of the box without any problems, everything is well explained and documented. The design of your website looks very professional: nice layout, beautiful colors (green is my favorite color) and clear structure. Congratulations and thank you very much!

9. Le jeudi 25 novembre 2021, 15:23 par black

Wow that was unusual. I just wrote an really long comment
but after I clicked submit my comment didn't appear.
Grrrr... well I'm not writing all that over again.
Regardless, just wanted to say excellent blog!

10. Le mercredi 8 décembre 2021, 20:45 par Google Seo

Howdy! This post couldn't be written any better!
Reading this post reminds me of my previous room mate!

He always kept chatting about this. I will forward this post to him.
Fairly certain he will have a good read. Thanks for sharing!

11. Le vendredi 10 décembre 2021, 00:28 par double mattress size uk

You are so interesting! I don't think I've read a single thing
like that before. So nice to discover someone with some unique
thoughts on this topic. Really.. many thanks for starting this up.
This site is one thing that is required on the internet, someone with a little originality!

12. Le samedi 11 décembre 2021, 17:13 par Seo Uk

It's a shame you don't have a donate button! I'd most certainly
donate to this brilliant blog! I guess for now i'll settle
for bookmarking and adding your RSS feed to my Google account.

I look forward to fresh updates and will talk about this website with my Facebook
group. Talk soon!

13. Le jeudi 27 janvier 2022, 11:11 par news

Hello There. I found your weblog using msn. This is a very neatly written article.
I will make sure to bookmark it and come back to learn extra of your
useful info. Thanks for the post. I'll definitely return.

14. Le mercredi 2 mars 2022, 20:31 par funny st

Greetings! Very useful advice in this particular post!

It is the little changes which will make the largest
changes. Thanks a lot for sharing!

Ajouter un commentaire

Le code HTML est affiché comme du texte et les adresses web sont automatiquement transformées.

La discussion continue ailleurs

URL de rétrolien : http://cambier.eu/ubicomp/index.php?trackback/5

Fil des commentaires de ce billet