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..
Par : catalin
Par : engel
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);
}
Par : catalin
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.
Par : engel
I will buy a RF emitter this evening and do a few test, I will post the results here.
Par : Olivier
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.
Par : Olivier
Bonjour Robert,
Désolé pour le tps de réponse :/
Oui j’en ai vu un il y a un moment (cf lien en bas de page ici : http://jeelabs.net/projects/cafe/wiki/Decoding_the_Oregon_Scientific_V2_protocol ) mais malheureusement la page n’est plus accessible et je ne l’ai pas conservée.
Mais avec les spec il doit être possible de modifier le décodeur actuel pour le faire fonctionner avec la version 1.0 du protocole.
Par : gribouille
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
Par : gribouille
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
Par : engel
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 0×57 dans votre cas.
Par : gribouille
bon j’ai testé en enlevant le 57 , mais c’est pas ça
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
********************************************************
Par : Florent
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
Par : gribouille
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
Par : Olivier
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 :/
Par : gribouille
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 ^_^ )
Par : Julien
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
Par : Olivier
Salut,
Merci pour le retour, ça fait plaisir
Par : Leon
Salut,
Can you share your code here? Merci.
Par : Julien
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);
}
}
Par : pascal
Bonjour engel
Avez vous pu confirmer qu’il s’agit bien d’un CRC 8 ? Si oui avec quel polynome ?
J’ai testé avec 0×07 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
Par : guillaume
quelqu’un a t’il reussi a faire reconnaitre une sonde simulé sur une station oregon?