Skip to content

Commit cdc7b76

Browse files
committed
upd
1 parent 28b2198 commit cdc7b76

File tree

6 files changed

+169
-45
lines changed

6 files changed

+169
-45
lines changed

examples/OTA_update/OTA_update.ino

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// пример обновления прошивки из чата
2+
3+
#define WIFI_SSID "login"
4+
#define WIFI_PASS "pass"
5+
#define BOT_TOKEN "2654326546:asjhAsfAsfkllgUsaOuiz_axfkj_AsfkjhB"
6+
#define CHAT_ID "123456789"
7+
8+
#include <FastBot.h>
9+
FastBot bot(BOT_TOKEN);
10+
11+
void setup() {
12+
connectWiFi();
13+
Serial.println("v1.0");
14+
bot.attach(newMsg);
15+
}
16+
17+
// обработчик сообщений
18+
void newMsg(FB_msg& msg) {
19+
// выводим всю информацию о сообщении
20+
Serial.println(msg.toString());
21+
22+
// обновить, если прислали bin файл
23+
if (msg.OTA) bot.update();
24+
25+
// обновить, если файл имеет нужную подпись
26+
//if (msg.OTA && msg.text == "update") bot.update();
27+
28+
// обновить, если прислал известный человек (админ)
29+
//if (msg.OTA && msg.chatID == "123456") bot.update();
30+
}
31+
32+
void loop() {
33+
bot.tick();
34+
}
35+
36+
void connectWiFi() {
37+
delay(2000);
38+
Serial.begin(115200);
39+
Serial.println();
40+
41+
WiFi.begin(WIFI_SSID, WIFI_PASS);
42+
while (WiFi.status() != WL_CONNECTED) {
43+
delay(500);
44+
Serial.print(".");
45+
if (millis() > 15000) ESP.restart();
46+
}
47+
Serial.println("Connected");
48+
}
404 KB
Binary file not shown.

keywords.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ clearServiceMessages KEYWORD2
5353
pinMessage KEYWORD2
5454
unpinMessage KEYWORD2
5555
unpinAll KEYWORD2
56+
update KEYWORD2
5657

5758
timeSynced KEYWORD2
5859
getTime KEYWORD2
@@ -67,6 +68,7 @@ data KEYWORD2
6768
query KEYWORD2
6869
edited KEYWORD2
6970
isBot KEYWORD2
71+
OTA KEYWORD2
7072
unix KEYWORD2
7173
toString KEYWORD2
7274

library.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name=FastBot
2-
version=2.12
2+
version=2.13
33
author=AlexGyver <alex@alexgyver.ru>
44
maintainer=AlexGyver <alex@alexgyver.ru>
55
sentence=Simple library for Telegram bot (messages and menus)

src/FastBot.h

Lines changed: 114 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
- Поддержка Unicode (другие языки + эмодзи) для входящих сообщений
1717
- Встроенный urlencode для исходящих сообщений
1818
- Встроенные часы реального времени с синхронизацией от сервера Telegram
19+
- Возможность OTA обновления прошивки файлом из чата Telegram
1920
2021
AlexGyver, alex@alexgyver.ru
2122
https://alexgyver.ru/
@@ -78,13 +79,14 @@
7879
- usrID и ID переименованы в userID и messageID (с сохранением легаси)
7980
- Окончательно убран старый обработчик входящих сообщений
8081
v2.12: поправлены примеры, исправлен парсинг isBot, переделан механизм защиты от длинных сообщений, переделана инициализация
82+
v2.13: Оптимизация памяти. Добавил OTA обновление
8183
*/
8284

8385
/*
8486
Статусы tick:
8587
0 - ожидание
8688
1 - ОК
87-
2 - Переполнен по ovf
89+
2 - Переполнен
8890
3 - Ошибка телеграм
8991
4 - Ошибка подключения
9092
5 - не задан chat ID
@@ -103,24 +105,26 @@
103105
#define FB_ALERT 1
104106

105107
#include <Arduino.h>
108+
#include <StreamString.h>
109+
#include "utils.h"
110+
106111
#ifdef ESP8266
107112
#include <ESP8266WiFi.h>
108113
#include <ESP8266HTTPClient.h>
114+
#include <ESP8266httpUpdate.h>
109115
#include <WiFiClientSecure.h>
110116
#include <WiFiClientSecureBearSSL.h>
111117
static BearSSL::WiFiClientSecure _FB_client;
112-
static HTTPClient _FB_httpGet, _FB_httpReq;
118+
static HTTPClient _FB_http;
113119
#else
114120
#include <WiFi.h>
115121
#include <HTTPClient.h>
122+
#include <HTTPUpdate.h>
116123
#include <WiFiClientSecure.h>
117124
WiFiClientSecure _FB_client;
118-
static HTTPClient _FB_httpGet;
119-
#define _FB_httpReq _FB_httpGet
125+
static HTTPClient _FB_http;
120126
#endif
121127

122-
#include "utils.h"
123-
124128
// ================================
125129
class FastBot {
126130
public:
@@ -134,7 +138,6 @@ class FastBot {
134138
_prd = period;
135139
setBufferSizes(512, 512);
136140
_FB_client.setInsecure();
137-
//_FB_httpGet.setTimeout(500);
138141
}
139142

140143
// ===================== НАСТРОЙКИ =====================
@@ -188,18 +191,42 @@ class FastBot {
188191
// ручная проверка обновлений
189192
uint8_t tickManual() {
190193
if (!*_callback) return 7;
191-
uint8_t status = 1;
192194
String req;
193195
_addToken(req);
194196
req += F("/getUpdates?limit=");
195-
req += ovfFlag ? 1 : _limit; // берём по 1 сообщению если переполнены
197+
req += ovfFlag ? 1 : _limit; // берём по 1 сообщению если переполнен
196198
req += F("&offset=");
197199
req += ID;
198-
if (_FB_httpGet.begin(_FB_client, req)) {
199-
if (_FB_httpGet.GET() == HTTP_CODE_OK) status = parse(_FB_httpGet.getString(), _FB_httpGet.getSize());
200-
else status = 3;
201-
_FB_httpGet.end();
202-
} else status = 4;
200+
201+
if (!_FB_http.begin(_FB_client, req)) return 4; // ошибка подключения
202+
if (_FB_http.GET() != HTTP_CODE_OK) {
203+
_FB_http.end();
204+
return 3; // ошибка сервера телеграм
205+
}
206+
207+
// была попытка OTA обновления. Обновляемся после ответа серверу!
208+
if (OTAstate >= 0) {
209+
String ota;
210+
if (OTAstate == 0) ota = F("error");
211+
else if (OTAstate == 1) ota = F("no updates");
212+
else if (OTAstate == 2) ota = F("OK");
213+
sendMessage(ota, _otaID);
214+
if (OTAstate == 2) ESP.restart();
215+
OTAstate = -1;
216+
}
217+
218+
int size = _FB_http.getSize();
219+
ovfFlag = size > 25000; // 1 полное сообщение на русском языке или ~5 на английском
220+
uint8_t status = 1; // OK
221+
if (size) { // не пустой ответ?
222+
StreamString sstring;
223+
if (!ovfFlag && sstring.reserve(size + 1)) { // не переполнен и хватает памяти
224+
_FB_http.writeToStream(&sstring); // копируем
225+
_FB_http.end(); // завершаем
226+
return parseMessages(sstring); // парсим
227+
} else status = 2; // переполнение
228+
} else status = 3; // пустой ответ
229+
_FB_http.end();
203230
return status;
204231
}
205232

@@ -360,32 +387,32 @@ class FastBot {
360387

361388
// ответить на callback текстом и true - предупреждением
362389
uint8_t answer() {
363-
if (!_query) return 5;
390+
if (!_query_ptr) return 5;
364391
String req;
365392
_addToken(req);
366393
req += F("/answerCallbackQuery?callback_query_id=");
367-
req += *_query;
368-
_query = nullptr;
394+
req += *_query_ptr;
395+
_query_ptr = nullptr;
369396
return sendRequest(req);
370397
}
371398

372399
uint8_t answer(const String& text, bool alert = false) {
373-
if (!_query) return 5;
400+
if (!_query_ptr) return 5;
374401
#ifndef FB_NO_URLENCODE
375402
String utext;
376403
FB_urlencode(text, utext);
377404
#endif
378405
String req;
379406
_addToken(req);
380407
req += F("/answerCallbackQuery?callback_query_id=");
381-
req += *_query;
408+
req += *_query_ptr;
382409
#ifndef FB_NO_URLENCODE
383410
_addText(req, utext);
384411
#else
385412
_addText(req, text);
386413
#endif
387414
if (alert) req += F("&show_alert=True");
388-
_query = nullptr;
415+
_query_ptr = nullptr;
389416
return sendRequest(req);
390417
}
391418

@@ -603,21 +630,12 @@ class FastBot {
603630
}
604631

605632
uint8_t sendRequest(String& req) {
633+
if (!_FB_http.begin(_FB_client, req)) return 4; // ошибка подключения
606634
uint8_t status = 1;
607-
if (_FB_httpReq.begin(_FB_client, req)) {
608-
if (_FB_httpReq.GET() != HTTP_CODE_OK) status = 3;
609-
const String& answ = _FB_httpReq.getString();
610-
int16_t st = 0;
611-
String buf;
612-
if (find(answ, buf, st, F("\"message_id\":"), ',', answ.length())) {
613-
_lastBotMsg = buf.toInt();
614-
}
615-
if (find(answ, buf, st, F("\"date\":"), ',', answ.length())) {
616-
_unix = buf.toInt();
617-
_lastUpd = millis();
618-
}
619-
_FB_httpReq.end();
620-
} else status = 4;
635+
if (_FB_http.GET() == HTTP_CODE_OK && _FB_http.getSize()) { // есть ответ и он не пустой
636+
parseRequest(_FB_http.getString()); // парсим
637+
} else status = 3; // некорректный ответ
638+
_FB_http.end();
621639
return status;
622640
}
623641

@@ -658,6 +676,17 @@ class FastBot {
658676
bool timeSynced() {
659677
return _unix;
660678
}
679+
680+
uint8_t update() {
681+
if (!_file_ptr) return 5;
682+
sendMessage(F("OTA update..."), _otaID);
683+
String req;
684+
_addToken(req);
685+
req += F("/getFile?file_id=");
686+
req += *_file_ptr;
687+
_file_ptr = nullptr;
688+
return sendRequest(req);
689+
}
661690

662691
private:
663692
// ================ BUILDER ===============
@@ -731,9 +760,7 @@ class FastBot {
731760
return (strPos > 0) && (strPos < end);
732761
}
733762

734-
uint8_t parse(const String& str, uint16_t size) {
735-
ovfFlag = size > 25000; // 1 полное сообщение на русском языке или ~5 на английском
736-
if (ovfFlag) return 2;
763+
uint8_t parseMessages(const String& str) {
737764
if (!str.startsWith(F("{\"ok\":true"))) return 3; // ошибка запроса (неправильный токен итд)
738765
int16_t IDpos = str.indexOf(F("{\"update_id\":"), 0); // первая позиция ключа update_id
739766

@@ -749,10 +776,11 @@ class FastBot {
749776

750777
String query;
751778
int16_t queryEnd = 0;
779+
if (_query_ptr) _query_ptr = nullptr;
752780
if (find(str, query, textPos, F("\"callback_query\":{\"id\":\""), ',', IDpos)) {
753-
_query = &query;
781+
_query_ptr = &query;
754782
queryEnd = textPos;
755-
} else _query = nullptr;
783+
}
756784

757785
bool edited = find(str, F("\"edited_message\":"), textPos, IDpos);
758786

@@ -778,6 +806,16 @@ class FastBot {
778806
String date;
779807
find(str, date, textPos, F("\"date\":"), ',', IDpos);
780808

809+
String file;
810+
if (_file_ptr) _file_ptr = nullptr;
811+
if (find(str, file, textPos, F("\"file_name\":\""), '\"', IDpos)) {
812+
if (file.endsWith(F(".bin"))) {
813+
find(str, file, textPos, F("\"file_id\":\""), '\"', IDpos);
814+
_file_ptr = &file;
815+
_otaID = chatID;
816+
}
817+
}
818+
781819
// удаление сервисных сообщений
782820
if (clrSrv) {
783821
if (find(str, F("\"new_chat_title\""), textPos, IDpos) ||
@@ -788,7 +826,8 @@ class FastBot {
788826
}
789827

790828
String text;
791-
find(str, text, textPos, F("\"text\":\""), '\"', IDpos);
829+
if (_file_ptr) find(str, text, textPos, F("\"caption\":\""), '\"', IDpos);
830+
else find(str, text, textPos, F("\"text\":\""), '\"', IDpos);
792831

793832
String data;
794833
find(str, data, textPos, F("\"data\":\""), '\"', IDpos);
@@ -805,9 +844,10 @@ class FastBot {
805844
_lastUsrMsg,
806845
text,
807846
data,
808-
(bool)_query,
847+
(bool)_query_ptr,
809848
edited,
810849
is_bot[0] == 't',
850+
(bool)_file_ptr,
811851
(uint32_t)date.toInt(),
812852

813853
// legacy
@@ -817,16 +857,46 @@ class FastBot {
817857
_lastUsrMsg,
818858
};
819859
_callback(msg);
820-
if (_query) answer(); // отвечаем на коллбэк, если юзер не ответил
860+
if (_query_ptr) answer(); // отвечаем на коллбэк, если юзер не ответил
861+
if (OTAstate >= 0) break; // обновление! выходим
821862
yield();
822863
}
823864
if (_incr) ID += counter;
824865
return 1;
825866
}
867+
868+
void parseRequest(const String& answ) {
869+
int16_t st = 0;
870+
String buf;
871+
if (find(answ, buf, st, F("\"message_id\":"), ',', answ.length())) {
872+
_lastBotMsg = buf.toInt();
873+
}
874+
if (find(answ, buf, st, F("\"date\":"), ',', answ.length())) {
875+
_unix = buf.toInt();
876+
_lastUpd = millis();
877+
}
878+
if (find(answ, buf, st, F("\"file_path\":\""), '\"', answ.length())) {
879+
String url(F("https://api.telegram.org/file/bot"));
880+
url += _token;
881+
url += '/';
882+
url += buf;
883+
#ifdef ESP8266
884+
ESPhttpUpdate.rebootOnUpdate(false);
885+
OTAstate = ESPhttpUpdate.update(_FB_client, url);
886+
#else
887+
WiFiClientSecure client;
888+
client.setInsecure();
889+
httpUpdate.rebootOnUpdate(false);
890+
OTAstate = httpUpdate.update(client, url);
891+
#endif
892+
}
893+
}
826894

827895
void (*_callback)(FB_msg& msg) = nullptr;
828896
String _token;
829-
String* _query = nullptr;
897+
String _otaID;
898+
String* _file_ptr = nullptr;
899+
String* _query_ptr = nullptr;
830900
uint16_t _ovf, _prd, _limit;
831901
int32_t ID = 0;
832902
uint32_t tmr = 0;
@@ -836,6 +906,7 @@ class FastBot {
836906
bool notif = true;
837907
bool clrSrv = false;
838908
bool ovfFlag = 0;
909+
int8_t OTAstate = -1;
839910

840911
uint32_t _unix = 0;
841912
uint32_t _lastUpd = 0;

0 commit comments

Comments
 (0)