--------------------------------------------------------------------------------------- ----------------------- LkyRx_10E.ino ------------------------- ----------------------------------------------------------------------------------------- ----------------------- LinkyHistTIC.cpp ----- LinkyHistTIC.h ----------------------- /*********************************************************************** Récepteur TIC Linky --- Mode historique V03 : External SoftwareSerial. Tested OK on 07/03/18. V04 : Replaced available() by new(). Tested Ok on 08/03/18. V05 : Internal SoftwareSerial. Cf special construction syntax. V06 : Separate compilation version. V10a : Parametric version, initial. Tested OK on 23/10/19. V10b : fixed bug in ptecIsNew(). Tested OK on 24/10/19. V10c : added LKYSIMINPUT mode. Tested OK (partial) on 31/10/19. V10d : adapted to Arduino Uno and Mega. Tested Ok on 27/04/20. V10e : added optional ISOUSC. OK 26/11/22 *********************************************************************** Configuration parameters are defined in LinkyHistTIC.h ***********************************************************************/ /* * ---- types de variables -------- uint16_t papp(); Returns papp in VA uint32_t base(); Returns base index in Wh uint32_t hchc(); Index heures creuses en Wh uint32_t hchp(); Index heures pleines en Wh uint8_t ptec(); Periode tarifaire en cours (0 = HP, 1 = HC) uint8_t iinst(); Returns iinst in A */ //------------ https://forum.arduino.cc/t/decodeur-tic-linky-le-retour/1057221/4 ------- // //................. Librairie SoftwareSerial désactiver --------------------- // //-------------------- ajout de la partie Node To Node ------------------------------------ //------------------------------------------------------------------------- //****** Arduino Uno - MySensors et RS485 ********* 2022 //------------------------------------------------------------------------- //--- Enable debug prints MySensors, Enable debug prints to serial monitor //#define MY_DEBUG // mode standard terminal en 115200baud //#define MY_DEBUG_LOCAL //#define MY_BAUD_RATE 1200 // pour definir vitesse du terminal debug?? //----------------- MySensors -------------------------- #define MY_NODE_ID 36 /*Node en ID static*/ // #define MY_TRANSPORT_WAIT_READY_MS 3000 //Timeout (ms) pour mis en Com.(0 pour aucun) /* nécessaire lorsque pas connecté à la passerelle, pour test*/ //.......... RS485 .......................... #define MY_RS485 // Enable RS485 transport layer #define MY_RS485_DE_PIN 2 // Define this to enables Cmd DE-pin management on defined pin #define MY_RS485_BAUD_RATE 9600 // Set RS485 baud rate to use (9600 mode standard) // #define MY_RS485_HWSERIAL Serial3 // choix du port RX-Tx sur Mega2560 #define DELAY_PREFIX 50 #define DELAY_PRESENTATION 100 // tempo du Wait /***************************** Includes *******************************/ #include #include #include #include "LinkyHistTIC.h" /********************** MyS *******************************/ #define OPTARIF_CHILD_ID 0 // test base #define PAPP_CHILD_ID 1 //Puissance apparente (5car. unité=VA) #define HCHC_CHILD_ID 2 //Index heures creuses si option (9car.unité=Wh) #define HCHP_CHILD_ID 3 //Index heures pleines si option heures creuses (9car.unité=Wh) #define PTEC_CHILD_ID 4 //Période tarifaire en cours (4car. texte ) #define IINST_CHILD_ID 5 //Intensité instantanée (3car. unité=ampères) #define ISOUSC_CHILD_ID 6 //Intensité instantanée (3car. unité=ampères) #define seuil1Papp_CHILD_ID 8 //seuil1 Puissance apparente (5car. unité=VA) #define seuil2Papp_CHILD_ID 9 //seuil2 //----------- Node To Node ------ #define DISPLAY_NODE_ID 29 // Node de l'afficheur #define NtNva_CHILD_ID 100 //valeur Puissance apparente sur OLED MyMessage NtNmsgVA(NtNva_CHILD_ID, V_VA); // message VA MyMessage msgOPTARIF (OPTARIF_CHILD_ID, V_TEXT); MyMessage msgPAPP (PAPP_CHILD_ID, V_VA); MyMessage msgHCHC (HCHC_CHILD_ID, V_KWH); MyMessage msgHCHP (HCHP_CHILD_ID, V_KWH); MyMessage msgPTEC (PTEC_CHILD_ID, V_TEXT); MyMessage msgIINST(IINST_CHILD_ID, V_CURRENT); MyMessage msgISOUSC(ISOUSC_CHILD_ID, V_CURRENT); MyMessage msgSeuil1Papp (seuil1Papp_CHILD_ID, V_PERCENTAGE); MyMessage msgSeuil2Papp (seuil2Papp_CHILD_ID, V_PERCENTAGE); /* MyMessage Types: V_TEXT = S_INFO / V_CURRENT V_VOLTAGE = S_MULTIMETER / V_VA V_WATT V_KWH = S_POWER */ /****************************** Defines *******************************/ bool info; // pour info GW sur MyC // ------ gestion des 3 leds de seuil HL 1 et 2 --------------- const byte pinLED_R = 12; //declaration de la led rouge const byte pinLED_J = 11; //declaration de la jaune const byte pinLED_V = 10; //declaration de la led verte int val_papp ; //recopy de Linky.papp int seuil1_papp ; // consigne HL1 en VA int seuil2_papp ; // consigne HL2 bool statR = false; bool statJ = false; bool statV = false; //---------- test Hysteresis define seuil PAPP ---------------- // #define Alarm_PIN 12 // #define Alarme_ON 1 // Valeur pour activer le relais (led) // #define Alarme_OFF 0 //int seuil1 ; //int seuil2 ; //int setpoint = hlVA; // Point de Consigne //int HYST = 10; // seuil hystérésis //bool StatHyst = false; // doit être global ou statique! /****************************** Defines *******************************/ #define VERSION "V10E" /****************************** Constants *****************************/ /************************* Global variables ***************************/ /************************* Object instanciation ***********************/ LinkyHistTIC Linky(LKYRX_INPUT, LKYTXPIN); /**************************** Routines ******************************/ /****************************** Setup *******************************/ void setup() { //---- test set point ----- /* send(msgSeuilPapp.set(info)); send(msgPAPP.set(info)); send(msgOPTARIF.set(info)); send(msgIINST.set(info)); send(msgHCHP.set(info)); send(msgHCHC.set(info)); send(msgPTEC.set(info)); send(msgISOUSC.set(info)); */ /* Initialise serial link */ #ifndef LKYSIMINPUT Serial.begin(9600); #endif Linky.Init(); /* Initialise the Linky receiver */ // Serial << F("Bonjour - ") << VERSION << endl; pinMode( pinLED_R , OUTPUT); // mode sortie pinMode( pinLED_J , OUTPUT); pinMode( pinLED_V , OUTPUT); digitalWrite(pinLED_R , LOW); //LOW au démarrage digitalWrite(pinLED_J , LOW); digitalWrite(pinLED_V , LOW); } /******************* Presenstation MyS ********************************/ void presentation() { sendSketchInfo("Teleinfo2", "Ver2.4"); // Send the sketch version info sur gateway and Controller present (OPTARIF_CHILD_ID, S_INFO, F("OPTARIF")); //???? present(PAPP_CHILD_ID, S_POWER, "PAPP"); present(HCHC_CHILD_ID, S_POWER, "HCHC"); wait(DELAY_PRESENTATION); present(HCHP_CHILD_ID, S_POWER, "HCHP"); present(PTEC_CHILD_ID, S_INFO, "PTEC"); present(IINST_CHILD_ID, S_MULTIMETER, "IINST"); wait(DELAY_PRESENTATION); present(ISOUSC_CHILD_ID, S_MULTIMETER, "ISOUSC"); present( seuil1Papp_CHILD_ID, S_DIMMER, "HL1 VA" ); // HL VA present( seuil2Papp_CHILD_ID, S_DIMMER, "HL2 VA" ); // HL VA wait(DELAY_PRESENTATION); present(NtNva_CHILD_ID, S_POWER, "PAPP"); //Node To Node Linky VA sur OLED } //----- reception MyS ------------ void receive(const MyMessage &message) { if (message.getType() == V_PERCENTAGE) { if (message.sensor == 8) { //seuil1Papp_CHILD_ID seuil1_papp = atoi( message.data ); //Récupérer la valeur ID8 à partir du message } if (message.sensor == 9) { //seuil2Papp_CHILD_ID seuil2_papp = atoi( message.data ); //Récupérer la valeur ID9 à partir du message } //limite valeur entrant dans la plage valide : 0 to 60000VA // seuil_papp = seuil_papp > 30 ? 30 : hlVA; // seuil_papp = seuil_papp < 0 ? 0 : hlVA; } //----- retour valeur pour MyC ------- send ( msgSeuil1Papp.set(seuil1_papp) ); send ( msgSeuil2Papp.set(seuil2_papp) ); } /******************************* Loop *********************************/ void loop() { uint8_t i; Linky.Update(); // ----------- PAPP if (Linky.pappIsNew()) { //Serial << F("Puis. app. = ") << Linky.papp() << F(" VA") << endl; send(msgPAPP.setSensor(PAPP_CHILD_ID).set(Linky.papp())); val_papp = Linky.papp(); //----- NodeToNode -------- NtNmsgVA.setDestination(DISPLAY_NODE_ID); send(NtNmsgVA.set(val_papp)); } //----------- BASE #ifdef LKY_Base if (Linky.baseIsNew()) { //Serial << F("Index base = ") << Linky.base() << F(" Wh") << endl; send(msgOPTARIF.setSensor(OPTARIF_CHILD_ID).set(Linky.base())); } #endif //----------- index des tarifs------------- #ifdef LKY_HPHC if (Linky.hchpIsNew()) { //Serial << F("Index HP = ") << Linky.hchp() << F(" Wh") << endl; send(msgHCHP.setSensor(HCHP_CHILD_ID).set(Linky.hchp())); } if (Linky.hchcIsNew()) { //Serial << F("Index HC = ") << Linky.hchc() << F(" Wh") << endl; send(msgHCHC.setSensor(HCHC_CHILD_ID).set(Linky.hchc())); } //----------- Tarif en cours ------------- if (Linky.ptecIsNew()) { //Serial << F("Tarif en cours : "); if (Linky.ptec() == Linky.C_HPleines) { //Serial << F("heures pleines") << endl; send(msgPTEC.setSensor(PTEC_CHILD_ID).set("HPleines")); //HCHP } else { //Serial << F("heures creuses") << endl; send(msgPTEC.setSensor(PTEC_CHILD_ID).set("HCreuses")); //HCHC } } #endif //----------- IINST #ifdef LKY_IMono if (Linky.iinstIsNew()){ //Serial << F("I instant. = ") << Linky.iinst() << F(" A") << endl; send(msgIINST.setSensor(IINST_CHILD_ID).set(Linky.iinst(),1)); } #endif //----------- non activer #ifdef LKY_ITri for (i = Linky.C_Phase_1; i <= Linky.C_Phase_3; i++) { if (Linky.iinstIsNew(i)) { //Serial << F("I Phase ") << i+1 << F(" = ") \ << Linky.iinst(i) << F(" A") << endl; } } #endif //----------- ISOUSC #ifdef LKY_ISOUSC if (Linky.isouscIsNew()) { // Serial << F("Intensité souscrite = ") << Linky.isousc() << F(" A (par phase)") << endl; send(msgISOUSC.setSensor(ISOUSC_CHILD_ID).set(Linky.isousc(),1)); } #endif // ............... hystérésis sur PAPP ................ /* if (val_papp > (seuil_papp + HYST )) { StatHyst = true; digitalWrite(Alarm_PIN, StatHyst); } if (val_papp < (seuil_papp - HYST )) { StatHyst = false; digitalWrite(Alarm_PIN, StatHyst); } */ if (val_papp > seuil2_papp ) statR = true; else statR = false; // Led Rouge if (val_papp >= seuil1_papp && val_papp <= seuil2_papp ) statJ = true; else statJ = false; // Led Jaune if (val_papp < seuil1_papp ) statV = true; else statV = false; //Led Vert digitalWrite(pinLED_R, statR ); // Led rouge allumer au dessus de seuil2 digitalWrite(pinLED_J, statJ ); // led jaune allumer entre seuil1 et 2 digitalWrite(pinLED_V, statV ); // led verte allumer en dessous de seuil1 }; /************ Fin de LOOP *******************/ //------------------------ Fin Pgm ---------------------------- --------------------------------------------------------------------------------------- ----------------------- Oled_Time_LinkySensor_MyS_RS485_ID29.ino ------------------------- ----------------------------------------------------------------------------------------- /* * LIBRAIRIE: * MySensors v2 : https://github.com/mysensors/MySensors * TimeLib.h : https://github.com/PaulStoffregen/Time * SSD1306Ascii.h : https://github.com/greiman/SSD1306Ascii * * MATERIEL: * - Arduino Uno * - Afficheur OLED 0,96" I2C TF052 / circuit SSD1306. * - TTLModule bus RS485 * * REVISION HISTORY * base de Henrik Ekblad 2013-2015 et autres :) * ajout bus RS485 et OLED * * DESCRIPTION * demander Date et Heure au contrôleur et l'affiche sur ecran OLED * * Connectique i2c: * Arduino : A4 A5 * OLED : SDA SCL * */ //------------ 2022 ----------------------- Fonctionnelle avec MyC et MyS------------------- // ---- ajout partie Node To Node pour les valeurs VA du Linky ------------ //#define MY_DEBUG /*Enable debug prints to serial monitor*/ // #define MY_TRANSPORT_WAIT_READY_MS 3000 /*Timeout (ms) pour mis en Com.(0 pour aucun)*/ #define MY_NODE_ID 29 /*Node local en ID static*/ /* ----- Module RS485 ----*/ #define MY_RS485 /*Apl du transport RS485 (protocol?)*/ #define MY_RS485_DE_PIN 2 /*Cmd DE pin*/ #define MY_RS485_BAUD_RATE 9600 /*Set RS485 baud rate to use*/ //#define MY_RS485_HWSERIAL Serial1 /*pour port Serial autre*/ #include "SSD1306Ascii.h" #include "SSD1306AsciiAvrI2c.h" #include #include //#define CHILD_ID 22 /* MyS numero child */ // -------------------- MyS -- Node To Node-------------------------------- #define PAPP_SENSOR_ID 100 // sensor distant #define LINKY_NODE_ID 36 // Node distant #define I2C_ADDRESS 0x3C /*i2c adresse*/ #define RST_PIN -1 // Define proper RST_PIN if required.(oled) SSD1306AsciiAvrI2c oled; //type de com oled //----- MyS ------ bool timeReceived = false; bool stateCom = false; unsigned long lastUpdate=0, lastRequest=0; unsigned long newTime = 0, oldTime = 0; uint16_t valPAPP ; // valeur PAPP NtN uint16_t oldvalPAPP ; // pour compar valeur PAPP //---------------- SETUP ---------------------------- void setup() { //--- OLED ---- #if RST_PIN >= 0 oled.begin(&Adafruit128x32, I2C_ADDRESS, RST_PIN); #else // RST_PIN >= 0 oled.begin(&Adafruit128x32, I2C_ADDRESS); #endif // RST_PIN >= 0 oled.setFont(Adafruit5x7); /*font Oled*/ // oled.setFont(font8x8); //bien // oled.setFont(Verdana12); //grand // oled.setFont(fixed_bold10x15); //tres grand // oled.setFont(Arial_bold_14); //grand sympa oled.clear(); } //--------------MySensors------------- void presentation() { sendSketchInfo("NtN_ Clock et Linky", "2.0"); } //------------------ LOOP ----------------------- void loop() { unsigned long nowmillis = millis(); if (nowmillis > lastUpdate + 60000) //60000=1minute { requestTime(receiveTime); //Apl Time de MyC updateDisplay(); //Apl fonction display Oled lastUpdate = nowmillis; //restart tempo //Serial.print(" test NtN : "); Serial.println(valPAPP); //----- test com MyC --------- if (newTime != oldTime) { //En Com Controller oldTime = newTime ; stateCom = true; //Serial.print("---- En Com Controller ---- "); //Serial.print("\t\tstat newTime : "); //Serial.println(newTime); } else { // Erreur Com Controller stateCom = false; //Serial.println(" ----*** Erreur Com Controller *** ---- "); } } //------------ rafraichissement des valeurs PAPP (refreshment of values) ------- if (valPAPP != oldvalPAPP) { //compar valeur pour mis a jour Oled updateDisplay(); //Apl fonction display Oled oldvalPAPP = valPAPP; } } // -------------------- MyS -------------------------------- void receiveTime(unsigned long controllerTime) { newTime = controllerTime; timeReceived = true; setTime(controllerTime); // apl pour TimeLib.h } // -------------------- MyS -- Node To Node-------------------------------- /* info: * #define PAPP_SENSOR_ID 100 * #define LINKY_NODE_ID 36 * uint16_t valPAPP = 0; */ void receive(const MyMessage &message) { if (message.sender == LINKY_NODE_ID) { // message from node if (message.sensor == PAPP_SENSOR_ID && message.type == V_VA) // message from sensor { valPAPP = message.getInt(); //ou message.getFloat(); ou atoi(message.data); } } } //------------Gestion de l'affichage OLED--------------- void updateDisplay() { oled.set1X(); //ligne Message oled.setCursor(2, 0); printStatCom () ; oled.print(hour()); printDigits(minute()); // printStatDay () ; // affiche jour de la semaine //oled.print(day()); oled.set2X(); //ligne Heures oled.setCursor(37,1); oled.print(valPAPP); oled.print("va "); // oled.print(hour()); // printDigits(minute()); //printDigits(second()); oled.set1X(); // ligne jour mois Année / day month year oled.setCursor(35,3); oled.print(day()); printDigitsDay(month()); printDigitsDay(year()); } //-------- Day displaying------- void printDigitsDay(int digitday) { //function for Day displaying "0" and separator "/" for day/month/year values oled.print("/"); if(digitday < 10) oled.print('0'); oled.print(digitday); } //-------- Time displaying------- void printDigits(int digits) { //function for Time displaying "0" and separator ":" for hour:minute:sec values oled.print(":"); if(digits < 10) oled.print('0'); oled.print(digits); } //-------- state Com ------- void printStatCom() { //function for state Com oled.invertDisplay(!(stateCom)); // inverse N/B Oled sur erreur Com if(stateCom == true) { oled.print("com "); } //com yes if(stateCom == false){ oled.print("Error"); } //com no oled.print(" "); } //------ conversion date en texte (fonction weekday) et statu Com Controller ----------- /* void printStatDay () { //function for display Day texte oled.invertDisplay(!(stateCom)); // inverse N/B Oled sur erreur Com if(stateCom == true) { oled.print("com "); } //com okai if(stateCom == false){ oled.print("Error"); } //com okai // oled.print(stateCom); oled.print(" "); if(weekday() == 1) { oled.print("dimanche"); } //Sunday if(weekday() == 2) { oled.print("lundi"); } //Monday if(weekday() == 3) { oled.print("mardi"); } //Tuesday if(weekday() == 4) { oled.print("mercredi"); } //Wednesday if(weekday() == 5) { oled.print("jeudi"); } //Thursday if(weekday() == 6) { oled.print("vendredi"); } //Friday if(weekday() == 7) { oled.print("samedi"); } //Saturday oled.print(" "); oled.print(day()); } */ //-------------------FIN PGM --------------------------