diff --git a/tasmota/xnrg_15_teleinfo.ino b/tasmota/xnrg_15_teleinfo.ino new file mode 100644 index 000000000..4ea6c06b8 --- /dev/null +++ b/tasmota/xnrg_15_teleinfo.ino @@ -0,0 +1,197 @@ +/* + xnrg_15_Teleinfo.ino - Teleinfo support for Tasmota + + Copyright (C) 2020 Charles-Henri Hallard + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef USE_ENERGY_SENSOR +#ifdef USE_TELEINFO +/*********************************************************************************************\ + * Teleinfo : French energy provider metering telemety data + * Source: http://hallard.me/category/tinfo/ + * + * Hardware Serial will be selected if GPIO1 = [TELEINFO_RX] +\*********************************************************************************************/ + +#define XNRG_15 15 + +#include "LibTeleinfo.h" +#include + +#define TINFO_READ_TIMEOUT 400 // us; enough for 6 bytes@9600bps + +TInfo tinfo; // Teleinfo object +TasmotaSerial *TInfoSerial = nullptr; +bool tinfo_found = false; + +/*********************************************************************************************/ + +/* ====================================================================== +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) +{ + // n = phase number 1 to 3 + if (phase == 0) + phase = 1; + + AddLog_P2(LOG_LEVEL_INFO, PSTR("ADPS on phase %d"), phase); +} + +/* ====================================================================== +Function: DataCallback +Purpose : callback when we detected new or modified data received +Input : linked list pointer on the concerned data + current flags value +Output : - +Comments: - +====================================================================== */ +void DataCallback(struct _ValueList * me, uint8_t flags) +{ + char c = ' '; + + if (flags & TINFO_FLAGS_ADDED) { c = '#'; } + if (flags & TINFO_FLAGS_UPDATED) { c = '*'; } + + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TIC: %c %s=%s"),c , me->name, me->value); +} + +void TInfoDrvInit(void) { + if (PinUsed(GPIO_TELEINFO_RX)) { + energy_flg = XNRG_15; + } +} + +void TInfoInit(void) +{ + #ifdef USE_TELEINFO_STANDARD + #define TINFO_SPEED 9600 + #else + #define TINFO_SPEED 1200 + #endif + + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TIC: inferface speed %d bps"),TINFO_SPEED); + + tinfo_found = false; + if (PinUsed(GPIO_TELEINFO_RX)) + { + AddLog_P2(LOG_LEVEL_INFO, PSTR("TIC: enable receive on GPIO%d"), GPIO_TELEINFO_RX); + // Enable Teleinfo + if (PinUsed(GPIO_TELEINFO_ENABLE)) + { + pinMode(GPIO_TELEINFO_ENABLE, OUTPUT); + digitalWrite(GPIO_TELEINFO_ENABLE, HIGH); + AddLog_P2(LOG_LEVEL_INFO, PSTR("TIC: enable on GPIO%d"), GPIO_TELEINFO_ENABLE); + } + else + { + AddLog_P2(LOG_LEVEL_INFO, PSTR("TIC: always enabled")); + } + + TInfoSerial = new TasmotaSerial(Pin(GPIO_TELEINFO_RX), -1, 1); + // pinMode(GPIO_TELEINFO_RX, INPUT_PULLUP); + + if (TInfoSerial->begin(TINFO_SPEED, SERIAL_7E1)) + { + if (TInfoSerial->hardwareSerial()) + ClaimSerial(); + TInfoSerial->setTimeout(TINFO_READ_TIMEOUT); + + // Init teleinfo + tinfo.init(); + + // Attach needed callbacks + tinfo.attachADPS(ADPSCallback); + tinfo.attachData(DataCallback); + + tinfo_found = true; + AddLog_P2(LOG_LEVEL_INFO, PSTR("TIC: Ready")); + } + } +} + +void TInfoEvery250ms(void) +{ + char c; + if (!tinfo_found) + return; + + AddLog_P2(LOG_LEVEL_INFO, PSTR("TIC: received %d chars"), TInfoSerial->available()); + + // We received some data? + while (TInfoSerial->available()>8) + { + // get char + c = TInfoSerial->read(); + // data processing + tinfo.process(c); + } +} + +void TInfoShow(bool json) +{ + // TBD + if (json) + { +#ifdef USE_WEBSERVER + } + else + { +#endif // USE_WEBSERVER + } +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xnrg15(uint8_t function) +{ + + switch (function) + { + case FUNC_EVERY_250_MSECOND: + if (uptime > 4) { TInfoEvery250ms(); } + break; + case FUNC_JSON_APPEND: + TInfoShow(1); + break; +#ifdef USE_WEBSERVER + case FUNC_WEB_SENSOR: + TInfoShow(0); + break; +#endif // USE_WEBSERVER + case FUNC_INIT: + TInfoInit(); + break; + case FUNC_PRE_INIT: + TInfoDrvInit(); + break; + } + return false; +} + +#endif // USE_TELEINFO +#endif // USE_ENERGY_SENSOR