Protocoles Oregon Scientific et Arduino : Encodage

Maintenant que l’on décode les protocoles Oregon Scientific (le v2 du moins car n’ayant pas de sonde en v3, je n’ai pas pu tester mais certains commentaires laissent à penser que ça fonctionne :) ), on va s’attaquer à l’émission de trames Oregon Scientific v2 depuis un arduino. Je pense que ça va en intéresser plus d’un et vous aurez compris l’idée derrière cela … réaliser des sondes pas chères et surtout compatibles avec les équipements du marché tel que le RFXCom ou la Zibase.
MAJ 10/02/2013 : suite à un problème avec l’éditeur de wordpress, le code était foireux à la ligne 264, c’est corrigé. Merci à catalin.

Note: Je parle de protocole version 2, il s’agit du 2.1 à réalité.

Le protocole Oregon Scientific v2

Codage

Je suis parti des specs que l’on trouve ici: http://wmrx00.sourceforge.net/Arduino/OregonScientific-RF-Protocols.pdf.

Note : Il y a des différences entre la spec et ce que fait le décodeur des articles précédant, notamment au niveau des ID des sondes.
En effet, si on prend l’exemple d’une sonde THN132N, la spec indique qu’elle renvoie 0xEC40 comme ID, alors que nous on attend 0xEA4C. le « A » de 0xEA4C semble venir en fait de 4bits de syncho envoyés par toutes les sondes. Du coup, même si le décodeur fonctionne, je pense qu’il ne doit pas reconnaitre toutes les sondes correctement (à tester, maintenant que l’on peut simuler n’importe qu’elle sonde).

Les protocoles 2 et 3 transmettent à un débit d’environ 1024Hz et utilisent un codage manchester. Un bit 0 est représenté par une transition du niveau bas vers le niveau haut et un bit 1 par une transition du niveau haut vers le niveau bas. La transition se produit au milieu d’une pulsation.

Particularités du protocole Oregon Scientific 2

La version 2 du protocole Oregon Scientific présente quelques particularités. Chaque bit est envoyé 4 fois. D’abords, les bits sont doublés. Pour un bit 1, on envoie « 01 » et pour un bit 0, « 10 ». Puis le message complet est envoyé 2 fois.

Structure d’une trame Oregon Scientific

Les protocoles v2 et v3 ont une structure similaire :

[ Préambule (16/24) ] [ Sync (4) ] [ Data (taille variable) ] [ Postambule (taille variable) ]

  1. Un préambule qui permet de reconnaitre une trame Oregon. Elle consiste en une série de 24bits « 1 » pour la version 3 et 16bits « 1 » pour la version 2. N’oubliez pas que dans la version 2, chaque bit est doublé par son inverse. On se retrouve donc pour la v2 avec 32bits « 01010101… » .
  2. 4 bits de synchronisation : 0101, le fameux « A » (voir note plus haut). Les bits sont envoyés bit de poids faible en premier (A = 1010 -> tramis à l’envers : 0101). Pour la v2 : 10011001, Vous suivez toujours ?
  3. Les datas (voir plus bas)
  4. un postambule variable.

Analyse de la trame à « l’oscilloscope »

Forcement, ça n’a pas fonctionné du premier coup et pour vérifier ce que mon émetteur envoyait et le comparer avec une vrai sonde un oscilloscope aurait été bien pratique. Il y a plusieurs méthodes pour se dépatouiller sans oscillo.

On peut brancher un récepteur RF433 sur l’entrée ligne d’une carte son et utiliser un soft comme audacity pour afficher le signal comme le « ferait » un oscillo. Malheureusement je n’ai pas d’entrée ligne sur mon portable.

J’ai trouvé une autre méthode à base d’arduino : xoscillo. C’est un oscilloscope logiciel. Le signal reçu par un Arduino équipé d’un récepteur RF est envoyé via l’USB sur le PC qui fait tourner le soft xoscillo et qui affiche une représentation graphique du signal. Ca ne remplace pas un vrai oscillo bien sûr mais dans notre cas c’est suffisant et en tout cas, ça m’a bien dépanné :)

Sur l’image, une trame Oregon complète (le deuxième envoi) en haut. En bas, On voit clairement les 16 bits du préambule par exemple et les 4bits de synchro.

Trame oregon à l'oscilloscope

Simulation d’une sonde Oregon Scientific V2 avec un Arduino

Le sketch ci dessous permet de simuler une sonde de température Oregon Scientific THN132N ou une sonde de température/humidité THGR2228N.

Le code envoie la même trame toutes les 30 secondes. Libre à vous ensuite d’ajouter un capteur de température et/ou d’humidité pour envoyer de vrais informations.

Je me suis inspiré du code de skyduino pour l’envoi de trame blyss. Je l’ai testé sur Arduino Duemilanove et l’IDE 1.0.1 (linux).

/*
 * connectingStuff, Oregon Scientific v2.1 Emitter
 * http://www.connectingstuff.net/blog/encodage-protocoles-oregon-scientific-sur-arduino/
 *
 * Copyright (C) 2013 olivier.lebrun@gmail.com
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#define THN132N

const byte TX_PIN = 4;

const unsigned long TIME = 512;
const unsigned long TWOTIME = TIME*2;

#define SEND_HIGH() digitalWrite(TX_PIN, HIGH)
#define SEND_LOW() digitalWrite(TX_PIN, LOW)

// Buffer for Oregon message
#ifdef THN132N
  byte OregonMessageBuffer[8];
#else
  byte OregonMessageBuffer[9];
#endif

/**
 * \brief    Send logical "0" over RF
 * \details  azero bit be represented by an off-to-on transition
 * \         of the RF signal at the middle of a clock period.
 * \         Remenber, the Oregon v2.1 protocol add an inverted bit first 
 */
inline void sendZero(void) 
{
  SEND_HIGH();
  delayMicroseconds(TIME);
  SEND_LOW();
  delayMicroseconds(TWOTIME);
  SEND_HIGH();
  delayMicroseconds(TIME);
}

/**
 * \brief    Send logical "1" over RF
 * \details  a one bit be represented by an on-to-off transition
 * \         of the RF signal at the middle of a clock period.
 * \         Remenber, the Oregon v2.1 protocol add an inverted bit first 
 */
inline void sendOne(void) 
{
   SEND_LOW();
   delayMicroseconds(TIME);
   SEND_HIGH();
   delayMicroseconds(TWOTIME);
   SEND_LOW();
   delayMicroseconds(TIME);
}

/**
* Send a bits quarter (4 bits = MSB from 8 bits value) over RF
*
* @param data Source data to process and sent
*/

/**
 * \brief    Send a bits quarter (4 bits = MSB from 8 bits value) over RF
 * \param    data   Data to send
 */
inline void sendQuarterMSB(const byte data) 
{
  (bitRead(data, 4)) ? sendOne() : sendZero();
  (bitRead(data, 5)) ? sendOne() : sendZero();
  (bitRead(data, 6)) ? sendOne() : sendZero();
  (bitRead(data, 7)) ? sendOne() : sendZero();
}

/**
 * \brief    Send a bits quarter (4 bits = LSB from 8 bits value) over RF
 * \param    data   Data to send
 */
inline void sendQuarterLSB(const byte data) 
{
  (bitRead(data, 0)) ? sendOne() : sendZero();
  (bitRead(data, 1)) ? sendOne() : sendZero();
  (bitRead(data, 2)) ? sendOne() : sendZero();
  (bitRead(data, 3)) ? sendOne() : sendZero();
}

/******************************************************************/
/******************************************************************/
/******************************************************************/

/**
 * \brief    Send a buffer over RF
 * \param    data   Data to send
 * \param    size   size of data to send
 */
void sendData(byte *data, byte size)
{
  for(byte i = 0; i < size; ++i)
  {
    sendQuarterLSB(data[i]);
    sendQuarterMSB(data[i]);
  }
}

/**
 * \brief    Send an Oregon message
 * \param    data   The Oregon message
 */
void sendOregon(byte *data, byte size)
{
    sendPreamble();
    //sendSync();
    sendData(data, size);
    sendPostamble();
}

/**
 * \brief    Send preamble
 * \details  The preamble consists of 16 "1" bits
 */
inline void sendPreamble(void)
{
  byte PREAMBLE[]={0xFF,0xFF};
  sendData(PREAMBLE, 2);
}

/**
 * \brief    Send postamble
 * \details  The postamble consists of 8 "0" bits
 */
inline void sendPostamble(void)
{
#ifdef THN132N
  sendQuarterLSB(0x00);
#else
  byte POSTAMBLE[]={0x00};
  sendData(POSTAMBLE, 1);  
#endif
}

/**
 * \brief    Send sync nibble
 * \details  The sync is 0xA. It is not use in this version since the sync nibble
 * \         is include in the Oregon message to send.
 */
inline void sendSync(void)
{
  sendQuarterLSB(0xA);
}

/******************************************************************/
/******************************************************************/
/******************************************************************/

/**
 * \brief    Set the sensor type
 * \param    data       Oregon message
 * \param    type       Sensor type
 */
inline void setType(byte *data, byte* type) 
{
  data[0] = type[0];
  data[1] = type[1];
}

/**
 * \brief    Set the sensor channel
 * \param    data       Oregon message
 * \param    channel    Sensor channel (0x10, 0x20, 0x30)
 */
inline void setChannel(byte *data, byte channel) 
{
    data[2] = channel;
}

/**
 * \brief    Set the sensor ID
 * \param    data       Oregon message
 * \param    ID         Sensor unique ID
 */
inline void setId(byte *data, byte ID) 
{
  data[3] = ID;
}

/**
 * \brief    Set the sensor battery level
 * \param    data       Oregon message
 * \param    level      Battery level (0 = low, 1 = high)
 */
void setBatteryLevel(byte *data, byte level)
{
  if(!level) data[4] = 0x0C;
  else data[4] = 0x00;
}

/**
 * \brief    Set the sensor temperature
 * \param    data       Oregon message
 * \param    temp       the temperature
 */
void setTemperature(byte *data, float temp) 
{
  // Set temperature sign
  if(temp < 0)
  {
    data[6] = 0x08;
    temp *= -1;  
  }
  else
  {
    data[6] = 0x00;
  }

  // Determine decimal and float part
  int tempInt = (int)temp;
  int td = (int)(tempInt / 10);
  int tf = (int)round((float)((float)tempInt/10 - (float)td) * 10);

  int tempFloat =  (int)round((float)(temp - (float)tempInt) * 10);

  // Set temperature decimal part
  data[5] = (td << 4);
  data[5] |= tf;

  // Set temperature float part
  data[4] |= (tempFloat << 4);
}

/**
 * \brief    Set the sensor humidity
 * \param    data       Oregon message
 * \param    hum        the humidity
 */
void setHumidity(byte* data, byte hum)
{
    data[7] = (hum/10);
    data[6] |= (hum - data[7]*10) << 4;
}

/**
 * \brief    Sum data for checksum
 * \param    count      number of bit to sum
 * \param    data       Oregon message
 */
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;
}

/**
 * \brief    Calculate checksum
 * \param    data       Oregon message
 */
void calculateAndSetChecksum(byte* data)
{
#ifdef THN132N
    int s = ((Sum(6, data) + (data[6]&0xF) - 0xa) & 0xff);

    data[6] |=  (s&0x0F) << 4;     data[7] =  (s&0xF0) >> 4;
#else
    data[8] = ((Sum(8, data) - 0xa) & 0xFF);
#endif
}

/******************************************************************/
/******************************************************************/
/******************************************************************/

void setup()
{
  pinMode(TX_PIN, OUTPUT);

  Serial.begin(9600);
  Serial.println("\n[Oregon V2.1 encoder]");

  SEND_LOW();  

#ifdef THN132N  
  // Create the Oregon message for a temperature only sensor (TNHN132N)
  byte ID[] = {0xEA,0x4C};
#else
  // Create the Oregon message for a temperature/humidity sensor (THGR2228N)
  byte ID[] = {0x1A,0x2D};
#endif  

  setType(OregonMessageBuffer, ID);
  setChannel(OregonMessageBuffer, 0x20);
  setId(OregonMessageBuffer, 0xBB);
}

void loop()
{
  // Get Temperature, humidity and battery level from sensors
  // (ie: 1wire DS18B20 for température, ...)
  setBatteryLevel(OregonMessageBuffer, 0); // 0 : low, 1 : high
  setTemperature(OregonMessageBuffer, 11.2);

#ifndef THN132N
  // Set Humidity
  setHumidity(OregonMessageBuffer, 52);
#endif  

  // Calculate the checksum
  calculateAndSetChecksum(OregonMessageBuffer);

  // Show the Oregon Message
  for (byte i = 0; i < sizeof(OregonMessageBuffer); ++i)   {     Serial.print(OregonMessageBuffer[i] >> 4, HEX);
    Serial.print(OregonMessageBuffer[i] & 0x0F, HEX);
  }

  // Send the Message over RF
  sendOregon(OregonMessageBuffer, sizeof(OregonMessageBuffer));
  // Send a "pause"
  SEND_LOW();
  delayMicroseconds(TWOTIME*8);
  // Send a copie of the first message. The v2.1 protocol send the
  // message two time 
  sendOregon(OregonMessageBuffer, sizeof(OregonMessageBuffer));

  // Wait for 30 seconds before send a new message 
  SEND_LOW();
  delay(30000);
}

Compatibilité et conclusion

J’ai testé avec succès la réception avec le décodeur des articles précédant et avec un ancien RFXCom USB (2010). J’attends vos retours pour savoir si ça passe bien sur les nouveaux RFXcom ou sur une Zibase, voir sur une station Oregon Scientific directement.

J’avais commencé une librairie Oregon pour Arduino que je vais du coup essayer de terminer et de publier.

 

Partagez moi ...Tweet about this on Twitter0Share on Facebook0Share on Google+0Digg thisEmail this to someone

You may also like...

110 Responses

  1. Franck dit :

    Bonsoir,
    Je viens du forum touteladomotique.com qui m’a conseillé votre site.
    J’ai des sondes Oregon, un Arduino Uno.

    Pensez vous qu’il soit possible de lire les températures des sondes avec l’Arduino et ensuite de récupérer les données sous forme de courbe depuis un navigateur web (Pc, Mac, tablette, iPhone)?

    En vous remerciant pour le temps que vous prendrez à me répondre :)

    • Olivier dit :

      Salut,
      C’est moi qui t’es laissé le message sur le forum ;)
      Oui tout a fait c’est le but de cette série d’article. Si tu regarde ici : décodage oregon sur arduino 3/3 tu auras déjà le code pour réceptionner et décoder les infos des sondes 2.1 (quel modèle de sonde possèdes tu ?). Il faudra ensuite coder le transfert des données vers ton serveur. Il existe plein de moyen pour le faire (ethernet, usb, serie, rf …) et plein de façons différentes de le faire (http, xpl, …)

      Si tu es patient, je ferai un article avec cette partie là.

      • franck dit :

        Je saurait faire preuve de patience dans ce cas ;)

        Mes sondes sont des THGR122N et la dernière est une THGR122NX, je sais pas où ce trouve la différence?

        Par contre je ne sais pas si ce sont des V2 ou V3?

        Pour commencer avec les trois premier articles, il me manque donc un récepteur 433Mhz, j’en est trouvé mais pas à deux euros ;)

        Lequel prendre?

        http://www.planete-domotique.com/module-slave-recepteur-rf-433-92mhz-antenne-rfxcom.html

        http://www.lextronic.fr/P865-recepteur-43392-mhz-rrq3-433.html

        Tu as dit:
        « Il faudra ensuite coder le transfert des données vers ton serveur. Il existe plein de moyen pour le faire (ethernet, usb, serie, rf …) et plein de façons différentes de le faire (http, xpl, …) »

        L’Arduino ne peu pas faire office de serveur?
        Je pensais qu’il suffisait de lui adjoindre un shield Ethernet pour qu’il soit accessible via un navigateur internet.

        Mon serveur actuel, qui me sert pour les sauvegardes, bibliothéques iTunes est un Mac mini server avec OSX 10.6.

        Je ne sais pas si il peu être utilisé pour faire sa?

        • Olivier dit :

          Salut Frank,

          Je t’ai déjà répondu sur le forum de touteladomotique mais je partage les réponse ici aussi du coup.

          Je dirai que tu devrais pouvoir utiliser le code que j’ai fournis dans les articles précédant puisqu’elles partagent le même codage que les THGR228N pour lesquels j’ai fournis les fonctions nécessaires.

          J’ai acheté le mien ici (ce n’est pas le même que sur la photo par contre) : http://www.watterott.com/en/RF-Link-2400bps-Receiver-434MHz il me semblait l’avoir payé moins cher à l’époque.

          Si l’arduino peut faire office de serveur. On pourrait stocker les données sur la carte SD par exemple mais pour générer des graphs ça risque d’être limité. Je préfère utiliser l’arduino juste comme « passerelle », il s’occupe de la réception/décodage et renvoi les données décodées au serveur, chacun son boulot :)
          Oui tu peux utiliser ton MAc mini, pas de soucis.

  2. Franck dit :

    Je suppose qu’il faudra un module Rfx com pour lire les sondes Oregon?

    • Olivier dit :

      Tu peux le faire avec le rfxcom mais aussi avec un arduino + un module récepteur RF433 à 2€. Cf le commentaire au dessus: jette un oeil sur les trois articles précédant à propos du décodage du protocole oregon.

  3. catalin dit :

    Hi,

    there is a problem in your code and iit will not compile, the problem relates to the sum byte part there is something missing in the code and it will not compile on line 264..

    Thank you

  4. catalin dit :

    Please rectify the code on the page, I have found the problem.
    this is the correct code:
    int Sum(byte count, const byte* data)
    {
    int s = 0;

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

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

    return s;
    }

  5. franck dit :

    Je viens de trouver sa:

    http://www.mon-club-elec.fr/pmwiki_reference_arduino/pmwiki.php?n=Main.DebuterModuleArduinoEthernet

    Dans le cas où mon Mac Mini Server ne pourrais pas être utilisé, mais j’attend ta réponse à mon précédent post ;)

  6. catalin dit :

    Thank you for all your work, I have managed to use your code together with an 433.92 rf transmitter and an ShT22 sensor and i have a fully working replica of an Oregon Scientific sensor now, I am using it in Homeseer with RFXCom.
    I plan to have it ported outside arduino on a separate AVR platform with atmega 8 and make my own compatible temperature sensors.

    • Olivier dit :

      Great :) I’m glad it’s working for you !
      I plan to use a ATtiny or something like that too to reduce cost. I’ll write a post when it’s ok.

      Share with us if you do it ! :)

  7. catalin dit :

    sure it will be shared :)

  8. Robert dit :

    Bonjour,

    J’ai une série de thermomètres THR128 Oregon.

    Aucuns des décodeurs que j’ai pu tester ne fonctionne. Il semble qu’ils utilisent le protocole V1.

    Je n’ai pas trouvé de sketch Arduino pour cette version. Il y a-t-il une quelqu’un qui a réalisé un décodeur pour la version 1.

    Merci d’avance
    Robert

  9. Leon dit :

    Bonjour,

    Try to play with your sketch (including bufix line 264) to emulate sensor.
    I have at serial output 1A2D20BB0C500006F6, and nothing on Oregon screen.
    Could you please specify where is problem?
    Many thanks in advance for reply.

    Data from my real Oregon sensor
    OSV2 1A2D408E700870834B41

  10. engel dit :

    Bonjour, et merci pour cet excellent article, néanmoins je m’interroge… dans le document que vous citez en référence : http://wmrx00.sourceforge.net/Arduino/OregonScientific-RF-Protocols.pdf , les ID’s sont différents des votres, est-ce lié à un encodage particulier de vos données ?

  11. catalin dit :

    Hi,
    the code works fine with rfxcom but it is not recognised by any Oregon Scientific stations, i have tested it with BAR800U and BAR206.
    I believe there is an issue with the checksum or postamble, hard to say..

    • Olivier dit :

      Hi,
      Are they oregonv2.1 sensors ?
      If yes, you can have a look to xpl-perl source code (old version) to see if the checksum code is correct.
      I’ll check when I have some time.

  12. engel dit :

    bonjour,

    j’ai fait quelques essais avec ma station wmr86 et des capteurs en version 3. Il semble que le postamble soit en fait le crc 8 des données placées avant le cheksum, je n’ai pas de transmetteur RF 433 pour tester mais en ajoutant le crc, je pense que l’on devrait pouvoir afficher les données sur la station.

    Un petit sketch pour vérifier, ( les paquets RF sont ceux enregistrés depuis mes capteurs ).


    #include

    #define mByte(i) (RFPacket[i])
    #define NIBBLE(i) ((mByte((i)>>1) >> (((i)&1)<<2))&0xf)

    // WGR800
    // 1A8904BBA0C004000046E2 Anemo = Sync + longueur utile (17) + CheckSum + CRC = 22 nibbles
    //uint8_t RFPacket[]={0x1A, 0x89, 0x04, 0xBB, 0xA0, 0xC0, 0x04, 0x00, 0x00, 0x46, 0xE2};

    // PCR800
    //2A19047D0000204500F05208 Pluvio Sync + longueur utile (18) + CheckSum + CRC = 23 nibbles
    //uint8_t RFPacket[]={0x2A, 0x19, 0x04, 0x7D, 0x00, 0x00, 0x20, 0x45, 0x00, 0xF0, 0x52, 0x08};

    // THGN800
    //AF8241750570028CC4054 thermo Hygro = Sync + longueur utile (15) + CheckSum + CRC = 20 nibbles
    uint8_t RFPacket[]={0xFA, 0x28, 0x14, 0x57, 0x50, 0x07, 0x20, 0xC8, 0x4C, 0x50};

    void checkSumAndCRC(const uint8_t len)
    {
    uint8_t i,j,c,CRC,SUM;

    CRC =0x00;
    SUM =0x00;

    uint8_t CCIT_POLY = 0x07;

    for (j=1; j<=len; j++)
    {
    c = NIBBLE(j);
    Serial.print(c, HEX);Serial.print(" ");
    SUM += c;
    CRC ^= c;
    for(i = 0; i<4; i++)
    if(CRC & 0x80 )
    CRC = (CRC << 1) ^ CCIT_POLY;
    else
    CRC <<= 1;
    CRC &= 0xff;
    }
    for(i = 0; i<4; i++)
    if(CRC & 0x80 )
    CRC = (CRC << 1) ^ CCIT_POLY;
    else
    CRC <<= 1;
    Serial.print("SUM: ");Serial.print(SUM, HEX); Serial.print(" CRC:"); Serial.print(CRC, HEX);Serial.println("");
    }

    void setup()
    {
    Serial.begin(38400,4);
    Serial.print("Start\n");
    }

    void loop()
    {
    checkSumAndCRC(15);
    delay(10000);
    }

    • gribouille dit :

      bonjour engel,

      j’essaye de comprendre votre code de calcul du post-ambul
      mais je bloque sur la compréhension

      ne manque t il pas de { } pour les boucles for(i = 0; i<4; i++)?
      car sans eux, le for ne sert a rien?

      pour le SUM , pas de probleme, j'ai bien compris et il est bien corroboré par mes trames brutes issus de capteur V2 (non via un recepteur UHF)

      ex : A1D3015717220418 73 8B
      le SUM vaut bien 37
      mais j'arrive pas a calculé le B8

      merci de votre aide

      • engel dit :

        Les accolades ne sont pas nécessaires, le for est exécuté sur l’instruction if suivante,( l’indentation n’a pas été préservée ). enfin bon je reconnais que l’on peut les mettre, ca ne gâche rien :)

        je n’ai pas de capteurs V2. mais un truc intéressant à faire à mon avis c’est de calculer le CRC en excluant le rolling Code du capteur 0x57 dans votre cas.

        • gribouille dit :

          bon j’ai testé en enlevant le 57 , mais c’est pas ça :D
          ou alors c’est mon code qui ne colle pas au votre

          voila ce que j’ai ecrit sous visualbasic en m’inspirant du votre
          ai je bon ?

          plainText recupere chaque nibble de la trame
          dans la trame du dessus
          plainText[0] = 1
          plainText[1] = D
          plainText[2] = 3
          etc…

          ********************************************************
          Dim i, j, c, CRC, SUM As UInteger

          CRC = &H0
          SUM = &H0

          Dim CCIT_POLY As UInteger = &H7

          For j = 0 To (Input1.TextLength – 1)
          c = plainText(j)
          SUM = SUM + c
          CRC = CRC Xor c

          For i = 0 To 3
          If CRC And &H80 Then
          CRC = (CRC << 1) Xor CCIT_POLY
          Else
          CRC = CRC << 1
          End If
          Next i
          CRC = CRC And &HFF
          Next j

          For i = 0 To 3
          If CRC And &H80 Then
          CRC = (CRC << 1) Xor CCIT_POLY
          Else
          CRC = CRC << 1
          End If
          Next i
          ********************************************************

    • gribouille dit :

      bonjour engel,

      j’essaye de comprendre votre code de calcul du CRC8
      ni connaissant rien en arduino, j’essaye de faire la translation du code en C pour tenter de le comprendre

      dans votre code , ne manque t il pas de { } pour la boucle for(i = 0; i<4; i++)?
      car sans eux , la boucle for tourne sur elle meme?

      merci de votre aide pour avoir quelques explications sur le calcul du CRC

      merci

    • pascal dit :

      Bonjour engel
      Avez vous pu confirmer qu’il s’agit bien d’un CRC 8 ? Si oui avec quel polynome ?
      J’ai testé avec 0x07 comme indiqué dans votre code mais ca ne fonctionne pas. Je vais en tester d’autres mais si je peux éviter de partir sur une mauvaise piste c’est aussi bien…
      Si vous avez d’autres informations qui expliquent ce préambule vous me seriez d’une grande aide.
      Si je trouve quelque chose de mon coté je publierai le résultat.
      Merci d’avance

  13. catalin dit :

    Hi engel, I am willing to send you a free RF 433 transmitter to test your code, if you continue to share the code, get in touch with me and send me your details.

  14. Florent dit :

    Bonjour Olivier et quel super travail réalisé.
    J’arrive à capter toutes les infos de mes sondes (THN132N & THGR228N) :-)

    Par contre ma THN132N étant en train de lacher, je souhaite la remplacer par un montage à base d’Arduino + sonde DS18B20.

    En récupérant ce code, je capte bien les messages sur un Arduino + récepteur RF mais ma station Oregon ne capte pas le message.

    Quelqu’un a-t’il déjà réussi à émuler une sonde et faire afficher la température sur une station Oregon?

    Par avance, merci de vos réponses

    • gribouille dit :

      j’ai testé , mais helas sans le post-ambule
      impossible qu’une station oregon reconnaisse la trame :-(

      faut reussir à trouver le calcul du post-ambul sur un capteur V2

      • Olivier dit :

        Salut,

        Je n’ai pas de station oregon, le rfxcom doit être est plus permissif (?)
        J’essaierai de regarder de ce coté à l’occasion mais pour le moment le tps me manque un peut :/

        • gribouille dit :

          disons que le rfxcom se moque complétement du post-ambule vu qu’il a deja toutes les infos dont il a besoin avant (meme si elles peuvent etre erroné suite à un parasite, quoique y’a un minimum avec le CRC ^_^ )

    • deennoo dit :

      Bonjour,

      oui j’ai reussi a simuler une sonde THGN801 pour qu elle s affiche sur ma station wmr86.

      C’est une sonde qui utilise le protocole version 3

      J’utilise ce script que j ai trouver sur le net :

      https://github.com/barnybug/arduino-sous-vide

      il fonctionne en ce moment et me permet d’afficher la temperature de ma piscine du la canal 2 (il faut changer le channel a la ligne : 51 du fichier sous vide.ino.

      • Olivier dit :

        Bonsoir,
        Merci pour ce retour sur le protocole v3, c’est intéressant.
        Je suis justement en train de faire une sonde avec le code que j’avais publié ici (v2 donc), je vais regarder ça de plus près.

  15. Julien dit :

    Salut,

    Merci beaucoup pour ce code ! C’est cool ! Je n’ai pas pour habitude de laisser des messages sur internet, mais je voulais faire partager mes expériences. Tout cela me paraissait assez compliqué, si bien que je doutais de l’efficacité de toutes ces lignes…
    Je viens tout juste de programmer un Atmega328 muni d’une sonde temp/hygro DHT22 et d’un émetteur 433MHz (les moins chers sur eBay). J’avais déjà essayé ces deux petits objets pour d’autres projets et ça marchait très bien. Pour le DHT22, j’utilise la librairie du même nom.
    Ce qui m’intéressait, c’était que la zibase capte toute seule les ondes et que je n’aie pas à passer par le port série branché sur un Raspberry (je lance un script PHP à l’aide de php_serial.class pour récupérer ce que le récepteur 433 a lui-même récupéré sur le Uno). D’une part, c’est plus pratique (et ça soulage la Zibase et le Raspberry), et d’autre part, je vais enfin pouvoir utiliser de manière optimale la librairie LowPower pour mettre en powerDown en boucle et ne réveiller la bête que toutes les tant de minutes… Cela m’économisera les piles. A vrai dire, c’est surtout pour le montage d’une sonde à ultrasons HC-SR04 que j’ai placée dans ma cuve de récupération d’eau de pluie, qui est au fond du jardin, que tout ceci m’intéressait… Mais je vais en profiter pour me faire une autre sonde temp/hygro sans fil, une « Oregon fake » !
    Merci encore !
    (Donc ça marche super bien avec la Zibase ! Voici ce qu’elle m’envoie : Received radio ID (433Mhz Noise=2004 Level=5.0/5 Oregon Generic Temp-Hygro/THGR228N Ch=2 T=+27.5°C (+81.5°F) Humidity=49% Batt=Ok): OS439204610
    Autant dire que c’est parfait : avec un petit fil de 17,3cm, je capte à 100% alors que je suis à l’étage…)
    NB : pour le code, j’ai remplacé #ifndef THN132N par #ifdef THGR2228N

    • Olivier dit :

      Salut,
      Merci pour le retour, ça fait plaisir :)

    • Leon dit :

      Salut,

      Can you share your code here? Merci.

      • Julien dit :

        Le code pour la sonde Temp/hygro : (pour le byte ID 0x1A,0x2D, on peut le remplacer par 0xCA,0x2C (THGR328N), il y aura peut-être moins de risques sur la limitation des canaux s’il y a plusieurs sondes) (j’ai aussi celui de l’ultrason pour ceux qui veulent)

        #include "LowPower.h" // Appel pour la maise en veille

        #include

        // Data wire is plugged into port 7 on the Arduino
        // Connect a 4.7K resistor between VCC and the data pin (strong pullup)
        #define DHT22_PIN 2

        // Setup a DHT22 instance
        DHT22 myDHT22(DHT22_PIN);

        #define THGR228N

        const byte TX_PIN = 12;

        const unsigned long TIME = 512;
        const unsigned long TWOTIME = TIME*2;

        #define SEND_HIGH() digitalWrite(TX_PIN, HIGH)
        #define SEND_LOW() digitalWrite(TX_PIN, LOW)

        // Buffer for Oregon message
        #ifdef THN132N
        byte OregonMessageBuffer[8];
        #else
        byte OregonMessageBuffer[9];
        #endif

        /**
        * \brief Send logical "0" over RF
        * \details azero bit be represented by an off-to-on transition
        * \ of the RF signal at the middle of a clock period.
        * \ Remenber, the Oregon v2.1 protocol add an inverted bit first
        */
        inline void sendZero(void)
        {
        SEND_HIGH();
        delayMicroseconds(TIME);
        SEND_LOW();
        delayMicroseconds(TWOTIME);
        SEND_HIGH();
        delayMicroseconds(TIME);
        }

        /**
        * \brief Send logical "1" over RF
        * \details a one bit be represented by an on-to-off transition
        * \ of the RF signal at the middle of a clock period.
        * \ Remenber, the Oregon v2.1 protocol add an inverted bit first
        */
        inline void sendOne(void)
        {
        SEND_LOW();
        delayMicroseconds(TIME);
        SEND_HIGH();
        delayMicroseconds(TWOTIME);
        SEND_LOW();
        delayMicroseconds(TIME);
        }

        /**
        * Send a bits quarter (4 bits = MSB from 8 bits value) over RF
        *
        * @param data Source data to process and sent
        */

        /**
        * \brief Send a bits quarter (4 bits = MSB from 8 bits value) over RF
        * \param data Data to send
        */
        inline void sendQuarterMSB(const byte data)
        {
        (bitRead(data, 4)) ? sendOne() : sendZero();
        (bitRead(data, 5)) ? sendOne() : sendZero();
        (bitRead(data, 6)) ? sendOne() : sendZero();
        (bitRead(data, 7)) ? sendOne() : sendZero();
        }

        /**
        * \brief Send a bits quarter (4 bits = LSB from 8 bits value) over RF
        * \param data Data to send
        */
        inline void sendQuarterLSB(const byte data)
        {
        (bitRead(data, 0)) ? sendOne() : sendZero();
        (bitRead(data, 1)) ? sendOne() : sendZero();
        (bitRead(data, 2)) ? sendOne() : sendZero();
        (bitRead(data, 3)) ? sendOne() : sendZero();
        }

        /******************************************************************/
        /******************************************************************/
        /******************************************************************/

        /**
        * \brief Send a buffer over RF
        * \param data Data to send
        * \param size size of data to send
        */
        void sendData(byte *data, byte size)
        {
        for(byte i = 0; i < size; ++i)
        {
        sendQuarterLSB(data[i]);
        sendQuarterMSB(data[i]);
        }
        }

        /**
        * \brief Send an Oregon message
        * \param data The Oregon message
        */
        void sendOregon(byte *data, byte size)
        {
        sendPreamble();
        //sendSync();
        sendData(data, size);
        sendPostamble();
        }

        /**
        * \brief Send preamble
        * \details The preamble consists of 16 "1" bits
        */
        inline void sendPreamble(void)
        {
        byte PREAMBLE[]={
        0xFF,0xFF };
        sendData(PREAMBLE, 2);
        }

        /**
        * \brief Send postamble
        * \details The postamble consists of 8 "0" bits
        */
        inline void sendPostamble(void)
        {
        #ifdef THN132N
        sendQuarterLSB(0x00);
        #else
        byte POSTAMBLE[]={
        0x00 };
        sendData(POSTAMBLE, 1);
        #endif
        }

        /**
        * \brief Send sync nibble
        * \details The sync is 0xA. It is not use in this version since the sync nibble
        * \ is include in the Oregon message to send.
        */
        inline void sendSync(void)
        {
        sendQuarterLSB(0xA);
        }

        /******************************************************************/
        /******************************************************************/
        /******************************************************************/

        /**
        * \brief Set the sensor type
        * \param data Oregon message
        * \param type Sensor type
        */
        inline void setType(byte *data, byte* type)
        {
        data[0] = type[0];
        data[1] = type[1];
        }

        /**
        * \brief Set the sensor channel
        * \param data Oregon message
        * \param channel Sensor channel (0x10, 0x20, 0x30)
        */
        inline void setChannel(byte *data, byte channel)
        {
        data[2] = channel;
        }

        /**
        * \brief Set the sensor ID
        * \param data Oregon message
        * \param ID Sensor unique ID
        */
        inline void setId(byte *data, byte ID)
        {
        data[3] = ID;
        }

        /**
        * \brief Set the sensor battery level
        * \param data Oregon message
        * \param level Battery level (0 = low, 1 = high)
        */
        void setBatteryLevel(byte *data, byte level)
        {
        if(!level) data[4] = 0x0C;
        else data[4] = 0x00;
        }

        /**
        * \brief Set the sensor temperature
        * \param data Oregon message
        * \param temp the temperature
        */
        void setTemperature(byte *data, float temp)
        {
        // Set temperature sign
        if(temp < 0)
        {
        data[6] = 0x08;
        temp *= -1;
        }
        else
        {
        data[6] = 0x00;
        }

        // Determine decimal and float part
        int tempInt = (int)temp;
        int td = (int)(tempInt / 10);
        int tf = (int)round((float)((float)tempInt/10 - (float)td) * 10);

        int tempFloat = (int)round((float)(temp - (float)tempInt) * 10);

        // Set temperature decimal part
        data[5] = (td << 4);
        data[5] |= tf;

        // Set temperature float part
        data[4] |= (tempFloat << 4);
        }

        /**
        * \brief Set the sensor humidity
        * \param data Oregon message
        * \param hum the humidity
        */
        void setHumidity(byte* data, byte hum)
        {
        data[7] = (hum/10);
        data[6] |= (hum - data[7]*10) << 4;
        }

        /**
        * \brief Sum data for checksum
        * \param count number of bit to sum
        * \param data Oregon message
        */
        int Sum(byte count, const byte* data)
        {
        int s = 0;

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

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

        return s;
        }

        /**
        * \brief Calculate checksum
        * \param data Oregon message
        */
        void calculateAndSetChecksum(byte* data)
        {
        #ifdef THN132N
        int s = ((Sum(6, data) + (data[6]&0xF) - 0xa) & 0xff);

        data[6] |= (s&0x0F) <> 4;
        #else
        data[8] = ((Sum(8, data) - 0xa) & 0xFF);
        #endif
        }

        /******************************************************************/
        /******************************************************************/
        /******************************************************************/

        void setup()
        {

        pinMode(TX_PIN, OUTPUT);

        Serial.begin(9600);
        Serial.println("\n[Oregon V2.1 encoder]");

        SEND_LOW();

        #ifdef THN132N
        // Create the Oregon message for a temperature only sensor (TNHN132N)
        byte ID[] = {
        0xEA,0x4C };
        #else
        // Create the Oregon message for a temperature/humidity sensor (THGR228N)
        byte ID[] = {
        0x1A,0x2D };
        #endif

        setType(OregonMessageBuffer, ID);
        setChannel(OregonMessageBuffer, 0x20);
        setId(OregonMessageBuffer, 0xBB);
        }

        void loop()
        {
        // Get Temperature, humidity and battery level from sensors
        // (ie: 1wire DS18B20 for température, ...)

        DHT22_ERROR_t errorCode;

        // The sensor can only be read from every 1-2s, and requires a minimum
        // 2s warm-up after power-on.
        delay(2000);

        float t = myDHT22.getTemperatureC();
        float h = myDHT22.getHumidity();

        int hum = h * 10;
        int temp = t * 10;

        errorCode = myDHT22.readData();

        switch(errorCode)
        {
        case DHT_ERROR_NONE:
        // Alternately, with integer formatting which is clumsier but more compact to store and
        // can be compared reliably for equality:
        //
        char buf[128];
        sprintf(buf, "T%03hi%03hi ", temp, hum);

        Serial.println(buf);

        // vw_send((uint8_t *)buf, strlen(buf));
        // vw_wait_tx(); // Wait until the whole message is gone
        break;
        case DHT_ERROR_CHECKSUM:
        Serial.print("check sum error ");
        Serial.print(myDHT22.getTemperatureC());
        Serial.print("C ");
        Serial.print(myDHT22.getHumidity());
        Serial.println("%");
        break;
        case DHT_BUS_HUNG:
        Serial.println("BUS Hung ");
        break;
        case DHT_ERROR_TOOQUICK:
        Serial.println("Polled to quick ");
        break;
        }

        setBatteryLevel(OregonMessageBuffer, 1); // 0 : low, 1 : high
        setTemperature(OregonMessageBuffer, t);

        #ifdef THGR228N
        // Set Humidity
        setHumidity(OregonMessageBuffer, h);
        #endif

        // Calculate the checksum
        calculateAndSetChecksum(OregonMessageBuffer);

        // Show the Oregon Message
        for (byte i = 0; i > 4, HEX);
        Serial.print(OregonMessageBuffer[i] & 0x0F, HEX);
        }
        Serial.println();

        // Send the Message over RF
        sendOregon(OregonMessageBuffer, sizeof(OregonMessageBuffer));
        // Send a "pause"
        SEND_LOW();
        delayMicroseconds(TWOTIME*8);
        // Send a copie of the first message. The v2.1 protocol send the
        // message two time
        sendOregon(OregonMessageBuffer, sizeof(OregonMessageBuffer));

        // Wait for 30 seconds before send a new message
        SEND_LOW();
        int i =0;
        while (i++ < 70) {
        // Sleep for 8 s with ADC module and BOD module off x 70 = 560 s
        LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
        }

        }

        • yoon dit :

          Bonjour,
          petit déterrage de topic, cependant je suis fortement intéressé par le code pour le capteur à ultrason si toujours disponible :D
          Merci d’avance ;)

  16. David Pilling dit :

    Hi, many thanks for this code.

    I have a comment, after working out what follows, I’ve found my discovery is something that is well known, but I’ll repeat it here to save others effort.

    I got Ook_OSV2 from Jee Labs Cafe, written by Dominique Pierre. Worked well with my Oregon sensors.

    I then set up this encoder – would not work. The Ook code demands 32 bits in the preamble, and this code seems to generate 31..

    I have found that subsequent versions of the Ook code drop the preamble requirement to 24 bits, so the problem goes away if you’re using the latest version.

    • Olivier dit :

      Hi, you’re welcome :)
      Yes, Dominique Pierre explain me that sometimes the OokDecoder doesn’t « see » all 32 bits of the preamble. I have this problem with my THN132N sensors (31bits only are reported).

      However, if my encoder send only 31 bits, It’s a mistake … I need to check, thanks for pointing that out.

  17. dnis dit :

    Salut,
    Peut-on créer des sondes à bas cout en utilisant seulement la puce de l’Ardui (Atmega328) comme le montre Idleman , pour les utiliser sur Domoticz via RFXcom.
    merci d’avance.

    • Olivier dit :

      Salut,
      Oui c’est possible et c’était le but à l’origine des articles. Je ne m’en suis pas encore occupé mais j’ai tout ce qu’il faut pour le faire.
      J’aimerai être sous les 5€ boitier compris.

      • Galen dit :

        il semble que erwan ai déjà tenté l’expérience :)

        http://labalec.fr/erwan/?p=1489

        https://forum.jeedom.fr/viewtopic.php?f=36&t=1832

        hormis la conso électrique qui me semble a optimiser pour se rapprocher de celle des oregons officielles cela semble être un bon plan :)

        Apres va falloir que je potasse sérieusement l’arduino :)

        • Olivier dit :

          Salut,

          Oui j’ai vu le post d’Erwan, il ne reste plus qu’à supprimer l’arduino pour être un peut moins cher et plus petit :)

          Le coté conso n’est pas un problème je pense. Les sondes officielles émettent environ toutes les 30s mais tu peux monter à 1min, 5 min voir plus pour monitorer la température d’une pièce c’est largement suffisant. Ensuite, il suffit de mettre l’atmega en veille le reste du temps.
          On doit pouvoir tenir facilement plus d’un 1an à ce rythme avec une ou deux piles LR6.

          • Galen dit :

            C’est clair que les 30-40 secondes d’origine ne sont pas nécessaires :)

            Merci pour la réponse rapide

          • Erwan Labalec dit :

            Je viens de voir un lien vers mon site, Merci :)
            Ce site et cette page en particulier est une référence pour moi et m’a bcp aidé dans mes projets domotiques : un grand merci donc à Olivier !

            Pour info, oui un arduino ca consomme encore top.
            Donc, je suis passé sur un attiny85.
            Voir ici .
            Je passe 5ua en veille et 18ma en lecture : de quoi tenir longtemps, très longtemps sur une pile 3.7v / 1800 ma !

          • Olivier dit :

            Salut Erwan,
            Heureux de t’avoir été utile :)

            J’ai fais un test aussi avec un ATtiny et j’ai un article en préparation mais je n’arrive pas à le terminer, je cherche un petit boitier joli et pas cher, tu n’en aurais pas trouvé un ?
            ++

          • Erwan Labalec dit :

            Pour le boitier je me suis pas embête, je fais du strap sur une plaque mini de prototypage : ça me coûte pas cher et ma sonde est planqué derrière un meuble donc …
            voir photo ici

          • mulot35 dit :

            Salut,
            merci a Erwan pour son site et pour le boitier moi j’ai pris ca http://img15.hostingpics.net/pics/354568sondeo.jpg
            http://img15.hostingpics.net/pics/144889sondef.jpg
            1.5€ chez aliexpress

  18. Ludo dit :

    Bonjour à tous,

    Je souhaite faire un répéteur pour les sondes oregon dans le but d’augmenter la portée à partir d’un Uno. La partie réception fonctionne. Par contre la partie émission, j’ai plus de pb et en plus je débute avec Arduino.

    Si j’utilise le sketch d’Olivier, pas d’erreur de compilation par contre la zibase ne reçoit pas les ordres.

    En utilisant la correction de catalin, j’ai une erreur de compilation.

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

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

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

    return s;
    }

    Si quelqu’un pouvait m’aider…

    Merci

    • Olivier dit :

      Salut,
      Le code de l’article est correct, je l’avais corrigé suite au commentaire de catalin. Par contre dans son commentaire il y a une erreur (due à wordpress qui à supprimé un bout de code à l’enregistrement du commentaire :/) c’est pour cela que tu as une erreur de compilation.

  19. kaa dit :

    salut,

    Tout d’abord merci pour ton boulot de reverse.

    J’ai réussi à faire un module avec un DHT22+ Microview (arduino like)+Emetteur. ça fonctionne à merveille et est reconnu par domoticz comme un « THGN122/123, THGN132, THGR122/228/238/268″.

    j’ai essayé d’y ajouter un capteur BMP180 pour la pression et du coup, j’ai essayé de trouver quelle sonde Oregon faisait ça pour pouvoir l’émuler.
    il semble que la BTHR968/BTHR918N fait ça.

    J’ai essayé de l’émuler mais sans succès et même en émettant la trame soit disant de test du site http://www.mattlary.com/2012/06/23/weather-station-project/ ça ne fonctionne pas. le RFXCOM ne la voit pas.

    une idée sur le codage de cette sonde ?

  20. Michel Thevenot dit :

    Bonjour Olivier, bonjour à tous,

    Vraiment un grand bravo et un grand merci pour ce travail et cette mise à dispo, ça marche du tonnerre en réception comme en émission.

    Juste une petite remarque pour la partie réception, à l’intégration de la partie 3/3 j’ai eu une erreur de compilation avec « max_bits = 160; »que j’ai du déclarer ainsi « int max_bits; » en début du sketch.

    J’utilise un Tx/RX 433 vraiment pas cher (ce modèle : avec un fil de 17,5cm comme antenne, je me ballade dans toute la maison).

    Reste à traiter les infos, j’aimerais pouvoir interfacer avec Domoticz, à suivre…

    Merci encore
    Cordialement
    Michel

  21. DD91 dit :

    Bonjour

    deja bravo pour toute ces realisations qui font rever des novice comme moi :)

    je souhaite poser une petite question :)

    j’ai commencé a me pencher sur la domotique il y a peut et au regard du prix d’un z-wave et d’un rfxcom je trouve ca bete de mettre peux cher dans un rasp pour devoir payer a prix d’or une interface :)

    le module avec l’arduino presenté dans le post est-il compatible avec le logiciel domoticz?

    est ce que par exemple les prises radiocommandé d’idleman sont compatible avec par exemple?

    j’ai une sonde de temperature exterieure en 433mhz (vendu avec une horloge de base) est ce que ca peut etre compatible?

    merci d’avance de vos reponses

    DD91

  22. F1MVP dit :

    Bonsoir,
    Ces explications remontent un peu et font ma joie aujourd’hui j’ai pu moi aussi simuler des sondes « oregon » avec un Arduino ! et pour bien moins cher qu’une sonde « originale ».

    Un grand merci pour votre article.

    Par contre je serait à la recherche de l’encodage de sonde styles SD18, WD18,… (detecteurs de fumée, gaz, eau, …) et OWL (mesure de conso electyrique), quelqu’un aurait leurs protocoles ?

    Merci.

    • jsh dit :

      Salut F1MVP , je suis F1 JSH
      je suis comme toi à la recherche du protocole pour les OWL et autres sondes RFX as tu trouvé ces infos. J’ai cherché en vain…
      As tu trouvé quelques choses à ce sujet
      73 !!!
      Olivier

      • F1MVP dit :

        Bonjour,

        Non pas de réponse, un collègue m’a donné un morceau de code pour le décodage des trames, mais c’est à partir d’un récepteur RFX qui met déjà en forme ce qu’il a reçu. Donc je ne sais si la trame est complète (au niveau HF) et en plus il faut faire du rétro-engenering pour retrouver le contenu exact…
        73’s
        Thierry.

        • Snips dit :

          Bonjour,
          Je cherche aussi les informations sur le protocole owl : mon objectif est de simuler un compteur owl cm180 (micro+) en émettant en 433mhz les infos de comptage provenant de ma carte arduino branchée sur la prise teleinfo de mon compteur électrique ERDF. (J’ai une installation domotique basée sur domoticz + rfxcom USB).
          Le mieux que j’ai trouvé ce jour est sur http://forum.jeelabs.net/node/1038.html ou un forumeur disposant d’un owl cm119 signale que ce dernier utilise un protocole très proche d’0regon v3 et donne 2 trames capturees. Des que j’ai un peu de temps j’essaie de reconstituer le protocole du owl cm180 qui doit être proche.

          • onlinux dit :

            Bonjour,

            Pour le décodage des trames CMR180 j’ai mis à dispo le code sur un repo github (https://github.com/onlinux/OWL-CMR180)
            avec qq exemples d’appli pour arduino et raspberry pi.

            OSV3 62803C2801A0BE0313000020B5[CMR180,…] Id:6280, size:13 ,Flags:8 ,power:288 ,total:318946976 ,total kWh:88.60
            OSV2 1A2D10867018100535A6[THGR228N,…] Id:86 ,Channel:1 ,temp:18.70 ,hum:51 ,bat:90
            OSV2 1A2D20BB1C0940054700[THGR228N,…] Id:BB ,Channel:2 ,temp:9.10 ,hum:54 ,bat:10
            OSV2 1A2D10222017100424F4[THGR228N,…] Id:22 ,Channel:1 ,temp:17.20 ,hum:41 ,bat:90
            OSV2 1A2D10867018100535A6[THGR228N,…] Id:86 ,Channel:1 ,temp:18.70 ,hum:51 ,bat:90
            OSV3 62803C2801E0020413000000E4[CMR180,…] Id:6280, size:13 ,Flags:8 ,power:288 ,total:319029984 ,total kWh:88.62
            OSV2 1A2D40EC4120304440E6[THGR228N,…] Id:EC ,Channel:3 ,temp:20.40 ,hum:43 ,bat:90
            OSV2 1A2D10867018100535A6[THGR228N,…] Id:86 ,Channel:1 ,temp:18.70 ,hum:51 ,bat:90
            OSV2 1A2D20BB1C0940054700[THGR228N,…] Id:BB ,Channel:2 ,temp:9.10 ,hum:54 ,bat:10
            OSV3 62823CD800B0[CMR180,…] Id:6282, size:6 ,Flags:8 ,power:208
            OSV3 62813CE80040[CMR180,…] Id:6281, size:6 ,Flags:8 ,power:224

          • Snips dit :

            Merci onlinux !

          • snips dit :

            Encore merci onlinux,
            j’ai pu « rejouer » les trames que vous avez données pour faire croire à ma carte RFXCOM-USB que la carte arduino est un OWL CM180.

            Pour info : il faut absolument un « postamble » à 4 pulses « 0 » pour que RFXCOM reconnaisse la trame (par contre il est peu sensible au preamble : j’ai fait un test de 10 pulses à 32 pulses « 1 » de preamble et ca passe à chaque fois).

          • Domos dit :

            Bonjour,

            Serait-il possible d’avoir un exemple de code Arduino pour simuler un compteur owl cm180.

            merci

          • Snips dit :

            Je mettrai le bout de code des que c’est déverminé, peut être le we prochain.

        • F1MVP dit :

          Je vois que cela à avancé, j’ai trouvé aujourd’hui cet article :
          http://www.baghli.com/dspic_x10rf.php
          Ou il y a une explication du protocole X10, mais cela ne ressemble pas aux transmissions OWL et SD18.

          Merci pour vos infos.

          • snips dit :

            Comme promis ci-dessous le bout de code (pas du tout optimisé ni propre) pour simuler un CM180 (OWL micro+) vis à vis d’un RFXCOM-Usb.
            il réutilise largement le code de M. Olivier LEBRUN ele travail d’Onlinux ci-dessus.

            P.S. j’ai couplé ce code avec le code « Teléinfo » d’un montage arduino branché sur mon compteur électrique pour transmettre en 433Mhz la puissance apparente et les index compteurs HC et HP à mon RFXCOM-usb couplé à Domoticz.
            Je remercie l’auteur de ce Blog, Onlinux (ci-dessus) et M. Pascal Cardon (téléinfo : http://www.domotique-info.fr/2014/05/recuperer-teleinformation-arduino/).
            —————————————————–

            Le code est téléchargeable ici ->

          • snips dit :

            Il faut apporter un correctif au programme ino ci-dessus.
            La séquence de « postamble » consistant à faire 4 « SendZero » est incomplète ce qui peut faire planter le RFXCOM (je viens de le comprendre). Il faut y ajouter juste après un SEND_LOW() pendant une durée de 488 microsecondes (au moins).

            Donc dans la fonction « void sendPostamble(void) » après l’exécution de la boucle « for », à la fin, il faut ajouter les 2 lignes suivantes et cela marchera bien mieux :

            SEND_LOW();
            delayMicroseconds(TIME);

          • Olivier dit :

            J’ai apporté la modif dans le fichier à télécharger

  23. Equinoxefr dit :

    Bonjour,

    Super ton article. J’ai réutilisé ton code ( qui marche parfaitement d’ailleurs ;) pour communiquer à mon serveur domotique la température / humidité de mon garage et aussi la consommation de gaz de la maison.

    https://github.com/equinoxefr/gasMonitor

    Encore merci.

    Pierre

    • deennoo dit :

      Bonjour Pierre.

      Je suis aussi utilisateur de Domoticz et ton capteur de compteur gaz m interesse fortement.

      Comment est ton compteur gaz ? il a un emplacement prevu pour recevoir une telereleve ou c est le bete compteur blanc ?

      J’ai deja réaliser une copie de sonde osv3 (thgr810) visible par ma station meteo et par un soft utilisant un dongle usb tnt (rtl_433).

  24. snips dit :

    Bon, le copier et coller fait sauter les bouts de code…. notamment les signes les comparateurs et «  ». Désolé.

  25. Domos dit :

    @snips, merci pour le partage du code encodage CM180.

    Malheureusement la copie pose effectivement problème, il manque aussi des des accolades, il me semble.

    Possible de le partager sur une plateforme comme http://paste.debian.net qui permet de copier du texte/code pour une période limitée.

    merci

  26. deennoo dit :

    Snips

    Je viens d’essayer ton code pour la simulation du cm180, cela fonction nickel.

    Comment transmettre en valeur réel s’il te plait ?

    • snips dit :

      Bonsoir,

      Tu as déjà monté une carte électronique du type http://www.domotique-info.fr/2014/05/recuperer-teleinformation-arduino/ fonctionnelle et branchée sur les prises téléinfo de ton compteur électrique ?
      Tu as bien vérifié que ton compteur renvoie bien les données téléinfo ?

      • deennoo dit :

        La teleinfo fonctionne sans probleme, en direct sur mon PI, et en parrallele sur mon arduino.

        Ton code lui aussi fonctionne avec les valeurs fixe que tu as determiner 60000kw et 1000w

        J’ai essayer de commenté tes valeurs « test » forcement tout revient a 0

        Quand tu ecris que tu as couplé ton code avec celui de la teleinfo :

        – est ce que le code telechargeable ici est « complet » et l’accouplement est déja fait ?
        – est ce que je dois faire l’assemblage moi meme ?
        – en cas d assemblage maison, je prends quel code de teleinfo ? le test ou le final avec mise a jour du serveur web php ?.

        Ton code doit il envoyer les info d’heure pleines et d’heures creuses ?

        Merci de tes réponses

        • Snips dit :

          Parfait, j’ai déjà un code accouplé (encodeur + téléinfo) qui tourne chez moi depuis 2 semaines avec domoticz. Il faut que je nettoie le code et je demanderai a Olivier de publier sur le site (dans les jours qui viennent)
          Pour les heures creuses et heures pleines : j’ai opté pour la solution sous domoticz de créer 2 compteurs differents: 1 pour les heures pleines et un pour les heures creuses. La carte arduino va donc émuler 2 compteurs distincts (2 identifiants différents) qui retourne chacun l’index heure creuse ou pleine suivan la periode tarifaire retournee par teleinfo. J’envisage aussi d’émuler un troisième compteur où je cumulerai les index heures pleines et creuses mais ce n’est pas encore fait.

          • matyoo dit :

            Bonjour et merci à tous pour ce travail.
            J’ai pu grâce aux codes partagés simuler 2 sonde oregon avec un capteur DHT22 et un DS18B20 waterproof (pour une piscine) sur un atmega 328 en standalone le tout interfacer avec domoticz.
            Je suis actuellement en train de mettre en place la simulation OWL 180.
            A la différence des autres post je n’utilise pas le teleinfo mais un capteur CT SENSOR.
            J’arrive à intégrer dans le code OWL 180 la lecture de mon capteur en Watt, mais je ne sais pas comment faire pour envoyer correctement les bonnes infos à domoticz.
            compteur totale
            consommation « aujourd’hui »

            Si vous avez des idées.
            merci.

          • snips dit :

            Ok, j’ai nettoyé le code et débogué, je viens de l’envoyer à Olivier.

          • Olivier dit :

            Salut Snips, je n’ai rien reçu ?

          • matyoo dit :

            merci snips.
            Tu as la possibilité de le mettre à dispo ?
            Olivier doit être occupé.

          • snips dit :

            matyoo,
            je ne sais pas si ce lien vous sera utile : http://openenergymonitor.org/emon/node/58

            L’encodeur OWL Cm180 retourne à Domoticz une puissance (pour teleinfo = puissance apparente) et un « total usage » (pour télinfo = index compteur).

            Domoticz affiche la puissance et se sert de la variation du total usage (variation d’index compteur) pour calculer la consommation journalière.

            Donc votre carte arduino doit retourner a minima un total usage (index compteur) pour que cela fonctionne. Le lien ci-dessus devrait vous être utile.

          • matyoo dit :

            Merci je vais regarder ça et je vous fais un retour.

          • matyoo dit :

            Bonsoir snips,

            pour le lien j’utilise juste le current only je n’ai pas le dispositif AC voltage sur mon montage.
            Je multiplie A (current) *230 pour avoir la puissance en WATT.
            J’utilise donc qu’un seul PIN de mon arduino pour récupérer l’information.

            Pour revenir au code, Il faudrait donc que j’incrémente un total usage dans mon code.
            Je me pose la question s’il faut enregistrer ce totale dans l’eeprom en cas de coupure de courant. Sinon mon totale deviendra faux ?

            Sinon j’ai en ma possession un « vrai » OWL 180, il n’utilise pas le telinfo il a un CT SENSOR. C’est pour ça que je ne comprend pas que dans le code fourni on parle de teleinfo.

          • snips dit :

            Hello matyoo, pour répondre à votre question :
            >Télinfo : en France les compteurs électroniques ERDF comportent la plupart du temps des borniers téléinfo (I1, I2). Le compteur envoie des données en série 1200 bauds : puissance apparente, les index compteurs etc…..
            Donc quand on a la chance d’avoir un compteur de ce type, on a des mesures très précises (le compteur = instrument de mesure pour transaction) et on fait l’économie d’un OWL ou d’une pince ampèremétrique.

            >SI vous avez un OWL CM180, c’est reconnu directement par domoticz ! pourquoi ne pas l’utiliser !

            >Bon, si vous voulez utiliser votre CT SENSOR (je comprends ! c’est un défi, un challenge) effectivement pour Domoticz il me semble qu’il faut à partir de la puissance approximée A(t) * 230 multiplier par la durée entre 2 mesures puis ajouter cela au total pour avoir un total de consommation (énergie WH = index compteur). Ce chiffre devrait être mémorisé sur arduino d’une manière ou d’une autre. Après ce n’est pas catastrophique non plus si de temps temps le total compteur est « réinitialisé » car domoticz procède par différence (fin journée – début de journée il me semble) pour calculer la conso d’une journée. Une éventuelle anomalie sur Domoticz survient seulement pour le jour où le total compteur est réinitialisé (il suffit de corriger la base de données à la main avec sqlite manager par exemple….).

            P.S. : attention l’approximation A(t)* 230 V marche bien si vous avez des « résistances » chez vous genre chauffage électrique…. par contre si vous avez des plaques à induction (>> puissance réactive, cosphi <1) vous allez avoir une valeur A(t)* 230 V qui est supérieure à la puissance acive consommée réelle. Idem quand vous n'avez rien d'allumé chez vous, et vous n'avez que les appareils en veille… vous allez avoir un cosphi <1 et de la puissance réactive… C'est pour cela que, pour une mesure précise, il faut pouvoir mesurer la tension en plus de l'intensité.

          • deennoo dit :

            Je viens d’essaye le code « cleaner » et il ne fonctionne pas chez moi alors que le pas clean oui, j’ai l impression que rien n’est envoyer, et je n ai aucun retour dans la console de serial

            bien entendu le montage est le meme,, une idee ?

          • matyoo dit :

            Bonsoir Snips,

            J’utilise mon owl 180 dailleurs il marche très bien avec domoticz.
            Mais comme tu l’as dis c’est un challenge de réussir à en émuler un.
            Avec les infos que tu m’as donné « multiplié la valeur par la durée entre 2 mesures » + compteur totale je penses que je peux y arriver.
            Je vais alléger le code des entrées pour le teleinfo.

          • snips dit :

            deennoo,
            -j’ai re-téléchargé l’ino en lien ci-dessus, recompilé et déversé sur ma carte arduino et tout fonctionne chez moi.
            -si le programme encodeur_CM180.ino fonctionne chez vous : c’est que l’émetteur 433 mhz est ok
            -donc la conclusion c’est que la partie téléinfo qui a un problème. pour vérifier sur la console (PC branché sur l’USB) que tout est ok : dans la boucle loop il faut virer tout en bas les // devant la ligne // displayTeleInfo(); ce qui va activer le module d’affichage displayTeleInfo();
            Sur la console vous devez voir les data téléinfo. si vous ne voyez rien, c’est normal qu’il n’y a pas d’émission 433 Mhz car celle ci n’est activé que si une trame téléinfo a été correctement reçue.
            Si c’est le cas je vous suggère de vérifier si qqch n’a pas bougé (contact, cable; composant sur partie électronique teleinfo.

            Bon courage !

          • matyoo dit :

            Bonsoir,

            j’ai réussi à avoir les bonnes informations remontées dans domoticz.
            Ci-dessous le code utilisé
            http://matyoo.free.fr/owl_180.txt

            Il faudrait envoyé aussi la valeur de la batterie dans le code, car dans domoticz la sonde remonte en batterie faible (en tête en jaune). Mais je ne sais pas quel numéro de byte utiliser car ceux utilisés ci-dessous ne correspondent pas au code qu’on utilise.

            J’ai trouvé le code ci-dessous pour le rfxcom et le owl 180.
            Je ne sais pas si vous le connaissiez déjà.

            http://rfxcom.readthedocs.org/en/latest/_modules/rfxcom/protocol/elec.html

            «  » »The Elec protocol is a 17 byte packet used by energy sensors. The
            sensors transmit this packet periodically and the key data it provides is
            the current watt usage and total watt usage. It is used for example by the
            Owl energy monitors.

            ==== ====
            Byte Meaning
            ==== ====
            0 Packet Length, 0x11 (excludes this byte)
            1 Packet Type, 0x5A
            2 Sub Type
            3 Sequence Number
            4 ID 1
            5 ID 2
            6 Count (?)
            7 Current Watts 1
            8 Current Watts 2
            9 Current Watts 3
            10 Current Watts 4
            11 Total Watts 1
            12 Total Watts 2
            13 Total Watts 3
            14 Total Watts 4
            15 Total Watts 5
            16 Total Watts 6
            17 Battery Level and RSSI
            ==== ====
            «  » »

            Et encore merci pour l’aide.

            Je vais m’attaquer maintenant au compteur d’eau, je viens de recevoir mes modules CNY 70

          • Snips dit :

            Oui il s’agit du format des trames retournées par rfxcom mais cela ne correspond pas aux trames émises pas le owl cm180 (rfxcom reformate les trames suivant son standard). J’avais fait varier quelques valeurs des octets/quartets de la trame de l’owl non encore décodés (,on ne sait pas a quoi ils servent) pour essayer de voir si cela change l’etat des batteries dans domoticz mais ça restait toujours a faible. J’ai laisse tomber si j’ai le courage je m’y remets (balayer toutes les valeurs et voir sur la console rfxcom ou domoticz si ça change qqch… C’est super pénible !).

  27. Snips dit :

    Je renvoie tout de suite par mail il y a du avoir un problème avec ma messagerie.

  28. Michel Lafond dit :

    Bonjour,
    Un grand merci pour tout ce travail.
    J’ai repris le code pour faire un répétiteur et

  29. Michel Lafond dit :

    Je voudrais ajouter des infos en queue du message.
    Cela fonctionne bien jusqu’à 5 octets mais au-dessus, le message n’est pas reçu.
    J’ai augmenté un peu sauvagement la valeur max_bits mais cela ne l’a pas impressionné.
    Comme je ne comprends pas bien le fonctionnement du décodeur, je suis bloqué.
    Quelle serait la manipulation à faire pour allonger les messages simulant les sondes 0xEA4C ou 0x1A2D.
    Mon admiration pour l’ensemble du sujet !

  30. philippe hervier dit :

    Tout d’abord merci pour ce code très complet.

    Je viens juste de coder et tester le calcul de CRC pour les sondes THGR122NX.

    C’est bien un CRC8, pour le calcul duquel il faut supprimer l’ID et initialiser à 0x3C.

    voici le code complet : (à appeler à la place de calculateAndSetChecksum(OregonMessageBuffer, false) par checkSumAndCRC(OregonMessageBuffer,8) )

    void checkSumAndCRC(byte * data, const uint8_t len)
    {
    #define mByte(i) (data[i])
    #define NIBBLE(i) ((mByte(i>>1) >> (((i)&1)<<2))&0xf)
    uint8_t i,j,c,CRC,SUM;

    CRC =0x3C;
    SUM =0x00;

    uint8_t CCIT_POLY = 0x07;

    for (j=1; j<2*len; j++)
    {
    c = NIBBLE(j);
    SUM += c;
    if ( j != 6 && j != 7){ // place for ID
    CRC ^= c;
    for(i = 0; i<4; i++)
    if(CRC & 0x80 )
    CRC = (CRC << 1) ^ CCIT_POLY;
    else
    CRC <<= 1;
    CRC &= 0xff;
    }
    }
    for(i = 0; i<4; i++)
    if(CRC & 0x80 )
    CRC = (CRC << 1) ^ CCIT_POLY;
    else
    CRC <<= 1;

    data[len] = (SUM & 0xFF);
    data[len+1]= CRC;

    }

  31. Glubinours dit :

    Bonjour,

    merci pour cet article c’est vraiment super !
    Je voudrais installer un dizaine de sondes dans ma maison et je ne vois pas comment mon récepteur va les distinguer.
    Peut-être ceci est-il lié au paramètre channel ? et dans ce cas on est limité à 3 sondes. N’y a t’il pas un identifiant de sonde que l’on peut faire varier (par des micro switch par exemple) ?
    merci pour votre aide car je suis un peut perdu !
    Cordialement

    • Olivier dit :

      Salut,
      Si, l’identifiant c’est le code hexa que tu renseigne via la fonction : (ici 0xBB)
      setId(OregonMessageBuffer, 0xBB);

      Dans les trames que tu vas récupérer, soit avec un arduino récepteur (voir les articles sur la réception), soit avec un rfxcom, tu auras ce code comme identifiant.
      Tu peux donc le modifier pour chaque sonde ou brancher un dip switch et récupérer le code configuré.

  1. 6 octobre 2014

    […] comes the rf433_sendOOK. Note that that I am re using code from connectingstuff.net to send oregon 2.1 compatible […]

  2. 1 janvier 2015

    […] j’ai plutôt utilisé le format Oregon V2 gentiment mis à disposition par Olivier ici. Le nombre d’impulsions comptées est stocké dans l’EEPROM de l’arduino toutes […]

Laisser un commentaire

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

Vous pouvez utiliser ces balises et attributs HTML : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>