diff --git a/RELEASENOTES.md b/RELEASENOTES.md index fdac7edde..ab01ddaa4 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -52,7 +52,7 @@ The following binary downloads have been compiled with ESP8266/Arduino library c ## Changelog -### Version 8.3.1.2 +### Version 8.3.1.3 - Change IRremoteESP8266 library updated to v2.7.7 - Change Adafruit_SGP30 library from v1.0.3 to v1.2.0 (#8519) @@ -76,3 +76,4 @@ The following binary downloads have been compiled with ESP8266/Arduino library c - Add support for up to two BH1750 sensors controlled by commands ``BH1750Resolution`` and ``BH1750MTime`` (#8139) - Add support for up to eight MCP9808 temperature sensors by device111 (#8594) - Add support for BL0940 energy monitor as used in Blitzwolf BW-SHP10 (#8175) +- Add initial support for Telegram bot (#8619) diff --git a/tasmota/CHANGELOG.md b/tasmota/CHANGELOG.md index 4f7d3132b..9033a2bba 100644 --- a/tasmota/CHANGELOG.md +++ b/tasmota/CHANGELOG.md @@ -1,5 +1,9 @@ ## Unreleased (development) +### 8.3.1.3 20200611 + +- Add initial support for Telegram bot (#8619) + ### 8.3.1.2 20200522 - Change Energy JSON Total field from ``"Total":[33.736,11.717,16.978]`` to ``"Total":33.736,"TotalTariff":[11.717,16.978]`` diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index 4a75b4b98..ea2e6eefe 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -367,6 +367,11 @@ // Full documentation here: https://github.com/arendst/Tasmota/wiki/AWS-IoT // #define USE_4K_RSA // Support 4096 bits certificates, instead of 2048 +// -- Telegram Protocol --------------------------- +//#define USE_TELEGRAM // Support for Telegram protocol (+49k code, +7.0k mem and +4.8k additional during connection handshake) + #define USE_TELEGRAM_FINGERPRINT "\xB2\x72\x47\xA6\x69\x8C\x3C\x69\xF9\x58\x6C\xF3\x60\x02\xFB\x83\xFA\x8B\x1F\x23" // Telegram api.telegram.org TLS public key fingerpring +// #define USE_MQTT_TLS_CA_CERT // Use certificate instead of fingerprint + // -- KNX IP Protocol ----------------------------- //#define USE_KNX // Enable KNX IP Protocol Support (+9.4k code, +3k7 mem) #define USE_KNX_WEB_MENU // Enable KNX WEB MENU (+8.3k code, +144 mem) diff --git a/tasmota/support_features.ino b/tasmota/support_features.ino index 20bb9acf3..04de532d6 100644 --- a/tasmota/support_features.ino +++ b/tasmota/support_features.ino @@ -575,7 +575,9 @@ void GetFeatures(void) #ifdef USE_BL0940 feature6 |= 0x00004000; // xnrg_14_bl0940.ino #endif -// feature6 |= 0x00008000; +#ifdef USE_TELEGRAM + feature6 |= 0x00008000; // xdrv_40_telegram.ino +#endif // feature6 |= 0x00010000; // feature6 |= 0x00020000; diff --git a/tasmota/tasmota.h b/tasmota/tasmota.h index c3913e8a1..49347f1f8 100644 --- a/tasmota/tasmota.h +++ b/tasmota/tasmota.h @@ -293,7 +293,7 @@ enum SettingsTextIndex { SET_OTAURL, SET_TEMPLATE_NAME, SET_DEV_GROUP_NAME1, SET_DEV_GROUP_NAME2, SET_DEV_GROUP_NAME3, SET_DEV_GROUP_NAME4, SET_DEVICENAME, - SET_TELEGRAMTOKEN, + SET_TELEGRAM_TOKEN, SET_TELEGRAM_CHATID, SET_MAX }; enum DevGroupMessageType { DGR_MSGTYP_FULL_STATUS, DGR_MSGTYP_PARTIAL_UPDATE, DGR_MSGTYP_UPDATE, DGR_MSGTYP_UPDATE_MORE_TO_COME, DGR_MSGTYP_UPDATE_DIRECT, DGR_MSGTYPE_UPDATE_COMMAND }; @@ -321,9 +321,10 @@ enum DevGroupShareItem { DGR_SHARE_POWER = 1, DGR_SHARE_LIGHT_BRI = 2, DGR_SHARE enum CommandSource { SRC_IGNORE, SRC_MQTT, SRC_RESTART, SRC_BUTTON, SRC_SWITCH, SRC_BACKLOG, SRC_SERIAL, SRC_WEBGUI, SRC_WEBCOMMAND, SRC_WEBCONSOLE, SRC_PULSETIMER, SRC_TIMER, SRC_RULE, SRC_MAXPOWER, SRC_MAXENERGY, SRC_OVERTEMP, SRC_LIGHT, SRC_KNX, SRC_DISPLAY, SRC_WEMO, SRC_HUE, SRC_RETRY, SRC_REMOTE, SRC_SHUTTER, - SRC_THERMOSTAT, SRC_MAX }; + SRC_THERMOSTAT, SRC_CHAT, SRC_MAX }; const char kCommandSource[] PROGMEM = "I|MQTT|Restart|Button|Switch|Backlog|Serial|WebGui|WebCommand|WebConsole|PulseTimer|" - "Timer|Rule|MaxPower|MaxEnergy|Overtemp|Light|Knx|Display|Wemo|Hue|Retry|Remote|Shutter|Thermostat"; + "Timer|Rule|MaxPower|MaxEnergy|Overtemp|Light|Knx|Display|Wemo|Hue|Retry|Remote|Shutter|" + "Thermostat|Chat"; const uint8_t kDefaultRfCode[9] PROGMEM = { 0x21, 0x16, 0x01, 0x0E, 0x03, 0x48, 0x2E, 0x1A, 0x00 }; @@ -344,10 +345,10 @@ const SerConfu8 kTasmotaSerialConfig[] PROGMEM = { SERIAL_5O2, SERIAL_6O2, SERIAL_7O2, SERIAL_8O2 }; -enum TuyaSupportedFunctions { TUYA_MCU_FUNC_NONE, TUYA_MCU_FUNC_SWT1 = 1, TUYA_MCU_FUNC_SWT2, TUYA_MCU_FUNC_SWT3, TUYA_MCU_FUNC_SWT4, - TUYA_MCU_FUNC_REL1 = 11, TUYA_MCU_FUNC_REL2, TUYA_MCU_FUNC_REL3, TUYA_MCU_FUNC_REL4, TUYA_MCU_FUNC_REL5, +enum TuyaSupportedFunctions { TUYA_MCU_FUNC_NONE, TUYA_MCU_FUNC_SWT1 = 1, TUYA_MCU_FUNC_SWT2, TUYA_MCU_FUNC_SWT3, TUYA_MCU_FUNC_SWT4, + TUYA_MCU_FUNC_REL1 = 11, TUYA_MCU_FUNC_REL2, TUYA_MCU_FUNC_REL3, TUYA_MCU_FUNC_REL4, TUYA_MCU_FUNC_REL5, TUYA_MCU_FUNC_REL6, TUYA_MCU_FUNC_REL7, TUYA_MCU_FUNC_REL8, TUYA_MCU_FUNC_DIMMER = 21, TUYA_MCU_FUNC_POWER = 31, - TUYA_MCU_FUNC_CURRENT, TUYA_MCU_FUNC_VOLTAGE, TUYA_MCU_FUNC_BATTERY_STATE, TUYA_MCU_FUNC_BATTERY_PERCENTAGE, + TUYA_MCU_FUNC_CURRENT, TUYA_MCU_FUNC_VOLTAGE, TUYA_MCU_FUNC_BATTERY_STATE, TUYA_MCU_FUNC_BATTERY_PERCENTAGE, TUYA_MCU_FUNC_REL1_INV = 41, TUYA_MCU_FUNC_REL2_INV, TUYA_MCU_FUNC_REL3_INV, TUYA_MCU_FUNC_REL4_INV, TUYA_MCU_FUNC_REL5_INV, TUYA_MCU_FUNC_REL6_INV, TUYA_MCU_FUNC_REL7_INV, TUYA_MCU_FUNC_REL8_INV, TUYA_MCU_FUNC_LOWPOWER_MODE = 51, TUYA_MCU_FUNC_LAST = 255 }; diff --git a/tasmota/tasmota_version.h b/tasmota/tasmota_version.h index 1b21293b2..f22a0288b 100644 --- a/tasmota/tasmota_version.h +++ b/tasmota/tasmota_version.h @@ -20,7 +20,7 @@ #ifndef _TASMOTA_VERSION_H_ #define _TASMOTA_VERSION_H_ -const uint32_t VERSION = 0x08030102; +const uint32_t VERSION = 0x08030103; // Lowest compatible version const uint32_t VERSION_COMPATIBLE = 0x07010006; diff --git a/tasmota/xdrv_40_telegram.ino b/tasmota/xdrv_40_telegram.ino new file mode 100644 index 000000000..a2ec2e49f --- /dev/null +++ b/tasmota/xdrv_40_telegram.ino @@ -0,0 +1,479 @@ +/* + xdrv_40_telegram.ino - telegram for Tasmota + + Copyright (C) 2020 Theo Arends + + 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_TELEGRAM +/*********************************************************************************************\ + * Telegram bot + * + * Supported commands: + * TGToken - Add your BotFather created bot token (default none) + * TGChatId - Add your BotFather created bot chat id (default none) + * TGPoll - Telegram receive poll time (default 10 seconds) + * TGState 0 - Disable telegram sending (default) + * TGState 1 - Enable telegram sending + * TGState 2 - Disable telegram listener (default) + * TGState 3 - Enable telegram listener + * TGState 4 - Disable telegram response echo (default) + * TGState 5 - Enable telegram response echo + * TGSend - If telegram sending is enabled AND a chat id is present then send data + * + * Tested with defines + * #define USE_TELEGRAM // Support for Telegram protocol + * #define USE_TELEGRAM_FINGERPRINT "\xB2\x72\x47\xA6\x69\x8C\x3C\x69\xF9\x58\x6C\xF3\x60\x02\xFB\x83\xFA\x8B\x1F\x23" // Telegram api.telegram.org TLS public key fingerpring +\*********************************************************************************************/ + +#define XDRV_40 40 + +#define TELEGRAM_SEND_RETRY 4 // Retries +#define TELEGRAM_LOOP_WAIT 10 // Seconds + +#ifdef USE_MQTT_TLS_CA_CERT + static const uint32_t tls_rx_size = 2048; // since Telegram CA is bigger than 1024 bytes, we need to increase rx buffer + static const uint32_t tls_tx_size = 1024; +#else + static const uint32_t tls_rx_size = 1024; + static const uint32_t tls_tx_size = 1024; +#endif + +#include "WiFiClientSecureLightBearSSL.h" +BearSSL::WiFiClientSecure_light *telegramClient = nullptr; + +static const uint8_t Telegram_Fingerprint[] PROGMEM = USE_TELEGRAM_FINGERPRINT; + +struct { + String message[3][6]; // amount of messages read per time (update_id, name_id, name, lastname, chat_id, text) + uint8_t state = 0; + uint8_t index = 0; + uint8_t retry = 0; + uint8_t poll = TELEGRAM_LOOP_WAIT; + uint8_t wait = 0; + bool send_enable = false; + bool recv_enable = false; + bool echo_enable = false; + bool recv_busy = false; +} Telegram; + +bool TelegramInit(void) { + bool init_done = false; + if (strlen(SettingsText(SET_TELEGRAM_TOKEN))) { + if (!telegramClient) { + telegramClient = new BearSSL::WiFiClientSecure_light(tls_rx_size, tls_tx_size); +#ifdef USE_MQTT_TLS_CA_CERT + telegramClient->setTrustAnchor(&GoDaddyCAG2_TA); +#else + telegramClient->setPubKeyFingerprint(Telegram_Fingerprint, Telegram_Fingerprint, false); // check server fingerprint +#endif + + Telegram.message[0][0]="0"; // Number of received messages + Telegram.message[1][0]=""; + Telegram.message[0][1]="0"; // Code of last read Message + + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TLG: Started")); + } + + init_done = true; + } + return init_done; +} + +/************************************************************************************************** + * function to achieve connection to api.telegram.org and send command to telegram * + * (Argument to pass: URL to address to Telegram) * + **************************************************************************************************/ +String TelegramConnectToTelegram(String command) { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TLG: Cmnd %s"), command.c_str()); + + if (!TelegramInit()) { return ""; } + + String response = ""; + uint32_t tls_connect_time = millis(); + + if (telegramClient->connect("api.telegram.org", 443)) { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TLG: Connected in %d ms, max ThunkStack used %d"), + millis() - tls_connect_time, telegramClient->getMaxThunkStackUse()); + + telegramClient->println("GET /"+command); + + String a = ""; + char c; + int ch_count=0; + uint32_t now = millis(); + bool avail = false; + while (millis() -now < 1500) { + while (telegramClient->available()) { + char c = telegramClient->read(); + if (ch_count < 700) { + response = response + c; + ch_count++; + } + avail = true; + } + if (avail) { + break; + } + } + + telegramClient->stop(); + } + + return response; +} + +/*************************************************************** + * GetUpdates - function to receive all messages from telegram * + * (Argument to pass: the last+1 message to read) * + ***************************************************************/ +void TelegramGetUpdates(String offset) { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TLG: getUpdates")); + + if (!TelegramInit()) { return; } + + String _token = SettingsText(SET_TELEGRAM_TOKEN); + String command = "bot" + _token + "/getUpdates?offset=" + offset; + String response = TelegramConnectToTelegram(command); //recieve reply from telegram.org + + // {"ok":true,"result":[]} + // or + // {"ok":true,"result":[ + // {"update_id":973125394, + // "message":{"message_id":25, + // "from":{"id":139920293,"is_bot":false,"first_name":"Theo","last_name":"Arends","username":"tjatja","language_code":"nl"}, + // "chat":{"id":139920293,"first_name":"Theo","last_name":"Arends","username":"tjatja","type":"private"}, + // "date":1591877503, + // "text":"M1" + // } + // }, + // {"update_id":973125395, + // "message":{"message_id":26, + // "from":{"id":139920293,"is_bot":false,"first_name":"Theo","last_name":"Arends","username":"tjatja","language_code":"nl"}, + // "chat":{"id":139920293,"first_name":"Theo","last_name":"Arends","username":"tjatja","type":"private"}, + // "date":1591877508, + // "text":"M2" + // } + // } + // ]} + // or + // {"ok":true,"result":[ + // {"update_id":973125396, + // "message":{"message_id":29, + // "from":{"id":139920293,"is_bot":false,"first_name":"Theo","last_name":"Arends","username":"tjatja","language_code":"nl"}, + // "chat":{"id":139920293,"first_name":"Theo","last_name":"Arends","username":"tjatja","type":"private"}, + // "date":1591879753, + // "text":"/power toggle", + // "entities":[{"offset":0,"length":6,"type":"bot_command"}] + // } + // } + // ]} + + AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("TLG: Response %s"), response.c_str()); + + // parsing of reply from Telegram into separate received messages + int i = 0; //messages received counter + if (response != "") { + + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TLG: Sent Update request messages up to %s"), offset.c_str()); + + String a = ""; + int ch_count = 0; + String c; + for (uint32_t n = 1; n < response.length() +1; n++) { //Search for each message start + ch_count++; + c = response.substring(n -1, n); + a = a + c; + if (ch_count > 8) { + if (a.substring(ch_count -9) == "update_id") { + if (i > 1) { break; } + Telegram.message[i][0] = a.substring(0, ch_count -11); + a = a.substring(ch_count-11); + i++; + ch_count = 11; + } + } + } + if (1 == i) { + Telegram.message[i][0] = a.substring(0, ch_count); //Assign of parsed message into message matrix if only 1 message) + } + if (i > 1) { i = i -1; } + } + //check result of parsing process + if (response == "") { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TLG: Failed to update")); + return; + } + if (0 == i) { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TLG: No new messages")); + Telegram.message[0][0] = "0"; + } else { + Telegram.message[0][0] = String(i); //returns how many messages are in the array + for (int b = 1; b < i+1; b++) { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TLG: Msg %d %s"), b, Telegram.message[b][0].c_str()); + } + + TelegramAnalizeMessage(); + } +} + +void TelegramAnalizeMessage(void) { + for (uint32_t i = 1; i < Telegram.message[0][0].toInt() +1; i++) { + Telegram.message[i][5] = ""; + + DynamicJsonBuffer jsonBuffer; + JsonObject &root = jsonBuffer.parseObject(Telegram.message[i][0]); + if (root.success()) { + Telegram.message[i][0] = root["update_id"].as(); + Telegram.message[i][1] = root["message"]["from"]["id"].as(); + Telegram.message[i][2] = root["message"]["from"]["first_name"].as(); + Telegram.message[i][3] = root["message"]["from"]["last_name"].as(); + Telegram.message[i][4] = root["message"]["chat"]["id"].as(); + Telegram.message[i][5] = root["message"]["text"].as(); + } + + int id = Telegram.message[Telegram.message[0][0].toInt()][0].toInt() +1; + Telegram.message[0][1] = id; // Write id of last read message + + for (int j = 0; j < 6; j++) { + AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("TLG: Parsed%d \"%s\""), j, Telegram.message[i][j].c_str()); + } + } +} + +bool TelegramSendMessage(String chat_id, String text) { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TLG: sendMessage")); + + if (!TelegramInit()) { return false; } + + bool sent = false; + if (text != "") { + String _token = SettingsText(SET_TELEGRAM_TOKEN); + String command = "bot" + _token + "/sendMessage?chat_id=" + chat_id + "&text=" + text; + String response = TelegramConnectToTelegram(command); + + AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("TLG: Response %s"), response.c_str()); + + if (response.startsWith("{\"ok\":true")) { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TLG: Message sent")); + sent = true; + } + + } + + return sent; +} + +/* +void TelegramSendGetMe(void) { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TLG: getMe")); + + if (!TelegramInit()) { return; } + + String _token = SettingsText(SET_TELEGRAM_TOKEN); + String command = "bot" + _token + "/getMe"; + String response = TelegramConnectToTelegram(command); + + // {"ok":true,"result":{"id":1179906608,"is_bot":true,"first_name":"Tasmota","username":"tasmota_bot","can_join_groups":true,"can_read_all_group_messages":false,"supports_inline_queries":false}} + + AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("TLG: Response %s"), response.c_str()); +} +*/ + +String TelegramExecuteCommand(const char *svalue) { + String response = ""; + + uint32_t curridx = web_log_index; + ExecuteCommand(svalue, SRC_CHAT); + if (web_log_index != curridx) { + uint32_t counter = curridx; + response = F("{"); + bool cflg = false; + do { + char* tmp; + size_t len; + GetLog(counter, &tmp, &len); + if (len) { + // [14:49:36 MQTT: stat/wemos5/RESULT = {"POWER":"OFF"}] > [{"POWER":"OFF"}] + char* JSON = (char*)memchr(tmp, '{', len); + if (JSON) { // Is it a JSON message (and not only [15:26:08 MQT: stat/wemos5/POWER = O]) + size_t JSONlen = len - (JSON - tmp); + if (JSONlen > sizeof(mqtt_data)) { JSONlen = sizeof(mqtt_data); } + char stemp[JSONlen]; + strlcpy(stemp, JSON +1, JSONlen -2); + if (cflg) { response += F(","); } + response += stemp; + cflg = true; + } + } + counter++; + counter &= 0xFF; + if (!counter) counter++; // Skip 0 as it is not allowed + } while (counter != web_log_index); + response += F("}"); + } else { + response = F("{\"" D_RSLT_WARNING "\":\"" D_ENABLE_WEBLOG_FOR_RESPONSE "\"}"); + } + + return response; +} + +void TelegramLoop(void) { + if (!global_state.wifi_down && (Telegram.recv_enable || Telegram.echo_enable)) { + switch (Telegram.state) { + case 0: + TelegramInit(); + Telegram.state++; + break; + case 1: + TelegramGetUpdates(Telegram.message[0][1]); // launch API GetUpdates up to xxx message + Telegram.index = 1; + Telegram.retry = TELEGRAM_SEND_RETRY; + Telegram.state++; + break; + case 2: + if (Telegram.echo_enable) { + if (Telegram.retry && (Telegram.index < Telegram.message[0][0].toInt() + 1)) { + if (TelegramSendMessage(Telegram.message[Telegram.index][4], Telegram.message[Telegram.index][5])) { + Telegram.index++; + Telegram.retry = TELEGRAM_SEND_RETRY; + } else { + Telegram.retry--; + } + } else { + Telegram.message[0][0] = ""; // All messages have been replied - reset new messages + Telegram.wait = Telegram.poll; + Telegram.state++; + } + } else { + if (Telegram.message[0][0].toInt() && (Telegram.message[Telegram.index][5].length() > 0)) { + String logging = TelegramExecuteCommand(Telegram.message[Telegram.index][5].c_str()); + if (logging.length() > 0) { + TelegramSendMessage(Telegram.message[Telegram.index][4], logging); + } + } + Telegram.message[0][0] = ""; // All messages have been replied - reset new messages + Telegram.wait = Telegram.poll; + Telegram.state++; + } + break; + case 3: + if (Telegram.wait) { + Telegram.wait--; + } else { + Telegram.state = 1; + } + } + } +} + +/*********************************************************************************************\ + * Commands +\*********************************************************************************************/ + +#define D_CMND_TGSTATE "State" +#define D_CMND_TGPOLL "Poll" +#define D_CMND_TGSEND "Send" +#define D_CMND_TGTOKEN "Token" +#define D_CMND_TGCHATID "ChatId" + +const char kTelegramCommands[] PROGMEM = "TG|" // Prefix + D_CMND_TGSTATE "|" D_CMND_TGPOLL "|" D_CMND_TGTOKEN "|" D_CMND_TGCHATID "|" D_CMND_TGSEND; + +void (* const TelegramCommand[])(void) PROGMEM = { + &CmndTgState, &CmndTgPoll, &CmndTgToken, &CmndTgChatId, &CmndTgSend }; + +void CmndTgState(void) { + if (XdrvMailbox.data_len > 0) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6)) { + switch (XdrvMailbox.payload) { + case 0: // Off + case 1: // On + Telegram.send_enable = XdrvMailbox.payload &1; + break; + case 2: // Off + case 3: // On + Telegram.recv_enable = XdrvMailbox.payload &1; + break; + case 4: // Off + case 5: // On + Telegram.echo_enable = XdrvMailbox.payload &1; + break; + } + } + } + snprintf_P (mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":{\"Send\":\"%s\",\"Receive\":\"%s\",\"Echo\":\"%s\"}}"), + XdrvMailbox.command, GetStateText(Telegram.send_enable), GetStateText(Telegram.recv_enable), GetStateText(Telegram.echo_enable)); +} + +void CmndTgPoll(void) { + if ((XdrvMailbox.payload >= 4) && (XdrvMailbox.payload <= 300)) { + Telegram.poll = XdrvMailbox.payload; + if (Telegram.poll < Telegram.wait) { + Telegram.wait = Telegram.poll; + } + } + ResponseCmndNumber(Telegram.poll); +} + +void CmndTgToken(void) { + if (XdrvMailbox.data_len > 0) { + SettingsUpdateText(SET_TELEGRAM_TOKEN, ('"' == XdrvMailbox.data[0]) ? "" : XdrvMailbox.data); + } + ResponseCmndChar(SettingsText(SET_TELEGRAM_TOKEN)); +} + +void CmndTgChatId(void) { + if (XdrvMailbox.data_len > 0) { + SettingsUpdateText(SET_TELEGRAM_CHATID, ('"' == XdrvMailbox.data[0]) ? "" : XdrvMailbox.data); + } + ResponseCmndChar(SettingsText(SET_TELEGRAM_CHATID)); +} + +void CmndTgSend(void) { + if (!Telegram.send_enable || !strlen(SettingsText(SET_TELEGRAM_CHATID))) { + ResponseCmndChar(D_JSON_FAILED); + return; + } + if (XdrvMailbox.data_len > 0) { + String message = XdrvMailbox.data; + String chat_id = SettingsText(SET_TELEGRAM_CHATID); + if (!TelegramSendMessage(chat_id, message)) { + ResponseCmndChar(D_JSON_FAILED); + return; + } + } + ResponseCmndDone(); +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xdrv40(uint8_t function) +{ + bool result = false; + + switch (function) { + case FUNC_EVERY_SECOND: + TelegramLoop(); + break; + case FUNC_COMMAND: + result = DecodeCommand(kTelegramCommands, TelegramCommand); + break; + } + return result; +} +#endif // USE_TELEGRAM diff --git a/tools/decode-status.py b/tools/decode-status.py index 1ce04951e..4228b69df 100755 --- a/tools/decode-status.py +++ b/tools/decode-status.py @@ -205,7 +205,7 @@ a_features = [[ "USE_KEELOQ","USE_HRXL","USE_SONOFF_D1","USE_HDC1080", "USE_IAQ","USE_DISPLAY_SEVENSEG","USE_AS3935","USE_PING", "USE_WINDMETER","USE_OPENTHERM","USE_THERMOSTAT","USE_VEML6075", - "USE_VEML7700","USE_MCP9808","USE_BL0940","", + "USE_VEML7700","USE_MCP9808","USE_BL0940","USE_TELEGRAM", "","","","", "","","","", "","","","", @@ -243,7 +243,7 @@ else: obj = json.load(fp) def StartDecode(): - print ("\n*** decode-status.py v20200607 by Theo Arends and Jacek Ziolkowski ***") + print ("\n*** decode-status.py v20200611 by Theo Arends and Jacek Ziolkowski ***") # print("Decoding\n{}".format(obj))