mirror of https://github.com/arendst/Tasmota.git
Fix memory corruption
This commit is contained in:
parent
c1fd24efc6
commit
f3591b8419
|
@ -1,9 +1,15 @@
|
||||||
# JSMN lightweight JSON parser for Tasmota
|
# JSMN lightweight JSON parser for Tasmota
|
||||||
|
|
||||||
Intro:
|
Intro: this library uses the JSMN in-place JSON parser.
|
||||||
|
See https://github.com/zserge/jsmn and https://zserge.com/jsmn/
|
||||||
|
|
||||||
|
It is proposed as a replacement for ArduinoJson. It has less features, does only parsing but does it in a very efficient way.
|
||||||
|
|
||||||
## Benefits
|
## Benefits
|
||||||
|
|
||||||
|
First, the memory impact is very low: 4 bytes per token and no need to add an extra buffer for values.
|
||||||
|
Second, the code is much smaller than ArduinoJson by 5-7KB.
|
||||||
|
|
||||||
## How to use
|
## How to use
|
||||||
|
|
||||||
`{"Device":"0x1234","Power":true,"Temperature":25.5}`
|
`{"Device":"0x1234","Power":true,"Temperature":25.5}`
|
||||||
|
@ -24,7 +30,8 @@ If what you need is to parse a JSON Object for values with default values:
|
||||||
#include "JsonParser.h"
|
#include "JsonParser.h"
|
||||||
|
|
||||||
char json_buffer[] = "{\"Device\":\"0x1234\",\"Power\":true,\"Temperature\":25.6}";
|
char json_buffer[] = "{\"Device\":\"0x1234\",\"Power\":true,\"Temperature\":25.6}";
|
||||||
JsonParserObject root = JsonParser(json_buffer).getRootObject();
|
JsonParser parser(json_buffer);
|
||||||
|
JsonParserObject root = parser.getRootObject();
|
||||||
if (!root) { ResponseCmndChar_P(PSTR("Invalid JSON")); return; }
|
if (!root) { ResponseCmndChar_P(PSTR("Invalid JSON")); return; }
|
||||||
|
|
||||||
uint16_t d = root.getUInt(PSTR("DEVICE"), 0xFFFF); // case insensitive
|
uint16_t d = root.getUInt(PSTR("DEVICE"), 0xFFFF); // case insensitive
|
||||||
|
@ -37,7 +44,8 @@ Alternative pattern, if you want to test the existence of the attribute first:
|
||||||
#include "JsonParser.h"
|
#include "JsonParser.h"
|
||||||
|
|
||||||
char json_buffer[] = "{\"Device\":\"0x1234\",\"Power\":true,\"Temperature\":25.6}";
|
char json_buffer[] = "{\"Device\":\"0x1234\",\"Power\":true,\"Temperature\":25.6}";
|
||||||
JsonParserObject root = JsonParser(json_buffer).getRootObject();
|
JsonParser parser(json_buffer);
|
||||||
|
JsonParserObject root = parser.getRootObject();
|
||||||
if (!root) { ResponseCmndChar_P(PSTR("Invalid JSON")); return; }
|
if (!root) { ResponseCmndChar_P(PSTR("Invalid JSON")); return; }
|
||||||
|
|
||||||
JsonParserToken val = root[PSTR("DEVICE")];
|
JsonParserToken val = root[PSTR("DEVICE")];
|
||||||
|
@ -54,6 +62,12 @@ if (val) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
WARNING: never use the following form:
|
||||||
|
```
|
||||||
|
JsonParserObject root = JsonParser(json_buffer).getRootObject();
|
||||||
|
```
|
||||||
|
In this case, the `JsonParser` object is temporary and destroyed at the end of the expression. Setting the JsonParser to a local variable ensures that the lifetime of the object is extended to the end of the scope.
|
||||||
|
|
||||||
## Types and conversion
|
## Types and conversion
|
||||||
|
|
||||||
JSMN relies on the concept of JSON Tokens `JsonParserToken`. Tokens do not hold any data, but point to token boundaries in JSON string instead. Every jsmn token has a type, which indicates the type of corresponding JSON token. JSMN for Tasmota extends the type from JSMN to ease further parsing.
|
JSMN relies on the concept of JSON Tokens `JsonParserToken`. Tokens do not hold any data, but point to token boundaries in JSON string instead. Every jsmn token has a type, which indicates the type of corresponding JSON token. JSMN for Tasmota extends the type from JSMN to ease further parsing.
|
||||||
|
|
|
@ -15,7 +15,7 @@ int main(int argc, char* argv[]) {
|
||||||
// char * json_str = test_complex;
|
// char * json_str = test_complex;
|
||||||
char * json_str = test_simple;
|
char * json_str = test_simple;
|
||||||
|
|
||||||
JsonParser parser(64); // size for 64 tokens
|
// JsonParser parser(64); // size for 64 tokens
|
||||||
|
|
||||||
int r = parser.parse(json_str);
|
int r = parser.parse(json_str);
|
||||||
|
|
||||||
|
|
|
@ -1473,7 +1473,8 @@ bool JsonTemplate(char* dataBuf)
|
||||||
|
|
||||||
if (strlen(dataBuf) < 9) { return false; } // Workaround exception if empty JSON like {} - Needs checks
|
if (strlen(dataBuf) < 9) { return false; } // Workaround exception if empty JSON like {} - Needs checks
|
||||||
|
|
||||||
JsonParserObject root = JsonParser((char*) dataBuf).getRootObject();
|
JsonParser parser((char*) dataBuf);
|
||||||
|
JsonParserObject root = parser.getRootObject();
|
||||||
if (!root) { return false; }
|
if (!root) { return false; }
|
||||||
|
|
||||||
// All parameters are optional allowing for partial changes
|
// All parameters are optional allowing for partial changes
|
||||||
|
|
|
@ -27,8 +27,6 @@
|
||||||
|
|
||||||
#define XDRV_01 1
|
#define XDRV_01 1
|
||||||
|
|
||||||
#include "JsonParser.h"
|
|
||||||
|
|
||||||
#ifndef WIFI_SOFT_AP_CHANNEL
|
#ifndef WIFI_SOFT_AP_CHANNEL
|
||||||
#define WIFI_SOFT_AP_CHANNEL 1 // Soft Access Point Channel number between 1 and 11 as used by WifiManager web GUI
|
#define WIFI_SOFT_AP_CHANNEL 1 // Soft Access Point Channel number between 1 and 11 as used by WifiManager web GUI
|
||||||
#endif
|
#endif
|
||||||
|
@ -3366,7 +3364,8 @@ bool JsonWebColor(const char* dataBuf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
JsonParserObject root = JsonParser((char*) dataBuf).getRootObject();
|
JsonParser parser((char*) dataBuf);
|
||||||
|
JsonParserObject root = parser.getRootObject();
|
||||||
JsonParserArray arr = root[PSTR(D_CMND_WEBCOLOR)].getArray();
|
JsonParserArray arr = root[PSTR(D_CMND_WEBCOLOR)].getArray();
|
||||||
if (arr) { // if arr is valid, i.e. json is valid, the key D_CMND_WEBCOLOR was found and the token is an arra
|
if (arr) { // if arr is valid, i.e. json is valid, the key D_CMND_WEBCOLOR was found and the token is an arra
|
||||||
uint32_t i = 0;
|
uint32_t i = 0;
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
#define XDRV_05 5
|
#define XDRV_05 5
|
||||||
|
|
||||||
#include <IRremoteESP8266.h>
|
#include <IRremoteESP8266.h>
|
||||||
#include "JsonParser.h"
|
|
||||||
|
|
||||||
enum IrErrors { IE_NO_ERROR, IE_INVALID_RAWDATA, IE_INVALID_JSON, IE_SYNTAX_IRSEND };
|
enum IrErrors { IE_NO_ERROR, IE_INVALID_RAWDATA, IE_INVALID_JSON, IE_SYNTAX_IRSEND };
|
||||||
|
|
||||||
|
@ -204,7 +203,8 @@ uint32_t IrRemoteCmndIrSendJson(void)
|
||||||
uint16_t repeat = root[UpperCase_P(parm_uc, PSTR(D_JSON_IR_REPEAT))];
|
uint16_t repeat = root[UpperCase_P(parm_uc, PSTR(D_JSON_IR_REPEAT))];
|
||||||
#else
|
#else
|
||||||
RemoveSpace(XdrvMailbox.data); // TODO is this really needed?
|
RemoveSpace(XdrvMailbox.data); // TODO is this really needed?
|
||||||
JsonParserObject root = JsonParser((char*) XdrvMailbox.data).getRootObject();
|
JsonParser parser(XdrvMailbox.data);
|
||||||
|
JsonParserObject root = parser.getRootObject();
|
||||||
if (!root) { return IE_INVALID_JSON; }
|
if (!root) { return IE_INVALID_JSON; }
|
||||||
|
|
||||||
// IRsend { "protocol": "SAMSUNG", "bits": 32, "data": 551502015 }
|
// IRsend { "protocol": "SAMSUNG", "bits": 32, "data": 551502015 }
|
||||||
|
|
|
@ -29,7 +29,6 @@
|
||||||
#include <IRrecv.h>
|
#include <IRrecv.h>
|
||||||
#include <IRutils.h>
|
#include <IRutils.h>
|
||||||
#include <IRac.h>
|
#include <IRac.h>
|
||||||
#include "JsonParser.h"
|
|
||||||
|
|
||||||
enum IrErrors { IE_RESPONSE_PROVIDED, IE_NO_ERROR, IE_INVALID_RAWDATA, IE_INVALID_JSON, IE_SYNTAX_IRSEND, IE_SYNTAX_IRHVAC,
|
enum IrErrors { IE_RESPONSE_PROVIDED, IE_NO_ERROR, IE_INVALID_RAWDATA, IE_INVALID_JSON, IE_SYNTAX_IRSEND, IE_SYNTAX_IRHVAC,
|
||||||
IE_UNSUPPORTED_HVAC, IE_UNSUPPORTED_PROTOCOL };
|
IE_UNSUPPORTED_HVAC, IE_UNSUPPORTED_PROTOCOL };
|
||||||
|
@ -288,7 +287,8 @@ uint32_t IrRemoteCmndIrHvacJson(void)
|
||||||
stdAc::state_t state, prev;
|
stdAc::state_t state, prev;
|
||||||
|
|
||||||
//AddLog_P2(LOG_LEVEL_DEBUG, PSTR("IRHVAC: Received %s"), XdrvMailbox.data);
|
//AddLog_P2(LOG_LEVEL_DEBUG, PSTR("IRHVAC: Received %s"), XdrvMailbox.data);
|
||||||
JsonParserObject root = JsonParser((char*) XdrvMailbox.data).getRootObject();
|
JsonParser parser(XdrvMailbox.data);
|
||||||
|
JsonParserObject root = parser.getRootObject();
|
||||||
if (!root) { return IE_INVALID_JSON; }
|
if (!root) { return IE_INVALID_JSON; }
|
||||||
|
|
||||||
// from: https://github.com/crankyoldgit/IRremoteESP8266/blob/master/examples/CommonAcControl/CommonAcControl.ino
|
// from: https://github.com/crankyoldgit/IRremoteESP8266/blob/master/examples/CommonAcControl/CommonAcControl.ino
|
||||||
|
|
|
@ -425,7 +425,8 @@ void CmndTimer(void)
|
||||||
#if defined(USE_RULES)==0 && defined(USE_SCRIPT)==0
|
#if defined(USE_RULES)==0 && defined(USE_SCRIPT)==0
|
||||||
if (devices_present) {
|
if (devices_present) {
|
||||||
#endif
|
#endif
|
||||||
JsonParserObject root = JsonParser(XdrvMailbox.data).getRootObject();
|
JsonParser parser(XdrvMailbox.data);
|
||||||
|
JsonParserObject root = parser.getRootObject();
|
||||||
if (!root) {
|
if (!root) {
|
||||||
Response_P(PSTR("{\"" D_CMND_TIMER "%d\":\"" D_JSON_INVALID_JSON "\"}"), index); // JSON decode failed
|
Response_P(PSTR("{\"" D_CMND_TIMER "%d\":\"" D_JSON_INVALID_JSON "\"}"), index); // JSON decode failed
|
||||||
error = 1;
|
error = 1;
|
||||||
|
|
|
@ -532,7 +532,7 @@ bool RulesRuleMatch(uint8_t rule_set, String &event, String &rule)
|
||||||
#else
|
#else
|
||||||
|
|
||||||
String buf = event; // copy the string into a new buffer that will be modified
|
String buf = event; // copy the string into a new buffer that will be modified
|
||||||
JsonParser parser = JsonParser((char*)buf.c_str());
|
JsonParser parser((char*)buf.c_str());
|
||||||
JsonParserObject obj = parser.getRootObject();
|
JsonParserObject obj = parser.getRootObject();
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("RUL: Event too long (%d)"), event.length());
|
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("RUL: Event too long (%d)"), event.length());
|
||||||
|
@ -1069,7 +1069,8 @@ bool RulesMqttData(void)
|
||||||
if (event_item.Key.length() == 0) { //If did not specify Key
|
if (event_item.Key.length() == 0) { //If did not specify Key
|
||||||
value = sData;
|
value = sData;
|
||||||
} else { //If specified Key, need to parse Key/Value from JSON data
|
} else { //If specified Key, need to parse Key/Value from JSON data
|
||||||
JsonParserObject jsonData = JsonParser((char*)sData.c_str()).getRootObject();
|
JsonParser parser((char*)sData.c_str());
|
||||||
|
JsonParserObject jsonData = parser.getRootObject();
|
||||||
|
|
||||||
String key1 = event_item.Key;
|
String key1 = event_item.Key;
|
||||||
String key2;
|
String key2;
|
||||||
|
|
|
@ -104,7 +104,8 @@ void CmndRfSend(void)
|
||||||
int repeat = 10;
|
int repeat = 10;
|
||||||
int pulse = 350;
|
int pulse = 350;
|
||||||
|
|
||||||
JsonParserObject root = JsonParser(XdrvMailbox.data).getRootObject();
|
JsonParser parser(XdrvMailbox.data);
|
||||||
|
JsonParserObject root = parser.getRootObject();
|
||||||
if (root) {
|
if (root) {
|
||||||
// RFsend {"data":0x501014,"bits":24,"protocol":1,"repeat":10,"pulse":350}
|
// RFsend {"data":0x501014,"bits":24,"protocol":1,"repeat":10,"pulse":350}
|
||||||
char parm_uc[10];
|
char parm_uc[10];
|
||||||
|
|
|
@ -569,7 +569,7 @@ void HueLightsCommand(uint8_t device, uint32_t device_id, String &response) {
|
||||||
if (Webserver->args()) {
|
if (Webserver->args()) {
|
||||||
response = "[";
|
response = "[";
|
||||||
|
|
||||||
JsonParser parser = JsonParser((char*) Webserver->arg((Webserver->args())-1).c_str());
|
JsonParser parser((char*) Webserver->arg((Webserver->args())-1).c_str());
|
||||||
JsonParserObject root = parser.getRootObject();
|
JsonParserObject root = parser.getRootObject();
|
||||||
|
|
||||||
JsonParserToken hue_on = root[PSTR("on")];
|
JsonParserToken hue_on = root[PSTR("on")];
|
||||||
|
|
|
@ -19,8 +19,6 @@
|
||||||
|
|
||||||
#ifdef USE_ZIGBEE
|
#ifdef USE_ZIGBEE
|
||||||
|
|
||||||
#include "JsonParser.h"
|
|
||||||
|
|
||||||
#ifndef ZIGBEE_SAVE_DELAY_SECONDS
|
#ifndef ZIGBEE_SAVE_DELAY_SECONDS
|
||||||
#define ZIGBEE_SAVE_DELAY_SECONDS 2 // wait for 2s before saving Zigbee info
|
#define ZIGBEE_SAVE_DELAY_SECONDS 2 // wait for 2s before saving Zigbee info
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -218,7 +218,7 @@ void ZigbeeHandleHue(uint16_t shortaddr, uint32_t device_id, String &response) {
|
||||||
if (Webserver->args()) {
|
if (Webserver->args()) {
|
||||||
response = "[";
|
response = "[";
|
||||||
|
|
||||||
JsonParser parser = JsonParser((char*) Webserver->arg((Webserver->args())-1).c_str());
|
JsonParser parser((char*) Webserver->arg((Webserver->args())-1).c_str());
|
||||||
JsonParserObject root = parser.getRootObject();
|
JsonParserObject root = parser.getRootObject();
|
||||||
|
|
||||||
JsonParserToken hue_on = root[PSTR("on")];
|
JsonParserToken hue_on = root[PSTR("on")];
|
||||||
|
|
|
@ -21,8 +21,6 @@
|
||||||
|
|
||||||
#define XDRV_23 23
|
#define XDRV_23 23
|
||||||
|
|
||||||
#include "JsonParser.h"
|
|
||||||
|
|
||||||
const char kZbCommands[] PROGMEM = D_PRFX_ZB "|" // prefix
|
const char kZbCommands[] PROGMEM = D_PRFX_ZB "|" // prefix
|
||||||
#ifdef USE_ZIGBEE_ZNP
|
#ifdef USE_ZIGBEE_ZNP
|
||||||
D_CMND_ZIGBEEZNPSEND "|" D_CMND_ZIGBEEZNPRECEIVE "|"
|
D_CMND_ZIGBEEZNPSEND "|" D_CMND_ZIGBEEZNPRECEIVE "|"
|
||||||
|
@ -626,7 +624,8 @@ void CmndZbSend(void) {
|
||||||
// ZbSend { "device":"0x1234", "endpoint":"0x03", "send":{"Color":"1,2"} }
|
// ZbSend { "device":"0x1234", "endpoint":"0x03", "send":{"Color":"1,2"} }
|
||||||
// ZbSend { "device":"0x1234", "endpoint":"0x03", "send":{"Color":"0x1122,0xFFEE"} }
|
// ZbSend { "device":"0x1234", "endpoint":"0x03", "send":{"Color":"0x1122,0xFFEE"} }
|
||||||
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
|
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
|
||||||
JsonParserObject root = JsonParser(XdrvMailbox.data).getRootObject();
|
JsonParser parser(XdrvMailbox.data);
|
||||||
|
JsonParserObject root = parser.getRootObject();
|
||||||
if (!root) { ResponseCmndChar_P(PSTR(D_JSON_INVALID_JSON)); return; }
|
if (!root) { ResponseCmndChar_P(PSTR(D_JSON_INVALID_JSON)); return; }
|
||||||
|
|
||||||
// params
|
// params
|
||||||
|
@ -748,7 +747,8 @@ void ZbBindUnbind(bool unbind) { // false = bind, true = unbind
|
||||||
|
|
||||||
// local endpoint is always 1, IEEE addresses are calculated
|
// local endpoint is always 1, IEEE addresses are calculated
|
||||||
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
|
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
|
||||||
JsonParserObject root = JsonParser(XdrvMailbox.data).getRootObject();
|
JsonParser parser(XdrvMailbox.data);
|
||||||
|
JsonParserObject root = parser.getRootObject();
|
||||||
if (!root) { ResponseCmndChar_P(PSTR(D_JSON_INVALID_JSON)); return; }
|
if (!root) { ResponseCmndChar_P(PSTR(D_JSON_INVALID_JSON)); return; }
|
||||||
|
|
||||||
// params
|
// params
|
||||||
|
@ -1064,8 +1064,8 @@ void CmndZbSave(void) {
|
||||||
// ZbRestore {"Device":"0x5ADF","Name":"Petite_Lampe","IEEEAddr":"0x90FD9FFFFE03B051","ModelId":"TRADFRI bulb E27 WS opal 980lm","Manufacturer":"IKEA of Sweden","Endpoints":["0x01","0xF2"]}
|
// ZbRestore {"Device":"0x5ADF","Name":"Petite_Lampe","IEEEAddr":"0x90FD9FFFFE03B051","ModelId":"TRADFRI bulb E27 WS opal 980lm","Manufacturer":"IKEA of Sweden","Endpoints":["0x01","0xF2"]}
|
||||||
void CmndZbRestore(void) {
|
void CmndZbRestore(void) {
|
||||||
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
|
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
|
||||||
JsonParser p(XdrvMailbox.data);
|
JsonParser parser(XdrvMailbox.data);
|
||||||
JsonParserToken root = p.getRoot();
|
JsonParserToken root = parser.getRoot();
|
||||||
|
|
||||||
if (!p || !(root.isObject() || root.isArray())) { ResponseCmndChar_P(PSTR(D_JSON_INVALID_JSON)); return; }
|
if (!p || !(root.isObject() || root.isArray())) { ResponseCmndChar_P(PSTR(D_JSON_INVALID_JSON)); return; }
|
||||||
|
|
||||||
|
@ -1219,7 +1219,8 @@ void CmndZbConfig(void) {
|
||||||
// if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
|
// if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
|
||||||
RemoveAllSpaces(XdrvMailbox.data);
|
RemoveAllSpaces(XdrvMailbox.data);
|
||||||
if (strlen(XdrvMailbox.data) > 0) {
|
if (strlen(XdrvMailbox.data) > 0) {
|
||||||
JsonParserObject root = JsonParser(XdrvMailbox.data).getRootObject();
|
JsonParser parser(XdrvMailbox.data);
|
||||||
|
JsonParserObject root = parser.getRootObject();
|
||||||
if (!root) { ResponseCmndChar_P(PSTR(D_JSON_INVALID_JSON)); return; }
|
if (!root) { ResponseCmndChar_P(PSTR(D_JSON_INVALID_JSON)); return; }
|
||||||
// Channel
|
// Channel
|
||||||
|
|
||||||
|
|
|
@ -1328,7 +1328,8 @@ void ThermostatDebug(uint8_t ctr_output)
|
||||||
#endif // DEBUG_THERMOSTAT
|
#endif // DEBUG_THERMOSTAT
|
||||||
|
|
||||||
void ThermostatGetLocalSensor(uint8_t ctr_output) {
|
void ThermostatGetLocalSensor(uint8_t ctr_output) {
|
||||||
JsonParserObject root = JsonParser(mqtt_data).getRootObject();
|
JsonParser parser(mqtt_data);
|
||||||
|
JsonParserObject root = parser.getRootObject();
|
||||||
if (root) {
|
if (root) {
|
||||||
JsonParserToken value_token = root[PSTR(THERMOSTAT_SENSOR_NAME)].getObject()[PSTR("Temperature")];
|
JsonParserToken value_token = root[PSTR(THERMOSTAT_SENSOR_NAME)].getObject()[PSTR("Temperature")];
|
||||||
if (value_token.isNum()) {
|
if (value_token.isNum()) {
|
||||||
|
|
|
@ -226,7 +226,8 @@ void TelegramAnalizeMessage(void) {
|
||||||
Telegram.message[i][5] = "";
|
Telegram.message[i][5] = "";
|
||||||
|
|
||||||
String buf = Telegram.message[i][0]; // we need to keep a copy of the buffer
|
String buf = Telegram.message[i][0]; // we need to keep a copy of the buffer
|
||||||
JsonParserObject root = JsonParser((char*)buf.c_str()).getRootObject();
|
JsonParser parser((char*)buf.c_str());
|
||||||
|
JsonParserObject root = parser.getRootObject();
|
||||||
if (root) {
|
if (root) {
|
||||||
Telegram.message[i][0] = root["update_id"].getStr();
|
Telegram.message[i][0] = root["update_id"].getStr();
|
||||||
Telegram.message[i][1] = root["message"].getObject()["from"].getObject()["id"].getStr();
|
Telegram.message[i][1] = root["message"].getObject()["from"].getObject()["id"].getStr();
|
||||||
|
|
Loading…
Reference in New Issue