// ********************************************************************************** // Arduino Teleinfo sample, Check and return Teleinfo Stats // This sketch works as is only for Denky D4 board, need to be adapted for other // ********************************************************************************** // Creative Commons Attrib Share-Alike License // You are free to use/extend this library but please abide with the CC-BY-SA license: // http://creativecommons.org/licenses/by-sa/4.0/ // // for detailled explanation of this library see dedicated article // https://hallard.me/libteleinfo/ // // For any explanation about teleinfo or use, see my blog // https://hallard.me/category/tinfo // // see dedicated article here https://hallard.me/demystifier-la-teleinfo/ // // Written by Charles-Henri Hallard (https://hallard.me) // // History : V1.00 2023-01-21 - First release // // All text above must be included in any redistribution. // // ********************************************************************************** #include #include #include #include #include #include #include const char* ssid = "Livebox-37cc"; const char* pass = "8A6060920A8A86896F770F2C47"; WebServer server(80); #define SERIAL_DEBUG Serial #define SERIAL_TIC Serial1 #define PUSH_BUTTON 15 //0 // Teleinfo RXD pin is connected to ESP32-PICO-V3-02 GPIO8 #define TIC_RX_PIN 16 //8 // Default mode, can be switched back and forth // with Denky D4 push button _Mode_e tinfo_mode = TINFO_MODE_HISTORIQUE; TInfo tinfo; // Teleinfo object // Uptime timer boolean tick1sec=0;// one for interrupt, don't mess with unsigned long uptime=0; // save value we can use in sketch even if we're interrupted // Count total frames uint32_t total_frames = 0; /* * Login page */ const char* loginIndex = "
" "" "" "" "
" "
" "" "" "" "" "" "
" "
" "" "" "" "
" "
" "" "" "" "" "
" "
ESP32 Login Page
" "
" "
Username:
Password:
" "
" ""; /* ====================================================================== Function: ShowStats Purpose : display teleinfo stats Input : - Output : - Comments: - ====================================================================== */ void ShowStats() { SERIAL_DEBUG.println(F("\r\n======= Stats =======")); SERIAL_DEBUG.printf_P(PSTR("Total Frames : %d\r\n"), total_frames); SERIAL_DEBUG.printf_P(PSTR("Interrupts : %d\r\n"), tinfo.getFrameInterruptedCount()); SERIAL_DEBUG.printf_P(PSTR("Checksum Err : %d\r\n"), tinfo.getChecksumErrorCount()); SERIAL_DEBUG.printf_P(PSTR("Size Err : %d\r\n"), tinfo.getFrameSizeErrorCount()); SERIAL_DEBUG.printf_P(PSTR("Format Err : %d\r\n"), tinfo.getFrameFormatErrorCount()); SERIAL_DEBUG.println( F("=====================")); } /* ====================================================================== Function: NewFrame Purpose : callback when we received a complete teleinfo frame Input : linked list pointer on the concerned data Output : - Comments: - ====================================================================== */ void NewFrame(ValueList * me) { total_frames++; // Display stat info on each 10 frames if (total_frames % 10 == 0) { ShowStats(); } } /* ====================================================================== Function: initSerial Purpose : Configure (or reconfigure Serial Port) Input : - Output : - Comments: - ====================================================================== */ void initSerial() { // Cleanup SERIAL_TIC.flush(); SERIAL_TIC.end(); // Configure Teleinfo SERIAL_DEBUG.printf_P(PSTR("TIC RX=GPIO%d Mode:"), TIC_RX_PIN); SERIAL_TIC.begin(tinfo_mode == TINFO_MODE_HISTORIQUE ? 1200 : 9600, SERIAL_7E1, TIC_RX_PIN); if ( tinfo_mode == TINFO_MODE_HISTORIQUE ) { SERIAL_DEBUG.println(F("Historique")); } else { SERIAL_DEBUG.println(F("Standard")); } } /* ====================================================================== Function: setup Purpose : Setup I/O and other one time startup stuff Input : - Output : - Comments: - ====================================================================== */ void setup() { // Serial, pour le debug SERIAL_DEBUG.begin(115200); SERIAL_DEBUG.println(F("\r\n\r\n")); SERIAL_DEBUG.println(F("=====================================")); SERIAL_DEBUG.println(F(" Teleinfo stats ")); SERIAL_DEBUG.println(F("=====================================")); SERIAL_DEBUG.println(F(" You can change teleinfo mode from")); SERIAL_DEBUG.println(F("Historique to Standard with B0 button")); // Button pinMode(PUSH_BUTTON, INPUT_PULLUP); // Init Serial Port initSerial(); // Init teleinfo tinfo.init(tinfo_mode); // Attacher les callback dont nous avons besoin tinfo.attachNewFrame(NewFrame); WiFi.mode(WIFI_STA); WiFi.begin(ssid, pass); while (WiFi.waitForConnectResult() != WL_CONNECTED) { Serial.println("Connection Failed! Rebooting..."); delay(5000); ESP.restart(); } // Définissez les gestionnaires pour les différentes URL // server.on("/", HTTP_GET, handleRoot); // server.on("/getData", HTTP_GET, handleData); server.on("/", HTTP_GET, []() { server.sendHeader("Connection", "close"); server.send(200, "text/html", loginIndex); }); // Démarrer le serveur server.begin(); Serial.println("Serveur Web démarré"); // Port defaults to 8266 ArduinoOTA.setPort(8266); // Hostname defaults to esp8266-[ChipID] // ArduinoOTA.setHostname("myesp8266"); // No authentication by default // ArduinoOTA.setPassword("admin"); // Password can be set with it's md5 value as well // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3 // ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3"); ArduinoOTA.onStart([]() { String type; if (ArduinoOTA.getCommand() == U_FLASH) { type = "sketch"; } else { // U_FS type = "filesystem"; } // NOTE: if updating FS this would be the place to unmount FS using FS.end() Serial.println("Start updating " + type); }); ArduinoOTA.onEnd([]() { Serial.println("\nEnd"); }); ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { Serial.printf("Progress: %u%%\r", (progress / (total / 100))); }); ArduinoOTA.onError([](ota_error_t error) { Serial.printf("Error[%u]: ", error); if (error == OTA_AUTH_ERROR) { Serial.println("Auth Failed"); } else if (error == OTA_BEGIN_ERROR) { Serial.println("Begin Failed"); } else if (error == OTA_CONNECT_ERROR) { Serial.println("Connect Failed"); } else if (error == OTA_RECEIVE_ERROR) { Serial.println("Receive Failed"); } else if (error == OTA_END_ERROR) { Serial.println("End Failed"); } }); ArduinoOTA.begin(); Serial.println("Ready"); Serial.print("IP address: "); Serial.println(WiFi.localIP()); } /* ====================================================================== Function: loop Purpose : infinite loop main code Input : - Output : - Comments: - ====================================================================== */ void loop() { ArduinoOTA.handle(); server.handleClient(); //SERIAL_DEBUG.println("In loop"); static char c; static unsigned long previousMillis = 0; static uint8_t buttonState = 0; static unsigned long lastDebounceTime = 0; _State_e state; unsigned long currentMillis = millis(); // Button to switch mode uint8_t button = digitalRead(PUSH_BUTTON); // New Press if ( button==LOW && buttonState==0) { buttonState = 1; lastDebounceTime = millis(); // Pressed enought (debounced) } else if ( buttonState==1 && button==LOW && (millis()-lastDebounceTime)>50 ) { buttonState = 2; // Release (no need debouce here) } else if ( buttonState==2 && button==HIGH ) { // Invert mode if ( tinfo_mode == TINFO_MODE_HISTORIQUE ) { tinfo_mode = TINFO_MODE_STANDARD; } else { tinfo_mode = TINFO_MODE_HISTORIQUE; } // Init Serial Port initSerial(); // Init teleinfo tinfo.init(tinfo_mode); lastDebounceTime = millis(); buttonState = 0; } // Avons nous recu un ticker de seconde? if (tick1sec) { tick1sec = false; uptime++; } // On a reçu un caractère ? if ( SERIAL_TIC.available() ) { // Le lire c = SERIAL_TIC.read(); // Gérer state = tinfo.process(c); // L'affcher dans la console if (c==TINFO_STX) { SERIAL_DEBUG.print(""); } else if (c==TINFO_ETX) { SERIAL_DEBUG.print(""); } else if (c==TINFO_HT) { SERIAL_DEBUG.print(""); } else if (c==TINFO_EOT) { SERIAL_DEBUG.print(""); } else { // Display only when receiving state OK if (state == TINFO_READY) { SERIAL_DEBUG.print(c); } } } if (currentMillis - previousMillis > 1000 ) { // save the last time previousMillis = currentMillis; tick1sec = true; } } /* ====================================================================== Function: sendJSON Purpose : dump teleinfo values on serial Input : linked list pointer on the concerned data true to dump all values, false for only modified ones Output : - Comments: - ====================================================================== */ void sendJSON(ValueList * me, boolean all) { bool firstdata = true; // Got at least one ? if (me) { // Json start Serial.print(F("{")); if (all) { Serial.print(F("\"_UPTIME\":")); Serial.print(uptime, DEC); firstdata = false; } // Loop thru the node while (me->next) { // go to next node me = me->next; // uniquement sur les nouvelles valeurs ou celles modifiées // sauf si explicitement demandé toutes if ( all || ( me->flags & (TINFO_FLAGS_UPDATED | TINFO_FLAGS_ADDED) ) ) { // First elemement, no comma if (firstdata) firstdata = false; else Serial.print(F(", ")) ; Serial.print(F("\"")) ; Serial.print(me->name) ; Serial.print(F("\":")) ; // we have at least something ? if (me->value && strlen(me->value)) { boolean isNumber = true; uint8_t c; char * p = me->value; // check if value is number while (*p && isNumber) { if ( *p < '0' || *p > '9' ) isNumber = false; p++; } // this will add "" on not number values if (!isNumber) { Serial.print(F("\"")) ; Serial.print(me->value) ; Serial.print(F("\"")) ; } // this will remove leading zero on numbers else Serial.print(atol(me->value)); } } } // Json end Serial.println(F("}")) ; } }