diff --git a/examples/ESP32/ESP32.ino b/examples/ESP32/ESP32.ino new file mode 100644 index 0000000..29dca88 --- /dev/null +++ b/examples/ESP32/ESP32.ino @@ -0,0 +1,419 @@ +// ********************************************************************************** +// ESP32 Teleinfo basic +// ********************************************************************************** +// Creative Commons Attrib Share-Alike License +// You are free to use/extend this library but please abide with the CC-BY-SA license: +// Attribution-NonCommercial-ShareAlike 4.0 International License +// http://creativecommons.org/licenses/by-nc-sa/4.0/ +// +// For any explanation about teleinfo ou use , see my blog +// http://hallard.me/category/tinfo +// +// This program works with the Wifinfo board +// see schematic here https://github.com/hallard/teleinfo/tree/master/Wifinfo +// +// Written by Charles-Henri Hallard (http://hallard.me) +// +// History : V1.00 2020-06-11 - First release +// +// All text above must be included in any redistribution. +// +// ********************************************************************************** + +#include + +//#define BOARD_EZSBC +//#define BOARD_LOLIN32 +#define BOARD_DENKY32 + +// https://www.tindie.com/products/ddebeer/esp32-dev-board-wifibluetooth-with-ftdi-/ +#if defined (BOARD_EZSBC) +// Set up the rgb led names +#define LED_RED_PIN 16 +#define LED_GRN_PIN 17 +#define LED_BLU_PIN 18 + +#define PUSH_BUTTON 0 + +#define TIC_ENABLE_PIN 27 +#define TIC_RX_PIN 33 +#define TIC_TX_PIN 32 + +// Lolin32 +#elif defined (BOARD_LOLIN32) + +#define PUSH_BUTTON 15 + +#define TIC_ENABLE_PIN 32 +#define TIC_RX_PIN 16 +#define TIC_TX_PIN 17 + +#define RGB_LED_PIN 13 + +// Denky32 +#elif defined (BOARD_DENKY32) + +#define PUSH_BUTTON 0 + +#define TIC_ENABLE_PIN 4 +#define TIC_RX_PIN 33 +//#define TIC_TX_PIN 17 + +#define LORA_TX_PIN 26 +#define LORA_RX_PIN 27 +#define LORA_RESET 14 + +#define RGB_LED_PIN 25 + + +#endif + +#ifdef RGB_LED_PIN +#include + +#define colorSaturation 128 +// three element pixels, in different order and speeds +NeoPixelBus strip(1, RGB_LED_PIN); + +RgbColor red(colorSaturation, 0, 0); +RgbColor green(0, colorSaturation, 0); +RgbColor blue(0, 0, colorSaturation); +RgbColor white(colorSaturation); +RgbColor black(0); + +#endif + + +TInfo tinfo; // Teleinfo object + +// Pour clignotement LED asynchrone +unsigned long blinkLed = 0; +uint8_t blinkDelay= 0; + +// 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 + +// Used to indicate if we need to send all date or just modified ones +boolean fulldata = true; + +//HardwareSerial Serial1(2); // UART1/Serial2 pins 16,17 +//HardwareSerial Serial1(1); // UART1/Serial1 pins 9,10 +//HardwareSerial Serial1(1); // UART1/Serial1 pins 9,10 + +/* ====================================================================== +Function: ADPSCallback +Purpose : called by library when we detected a ADPS on any phased +Input : phase number + 0 for ADPS (monophase) + 1 for ADIR1 triphase + 2 for ADIR2 triphase + 3 for ADIR3 triphase +Output : - +Comments: should have been initialised in the main sketch with a + tinfo.attachADPSCallback(ADPSCallback()) +====================================================================== */ +void ADPSCallback(uint8_t phase) +{ + // Envoyer JSON { "ADPS"; n} + // n = numero de la phase 1 à 3 + if (phase == 0) + phase = 1; + Serial.print(F("{\"ADPS\":")); + Serial.print('0' + phase); + Serial.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) +{ + // Start short led blink + #ifdef LED_RED_PIN + digitalWrite(LED_RED_PIN, LOW); + #endif + #ifdef RGB_LED_PIN + strip.SetPixelColor(0, red); + strip.Show(); + #endif + blinkLed = millis(); + blinkDelay = 50; // 50ms + + // Envoyer les valeurs uniquement si demandé + if (fulldata) + sendJSON(me, true); + + fulldata = false; +} + +/* ====================================================================== +Function: UpdatedFrame +Purpose : callback when we received a complete teleinfo frame +Input : linked list pointer on the concerned data +Output : - +Comments: it's called only if one data in the frame is different than + the previous frame +====================================================================== */ +void UpdatedFrame(ValueList * me) +{ + // Start long led blink + #ifdef LED_BLU_PIN + digitalWrite(LED_BLU_PIN, LOW); + #endif + #ifdef RGB_LED_PIN + strip.SetPixelColor(0, blue); + strip.Show(); + #endif + + blinkLed = millis(); + blinkDelay = 50; // 50ms + + // Envoyer les valeurs + sendJSON(me, fulldata); + fulldata = false; +} + +/* ====================================================================== +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; + 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("}")) ; + } +} + +/* ====================================================================== +Function: setup +Purpose : Setup I/O and other one time startup stuff +Input : - +Output : - +Comments: - +====================================================================== */ +void setup() +{ + // Arduino LED + #ifdef BOARD_EZSBC + pinMode(LED_RED_PIN, OUTPUT); + pinMode(LED_GRN_PIN, OUTPUT); + pinMode(LED_BLU_PIN, OUTPUT); + digitalWrite(LED_RED_PIN, HIGH); + digitalWrite(LED_GRN_PIN, HIGH); + digitalWrite(LED_BLU_PIN, HIGH); + #endif + + // Serial, pour le debug + Serial.begin(115200); + Serial.println(F("\r\n\r\n==============")); + Serial.println(F("Teleinfo")); + + + // Teleinfo enable pin + #ifdef TIC_ENABLE_PIN + pinMode(TIC_ENABLE_PIN, OUTPUT); + digitalWrite(TIC_ENABLE_PIN, HIGH); + Serial.printf_P(PSTR("Enable TIC on GPIO%d\r\n"), TIC_ENABLE_PIN); + #endif + + // Button + #ifdef PUSH_BUTTON + pinMode(PUSH_BUTTON, INPUT_PULLUP); + Serial.printf_P(PSTR("Enable Button on GPIO=%d\r\n"), PUSH_BUTTON); + #endif + + + + // this resets all the neopixels to an off state + #ifdef RGB_LED_PIN + Serial.printf_P(PSTR("Enable WS2812 RGB LED on GPIO=%d\r\n"), RGB_LED_PIN); + strip.Begin(); + strip.SetPixelColor(0, green); + strip.Show(); + blinkLed = millis(); + blinkDelay = 500; // 500ms + #endif + + // Configure Teleinfo Soft serial + // La téléinfo est connectee sur D3 + // ceci permet d'eviter les conflits avec la + // vraie serial lors des uploads + Serial.printf_P(PSTR("TIC RX = GPIO=%d\r\n"), TIC_RX_PIN); + Serial1.begin(1200, SERIAL_7E1, TIC_RX_PIN); + pinMode(TIC_RX_PIN, INPUT_PULLUP); + + // Init teleinfo + tinfo.init(); + + // Attacher les callback dont nous avons besoin + // pour cette demo, ADPS et TRAME modifiée + tinfo.attachADPS(ADPSCallback); + tinfo.attachUpdatedFrame(UpdatedFrame); + tinfo.attachNewFrame(NewFrame); +} + +/* ====================================================================== +Function: loop +Purpose : infinite loop main code +Input : - +Output : - +Comments: - +====================================================================== */ +void loop() +{ + static char c; + static unsigned long previousMillis = 0; + unsigned long currentMillis = millis(); + + // Button to enable TIC +#if defined (PUSH_BUTTON) && defined (TIC_ENABLE_PIN) + static uint8_t enableTIC = HIGH; + static uint8_t buttonState = 0; + static unsigned long lastDebounceTime = 0; + + 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 ) { + if ( enableTIC ) { + digitalWrite(TIC_ENABLE_PIN, LOW); + enableTIC = false; + } else { + digitalWrite(TIC_ENABLE_PIN, HIGH); + enableTIC = true; + } + + Serial.printf_P(PSTR("\r\nEnable TIC=%d\r\n"), enableTIC); + lastDebounceTime = millis(); + buttonState = 0; + } + +#endif + + + // Avons nous recu un ticker de seconde? + if (tick1sec) + { + tick1sec = false; + uptime++; + + // Forcer un envoi de trame complète toutes les minutes + // fulldata sera remis à 0 après l'envoi + if (uptime % 60 == 0) + fulldata = true; + } + + // On a reçu un caractère ? + if ( Serial1.available() ) { + // Le lire + c = Serial1.read(); + + // Gérer + tinfo.process(c); + + // L'affcher dans la console + if (c!=TINFO_STX && c!=TINFO_ETX) { + Serial.print(c); + } + } + + // Verifier si le clignotement LED doit s'arreter + if (blinkLed && ((millis()-blinkLed) >= blinkDelay)) + { + #ifdef BOARD_EZSBC + digitalWrite(LED_RED_PIN, HIGH); + digitalWrite(LED_GRN_PIN, HIGH); + digitalWrite(LED_BLU_PIN, HIGH); + #endif + + #ifdef RGB_LED_PIN + strip.SetPixelColor(0, black); + strip.Show(); + #endif + + blinkLed = 0; + } + + if (currentMillis - previousMillis > 1000 ) { + // save the last time you blinked the LED + previousMillis = currentMillis; + tick1sec = true; + } +} + +