#include #include "EmonLib.h" // Include Emon Library #include EnergyMonitor emon1; // Create an instance const byte TX_PIN = 10; // module 433 mhz const unsigned long TIME = 488; const unsigned long TWOTIME = TIME*2; #define SEND_HIGH() digitalWrite(TX_PIN, HIGH) #define SEND_LOW() digitalWrite(TX_PIN, LOW) byte OregonMessageBuffer[12]; // OWL180 //********************************************************* float Puissance_inst; // puissance instantannée en watt float P2mesure; // puissance totale entre 2 mesures int Compteur_totale; // compteur toale à transmettre int Puissance_inst_arrondi; unsigned long chksum_CM180; int addr = 0; //********************************************************************** /** * \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_LOW(); delayMicroseconds(TIME); 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_HIGH(); delayMicroseconds(TIME); SEND_LOW(); delayMicroseconds(TIME); } /** * \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) { (bitRead(data[i], 0)) ? sendOne() : sendZero(); (bitRead(data[i], 1)) ? sendOne() : sendZero(); (bitRead(data[i], 2)) ? sendOne() : sendZero(); (bitRead(data[i], 3)) ? sendOne() : sendZero(); (bitRead(data[i], 4)) ? sendOne() : sendZero(); (bitRead(data[i], 5)) ? sendOne() : sendZero(); (bitRead(data[i], 6)) ? sendOne() : sendZero(); (bitRead(data[i], 7)) ? sendOne() : sendZero(); } } /** * \brief Send an Oregon message * \param data The Oregon message */ void sendOregon(byte *data, byte size) { sendPreamble(); sendData(data, size); sendPostamble(); } /** * \brief Send preamble * \details The preamble : 10 pulse à 1 suffit pour RFXCOM */ inline void sendPreamble(void) { for(byte i = 0; i < 10; ++i) //OREGON V3 { sendOne(); } } /** * \brief Send postamble * \details The postamble consists of 4 "0" bits */ inline void sendPostamble(void) { for(byte i = 0; i <4 ; ++i) { sendZero() ; } // Ajout suite commentaire http://connectingstuff.net/blog/encodage-protocoles-oregon-scientific-sur-arduino/#comment-61955 SEND_LOW(); delayMicroseconds(TIME); } /******************************************************************/ void displayTeleInfo() { //Compteur_totale = EEPROM.read(addr); //lis dans l'eeprom a l'adresse 0 la valeur du compteur totale double Irms = emon1.calcIrms(1480); // Calculate Irms only Ampere Puissance_inst=(Irms*230.0); // Ampere multiplié par 230 v => puissance instantane en Watt Puissance_inst_arrondi=(Puissance_inst*497L/500L/16L); // on divise par 16 car rfxcom va multiplié par 16 la valeur pour l'afficher dans domoticz P2mesure=(Puissance_inst/60); //on fait un check toutes les minutes (60 s) donc on divise par 60 pour avoir la conso réel sur une minute. P2mesure=(P2mesure*223666LL)/1000LL; //RFXCOM récupère la valeur émise puis divise par 223,666 pour avoir l'index en Watt.Heure dans domoticz, donc on fait l'inverse pour retrouver la bonne valeur. Compteur_totale=(Compteur_totale+P2mesure); //on incremente le compteur totale //EEPROM.write(addr, Compteur_totale); //enregistre dans l'eeprom la valeur totale en cas de coupure ou redemarrage de l'arduino // améliore un peu la précision de la puissance apparente encodée (le CM180 transmet la PAPP * 497/500/16) if ((float(Puissance_inst)*497/500/16-Puissance_inst_arrondi)>0.5) { ++Puissance_inst_arrondi; } OregonMessageBuffer[0] =0x62; // imposé OregonMessageBuffer[1] =0x80; // GH G= non décodé par RFXCOLM, H = Count OregonMessageBuffer[2] =0x3C; // IJ ID compteur : "L IJ 2" soit (L & 1110 )*16*16*16+I*16*16+J*16+2 //OregonMessageBuffer[3] =0xE1; // KL K sert pour puissance instantanée, L sert pour identifiant compteur OregonMessageBuffer[3]=(Puissance_inst_arrondi&0x0F)<<4; //OregonMessageBuffer[4] =0x00; // MN puissance instantanée = (P MN K)*16 soit : (P*16*16*16 + M*16*16 +N*16+K)*16*500/497. attention RFXCOM corrige cette valeur en multipliant par 16 puis 500/497. OregonMessageBuffer[4]=(Puissance_inst_arrondi>>4)&0xFF; //OregonMessageBuffer[5] =0xCD; // OP Total conso : YZ WX UV ST QR O : Y*16^10 + Z*16^9..R*16 + O OregonMessageBuffer[5]=((Puissance_inst_arrondi>>12)&0X0F)+((0&0x0F)<<4); //OregonMessageBuffer[6] =0x97; // QR sert total conso OregonMessageBuffer[6] =(Compteur_totale>>4)&0xFF; //OregonMessageBuffer[7] =0xCE; // ST sert total conso OregonMessageBuffer[7] =(Compteur_totale>>12)&0xFF; // ST sert total conso //OregonMessageBuffer[8] =0x12; // UV sert total conso OregonMessageBuffer[8] =(Compteur_totale>>20)&0xFF; // UV sert total conso //OregonMessageBuffer[9] =0x00; // WX sert total conso OregonMessageBuffer[9] =(Compteur_totale>>28)&0xFF; //OregonMessageBuffer[10] =0x00; //YZ sert total conso OregonMessageBuffer[10] =(Compteur_totale>>36)&0xFF; chksum_CM180= 0; for (byte i=0; i<11; i++) { chksum_CM180 += long(OregonMessageBuffer[i]&0x0F) + long(OregonMessageBuffer[i]>>4) ; } chksum_CM180 -=2; // = =b*16^2 + d*16+ a ou [b d a] Serial.print(F(" chksum_CM180 HEX :")); Serial.println(chksum_CM180,HEX); //OregonMessageBuffer[11] =0xD0; //ab sert CHECKSUM somme(nibbles ci-dessus)=b*16^2 + d*16+ a + 2 OregonMessageBuffer[11] =((chksum_CM180&0x0F)<<4) + ((chksum_CM180>>8)&0x0F); //OregonMessageBuffer[12] =0xF6; //cd d sert checksum, a non décodé par RFXCOM OregonMessageBuffer[12] =(int(chksum_CM180>>4)&0x0F); //C = 0 mais inutilisé for (byte i = 0; i <=sizeof(OregonMessageBuffer); ++i) { Serial.print(OregonMessageBuffer[i] >> 4, HEX); Serial.println(OregonMessageBuffer[i] & 0x0F, HEX); } Serial.print("WATT:"); Serial.println(); Serial.println(Puissance_inst); Serial.println(P2mesure); Serial.print("puissance arrondi /16:"); Serial.println(Puissance_inst_arrondi); Serial.print("compteur totale:"); Serial.println(Compteur_totale); } //************************************************************************************ void setup() { Serial.begin(115200); Serial.println("CM180 test!"); // using 30A CT emon1.current(4, 30.0); // Current: input pin 4 ou est branché le CT SENSOR, calibration 30 Ampere. } void loop() { Serial.print(F("loop")); displayTeleInfo(); // cette fonction encode la trame à émettre et l'affiche (moniteur série sur 115 200 bauds) //mySerial->begin(115200); delay(60000); // temps d'attente avant nouvelle transmission 1 minutes owl 180 envoi toutes les minutes // Send the Message over RF sendOregon(OregonMessageBuffer, sizeof(OregonMessageBuffer)+1); }