mirror of https://github.com/arendst/Tasmota.git
Move IR from ArduinoJson to JSMN
This commit is contained in:
parent
1174479a70
commit
019e402fe7
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
JsonGenerator.cpp - lightweight JSON parser
|
||||
|
||||
Copyright (C) 2020 Stephan Hadinger
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "JsonGenerator.h"
|
||||
|
||||
/*********************************************************************************************\
|
||||
* JSON Generator for Arrays
|
||||
\*********************************************************************************************/
|
||||
void JsonGeneratorArray::pre(void) {
|
||||
// remove trailing ']'
|
||||
val.remove(val.length()-1);
|
||||
if (val.length() > 1) { // if not empty, prefix with comma
|
||||
val += ',';
|
||||
}
|
||||
}
|
||||
|
||||
// void JsonGeneratorArray::post(void) {
|
||||
// val += ']';
|
||||
// }
|
||||
|
||||
// Add signed int (32 bits)
|
||||
void JsonGeneratorArray::add(int32_t uval32) {
|
||||
pre();
|
||||
val += uval32;
|
||||
post();
|
||||
}
|
||||
|
||||
// Add unsigned int (32 bits)
|
||||
void JsonGeneratorArray::add(uint32_t uval32) {
|
||||
pre();
|
||||
val += uval32;
|
||||
post();
|
||||
}
|
||||
|
||||
// Add a raw string, that will not be escaped.
|
||||
// Can be used to add a sub-array, sub-object or 'null', 'true', 'false' values
|
||||
void JsonGeneratorArray::addStrRaw(const char * sval) {
|
||||
pre();
|
||||
val += sval;
|
||||
post();
|
||||
}
|
||||
|
||||
// Add a JSON String (will be escaped)
|
||||
void JsonGeneratorArray::addStr(const char * sval) {
|
||||
pre();
|
||||
val += '"';
|
||||
val += EscapeJSONString(sval).c_str();
|
||||
val += '"';
|
||||
post();
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* JSON Generator for Objects
|
||||
\*********************************************************************************************/
|
||||
void JsonGeneratorObject::pre(const char * key) {
|
||||
// remove trailing '}'
|
||||
val.remove(val.length()-1);
|
||||
if (val.length() > 1) { // if not empty, prefix with comma
|
||||
val += ',';
|
||||
}
|
||||
val += '"';
|
||||
val += EscapeJSONString(key);
|
||||
val += '"';
|
||||
val += ':';
|
||||
}
|
||||
|
||||
// void JsonGeneratorObject::post(void) {
|
||||
// val += '}';
|
||||
// }
|
||||
|
||||
// Add signed int (32 bits)
|
||||
void JsonGeneratorObject::add(const char* key, int32_t uval32) {
|
||||
pre(key);
|
||||
val += uval32;
|
||||
post();
|
||||
}
|
||||
|
||||
// Add unsigned int (32 bits)
|
||||
void JsonGeneratorObject::add(const char* key, uint32_t uval32) {
|
||||
pre(key);
|
||||
val += uval32;
|
||||
post();
|
||||
}
|
||||
|
||||
void JsonGeneratorObject::add(const char* key, const String & str) {
|
||||
pre(key);
|
||||
val += '"';
|
||||
val += EscapeJSONString(str.c_str()).c_str();
|
||||
val += '"';
|
||||
post();
|
||||
}
|
||||
|
||||
// Add a raw string, that will not be escaped.
|
||||
// Can be used to add a sub-array, sub-object or 'null', 'true', 'false' values
|
||||
void JsonGeneratorObject::addStrRaw(const char* key, const char * sval) {
|
||||
pre(key);
|
||||
val += sval;
|
||||
post();
|
||||
}
|
||||
|
||||
// Add a JSON String (will be escaped)
|
||||
void JsonGeneratorObject::addStr(const char* key, const char * sval) {
|
||||
pre(key);
|
||||
val += '"';
|
||||
val += EscapeJSONString(sval).c_str();
|
||||
val += '"';
|
||||
post();
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* JSON Generator for Arrays
|
||||
\*********************************************************************************************/
|
||||
// does the character needs to be escaped, and if so with which character
|
||||
static char EscapeJSONChar(char c) {
|
||||
if ((c == '\"') || (c == '\\')) {
|
||||
return c;
|
||||
}
|
||||
if (c == '\n') { return 'n'; }
|
||||
if (c == '\t') { return 't'; }
|
||||
if (c == '\r') { return 'r'; }
|
||||
if (c == '\f') { return 'f'; }
|
||||
if (c == '\b') { return 'b'; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
String EscapeJSONString(const char *str) {
|
||||
// As this function is used in ResponseCmndChar() and ResponseCmndIdxChar()
|
||||
// it needs to be PROGMEM safe!
|
||||
String r("");
|
||||
if (nullptr == str) { return r; }
|
||||
|
||||
bool needs_escape = false;
|
||||
size_t len_out = 1;
|
||||
const char* c = str;
|
||||
char ch = '.';
|
||||
while (ch != '\0') {
|
||||
ch = pgm_read_byte(c++);
|
||||
if (EscapeJSONChar(ch)) {
|
||||
len_out++;
|
||||
needs_escape = true;
|
||||
}
|
||||
len_out++;
|
||||
}
|
||||
|
||||
if (needs_escape) {
|
||||
// we need to escape some chars
|
||||
// allocate target buffer
|
||||
r.reserve(len_out);
|
||||
c = str;
|
||||
char *d = r.begin();
|
||||
char ch = '.';
|
||||
while (ch != '\0') {
|
||||
ch = pgm_read_byte(c++);
|
||||
char c2 = EscapeJSONChar(ch);
|
||||
if (c2) {
|
||||
*d++ = '\\';
|
||||
*d++ = c2;
|
||||
} else {
|
||||
*d++ = ch;
|
||||
}
|
||||
}
|
||||
*d = 0; // add NULL terminator
|
||||
r = (char*) r.begin(); // assign the buffer to the string
|
||||
} else {
|
||||
r = FPSTR(str);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
JsonGenerator.h - lightweight JSON generator
|
||||
|
||||
Copyright (C) 2020 Stephan Hadinger
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __JSON_GENERATOR__
|
||||
#define __JSON_GENERATOR__
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
extern String EscapeJSONString(const char *str);
|
||||
|
||||
/*********************************************************************************************\
|
||||
* JSON Generator for Arrays
|
||||
\*********************************************************************************************/
|
||||
class JsonGeneratorArray {
|
||||
public:
|
||||
|
||||
JsonGeneratorArray(): val("[]") {} // start with empty array
|
||||
|
||||
void add(uint32_t uval32);
|
||||
void add(int32_t uval32);
|
||||
void addStrRaw(const char * sval);
|
||||
void addStr(const char * sval);
|
||||
|
||||
inline String &toString(void) { return val; }
|
||||
|
||||
protected:
|
||||
void pre(void);
|
||||
void post(void) { val += ']'; }
|
||||
String val;
|
||||
};
|
||||
|
||||
/*********************************************************************************************\
|
||||
* JSON Generator for Objects
|
||||
\*********************************************************************************************/
|
||||
class JsonGeneratorObject {
|
||||
public:
|
||||
|
||||
JsonGeneratorObject(): val("{}") {} // start with empty object
|
||||
|
||||
void add(const char* key, uint32_t uval32);
|
||||
void add(const char* key, int32_t uval32);
|
||||
void add(const char* key, const String & str);
|
||||
void addStrRaw(const char* key, const char * sval);
|
||||
void addStr(const char* key, const char * sval);
|
||||
|
||||
inline String &toString(void) { return val; }
|
||||
|
||||
protected:
|
||||
void pre(const char * key);
|
||||
void post(void) { val += '}'; }
|
||||
String val;
|
||||
};
|
||||
|
||||
#endif // __JSON_PARSER__
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
JsonParser.h - lightweight JSON parser
|
||||
JsonParser.cpp - lightweight JSON parser
|
||||
|
||||
Copyright (C) 2020 Stephan Hadinger
|
||||
|
||||
|
@ -366,6 +366,9 @@ float JsonParserObject::getFloat(const char * needle, float val) const {
|
|||
const char * JsonParserObject::getStr(const char * needle, const char * val) const {
|
||||
return (*this)[needle].getStr(val);
|
||||
}
|
||||
const char * JsonParserObject::getStr(const char * needle) const {
|
||||
return getStr(needle, "");
|
||||
}
|
||||
|
||||
void JsonParser::parse(char * json_in) {
|
||||
k_current_json_buffer = "";
|
||||
|
|
|
@ -67,6 +67,7 @@ public:
|
|||
JsonParserToken(const jsmntok_t * token) : t(token) {
|
||||
if (nullptr == t) { t = &token_bad; }
|
||||
}
|
||||
JsonParserToken() : t(&token_bad) { }
|
||||
// no explicit destructor (not needed)
|
||||
|
||||
inline bool isValid(void) const { return t->type != JSMN_INVALID; }
|
||||
|
@ -160,6 +161,7 @@ public:
|
|||
uint64_t getULong(const char *, uint64_t) const;
|
||||
float getFloat(const char *, float) const;
|
||||
const char * getStr(const char *, const char *) const;
|
||||
const char * getStr(const char *) const;
|
||||
|
||||
// get first element (key)
|
||||
JsonParserKey getFirstElement(void) const;
|
||||
|
|
Binary file not shown.
|
@ -29,7 +29,6 @@ extern struct rst_info resetInfo;
|
|||
\*********************************************************************************************/
|
||||
|
||||
#include <Ticker.h>
|
||||
#include "JsonParser.h"
|
||||
|
||||
Ticker tickerOSWatch;
|
||||
|
||||
|
@ -1427,48 +1426,6 @@ bool GetUsedInModule(uint32_t val, uint16_t *arr)
|
|||
|
||||
bool JsonTemplate(char* dataBuf)
|
||||
{
|
||||
#if 0
|
||||
// {"NAME":"Generic","GPIO":[17,254,29,254,7,254,254,254,138,254,139,254,254],"FLAG":1,"BASE":255}
|
||||
|
||||
if (strlen(dataBuf) < 9) { return false; } // Workaround exception if empty JSON like {} - Needs checks
|
||||
|
||||
#ifdef ESP8266
|
||||
StaticJsonBuffer<400> jb; // 331 from https://arduinojson.org/v5/assistant/
|
||||
#else
|
||||
StaticJsonBuffer<999> jb; // 654 from https://arduinojson.org/v5/assistant/
|
||||
#endif
|
||||
JsonObject& obj = jb.parseObject(dataBuf);
|
||||
if (!obj.success()) { return false; }
|
||||
|
||||
// All parameters are optional allowing for partial changes
|
||||
const char* name = obj[D_JSON_NAME];
|
||||
if (name != nullptr) {
|
||||
SettingsUpdateText(SET_TEMPLATE_NAME, name);
|
||||
}
|
||||
if (obj[D_JSON_GPIO].success()) {
|
||||
for (uint32_t i = 0; i < ARRAY_SIZE(Settings.user_template.gp.io); i++) {
|
||||
#ifdef ESP8266
|
||||
Settings.user_template.gp.io[i] = obj[D_JSON_GPIO][i] | 0;
|
||||
#else // ESP32
|
||||
uint16_t gpio = obj[D_JSON_GPIO][i] | 0;
|
||||
if (gpio == (AGPIO(GPIO_NONE) +1)) {
|
||||
gpio = AGPIO(GPIO_USER);
|
||||
}
|
||||
Settings.user_template.gp.io[i] = gpio;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if (obj[D_JSON_FLAG].success()) {
|
||||
uint32_t flag = obj[D_JSON_FLAG] | 0;
|
||||
memcpy(&Settings.user_template.flag, &flag, sizeof(gpio_flag));
|
||||
}
|
||||
if (obj[D_JSON_BASE].success()) {
|
||||
uint32_t base = obj[D_JSON_BASE];
|
||||
if ((0 == base) || !ValidTemplateModule(base -1)) { base = 18; }
|
||||
Settings.user_template_base = base -1; // Default WEMOS
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
// {"NAME":"Generic","GPIO":[17,254,29,254,7,254,254,254,138,254,139,254,254],"FLAG":1,"BASE":255}
|
||||
|
||||
if (strlen(dataBuf) < 9) { return false; } // Workaround exception if empty JSON like {} - Needs checks
|
||||
|
@ -1508,7 +1465,6 @@ bool JsonTemplate(char* dataBuf)
|
|||
Settings.user_template_base = base -1; // Default WEMOS
|
||||
}
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void TemplateJson(void)
|
||||
|
|
|
@ -1,117 +0,0 @@
|
|||
/*
|
||||
support_json.ino - JSON support functions
|
||||
|
||||
Copyright (C) 2020 Theo Arends and Stephan Hadinger
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*********************************************************************************************\
|
||||
* JSON parsing
|
||||
\*********************************************************************************************/
|
||||
|
||||
// does the character needs to be escaped, and if so with which character
|
||||
char EscapeJSONChar(char c) {
|
||||
if ((c == '\"') || (c == '\\')) {
|
||||
return c;
|
||||
}
|
||||
if (c == '\n') { return 'n'; }
|
||||
if (c == '\t') { return 't'; }
|
||||
if (c == '\r') { return 'r'; }
|
||||
if (c == '\f') { return 'f'; }
|
||||
if (c == '\b') { return 'b'; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
String EscapeJSONString(const char *str) {
|
||||
// As this function is used in ResponseCmndChar() and ResponseCmndIdxChar()
|
||||
// it needs to be PROGMEM safe!
|
||||
String r("");
|
||||
if (nullptr == str) { return r; }
|
||||
|
||||
bool needs_escape = false;
|
||||
size_t len_out = 1;
|
||||
const char* c = str;
|
||||
char ch = '.';
|
||||
while (ch != '\0') {
|
||||
ch = pgm_read_byte(c++);
|
||||
if (EscapeJSONChar(ch)) {
|
||||
len_out++;
|
||||
needs_escape = true;
|
||||
}
|
||||
len_out++;
|
||||
}
|
||||
|
||||
if (needs_escape) {
|
||||
// we need to escape some chars
|
||||
// allocate target buffer
|
||||
r.reserve(len_out);
|
||||
c = str;
|
||||
char *d = r.begin();
|
||||
char ch = '.';
|
||||
while (ch != '\0') {
|
||||
ch = pgm_read_byte(c++);
|
||||
char c2 = EscapeJSONChar(ch);
|
||||
if (c2) {
|
||||
*d++ = '\\';
|
||||
*d++ = c2;
|
||||
} else {
|
||||
*d++ = ch;
|
||||
}
|
||||
}
|
||||
*d = 0; // add NULL terminator
|
||||
r = (char*) r.begin(); // assign the buffer to the string
|
||||
} else {
|
||||
r = FPSTR(str);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Find key - case insensitive
|
||||
\*********************************************************************************************/
|
||||
|
||||
// Given a JsonObject, finds the value as JsonVariant for the key needle.
|
||||
// The search is case-insensitive, and will find the first match in the order of keys in JSON
|
||||
//
|
||||
// If the key is not found, returns a nullptr
|
||||
// Input: needle cannot be NULL but may be PROGMEM
|
||||
#if 0
|
||||
const JsonVariant &GetCaseInsensitive(const JsonObject &json, const char *needle) {
|
||||
// key can be in PROGMEM
|
||||
// if needle == "?" then we return the first valid key
|
||||
bool wildcard = strcmp_P("?", needle) == 0;
|
||||
if ((nullptr == &json) || (nullptr == needle) || (0 == pgm_read_byte(needle)) || (!json.success())) {
|
||||
return *(JsonVariant*)nullptr;
|
||||
}
|
||||
|
||||
for (JsonObject::const_iterator it=json.begin(); it!=json.end(); ++it) {
|
||||
const char *key = it->key;
|
||||
const JsonVariant &value = it->value;
|
||||
|
||||
if (wildcard || (0 == strcasecmp_P(key, needle))) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
// if not found
|
||||
return *(JsonVariant*)nullptr;
|
||||
}
|
||||
|
||||
// This function returns true if the JsonObject contains the specified key
|
||||
// It's just a wrapper to the previous function but it can be tricky to test nullptr on an object ref
|
||||
bool HasKeyCaseInsensitive(const JsonObject &json, const char *needle) {
|
||||
return &GetCaseInsensitive(json, needle) != nullptr;
|
||||
}
|
||||
#endif
|
|
@ -50,6 +50,8 @@
|
|||
#include <ESP8266HTTPClient.h> // Ota
|
||||
#include <ESP8266httpUpdate.h> // Ota
|
||||
#include <StreamString.h> // Webserver, Updater
|
||||
#include <JsonParser.h>
|
||||
#include <JsonGenerator.h>
|
||||
#include <ArduinoJson.h> // WemoHue, IRremote, Domoticz
|
||||
#ifdef USE_ARDUINO_OTA
|
||||
#include <ArduinoOTA.h> // Arduino OTA
|
||||
|
|
|
@ -3344,26 +3344,6 @@ bool JsonWebColor(const char* dataBuf)
|
|||
// Default pre v7 (Light theme)
|
||||
// {"WebColor":["#000","#fff","#f2f2f2","#000","#fff","#000","#fff","#f00","#008000","#fff","#1fa3ec","#0e70a4","#d43535","#931f1f","#47c266","#5aaf6f","#fff","#999","#000"]} // {"WebColor":["#000000","#ffffff","#f2f2f2","#000000","#ffffff","#000000","#ffffff","#ff0000","#008000","#ffffff","#1fa3ec","#0e70a4","#d43535","#931f1f","#47c266","#5aaf6f","#ffffff","#999999","#000000"]}
|
||||
|
||||
#if 0
|
||||
char dataBufLc[strlen(dataBuf) +1];
|
||||
LowerCase(dataBufLc, dataBuf);
|
||||
RemoveSpace(dataBufLc);
|
||||
if (strlen(dataBufLc) < 9) { return false; } // Workaround exception if empty JSON like {} - Needs checks
|
||||
|
||||
StaticJsonBuffer<450> jb; // 421 from https://arduinojson.org/v5/assistant/
|
||||
JsonObject& obj = jb.parseObject(dataBufLc);
|
||||
if (!obj.success()) { return false; }
|
||||
|
||||
char parm_lc[10];
|
||||
if (obj[LowerCase(parm_lc, D_CMND_WEBCOLOR)].success()) {
|
||||
for (uint32_t i = 0; i < COL_LAST; i++) {
|
||||
const char* color = obj[parm_lc][i];
|
||||
if (color != nullptr) {
|
||||
WebHexCode(i, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
JsonParser parser((char*) dataBuf);
|
||||
JsonParserObject root = parser.getRootObject();
|
||||
JsonParserArray arr = root[PSTR(D_CMND_WEBCOLOR)].getArray();
|
||||
|
@ -3378,7 +3358,6 @@ bool JsonWebColor(const char* dataBuf)
|
|||
i++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -176,32 +176,9 @@ void IrReceiveCheck(void)
|
|||
|
||||
uint32_t IrRemoteCmndIrSendJson(void)
|
||||
{
|
||||
// ArduinoJSON entry used to calculate jsonBuf: JSON_OBJECT_SIZE(3) + 40 = 96
|
||||
// IRsend { "protocol": "RC5", "bits": 12, "data":"0xC86" }
|
||||
// IRsend { "protocol": "SAMSUNG", "bits": 32, "data": 551502015 }
|
||||
|
||||
#if 0
|
||||
char dataBufUc[XdrvMailbox.data_len + 1];
|
||||
UpperCase(dataBufUc, XdrvMailbox.data);
|
||||
RemoveSpace(dataBufUc);
|
||||
if (strlen(dataBufUc) < 8) {
|
||||
return IE_INVALID_JSON;
|
||||
}
|
||||
|
||||
StaticJsonBuffer<140> jsonBuf;
|
||||
JsonObject &root = jsonBuf.parseObject(dataBufUc);
|
||||
if (!root.success()) {
|
||||
return IE_INVALID_JSON;
|
||||
}
|
||||
|
||||
// IRsend { "protocol": "SAMSUNG", "bits": 32, "data": 551502015 }
|
||||
// IRsend { "protocol": "NEC", "bits": 32, "data":"0x02FDFE80", "repeat": 2 }
|
||||
char parm_uc[10];
|
||||
const char *protocol = root[UpperCase_P(parm_uc, PSTR(D_JSON_IR_PROTOCOL))];
|
||||
uint16_t bits = root[UpperCase_P(parm_uc, PSTR(D_JSON_IR_BITS))];
|
||||
uint64_t data = strtoull(root[UpperCase_P(parm_uc, PSTR(D_JSON_IR_DATA))], nullptr, 0);
|
||||
uint16_t repeat = root[UpperCase_P(parm_uc, PSTR(D_JSON_IR_REPEAT))];
|
||||
#else
|
||||
RemoveSpace(XdrvMailbox.data); // TODO is this really needed?
|
||||
JsonParser parser(XdrvMailbox.data);
|
||||
JsonParserObject root = parser.getRootObject();
|
||||
|
@ -213,7 +190,7 @@ uint32_t IrRemoteCmndIrSendJson(void)
|
|||
uint16_t bits = root.getUInt(PSTR(D_JSON_IR_BITS), 0);
|
||||
uint64_t data = root.getULong(PSTR(D_JSON_IR_DATA), 0);
|
||||
uint16_t repeat = root.getUInt(PSTR(D_JSON_IR_REPEAT), 0);
|
||||
#endif
|
||||
|
||||
// check if the IRSend<x> is great than repeat
|
||||
if (XdrvMailbox.index > repeat + 1) {
|
||||
repeat = XdrvMailbox.index - 1;
|
||||
|
@ -257,7 +234,6 @@ void CmndIrSend(void)
|
|||
uint8_t error = IE_SYNTAX_IRSEND;
|
||||
|
||||
if (XdrvMailbox.data_len) {
|
||||
// error = (strstr(XdrvMailbox.data, "{") == nullptr) ? IrRemoteCmndIrSendRaw() : IrRemoteCmndIrSendJson();
|
||||
if (strstr(XdrvMailbox.data, "{") == nullptr) {
|
||||
error = IE_INVALID_JSON;
|
||||
} else {
|
||||
|
|
|
@ -111,38 +111,39 @@ void IrReceiveInit(void)
|
|||
}
|
||||
|
||||
String sendACJsonState(const stdAc::state_t &state) {
|
||||
DynamicJsonBuffer jsonBuffer;
|
||||
JsonObject& json = jsonBuffer.createObject();
|
||||
json[D_JSON_IRHVAC_VENDOR] = typeToString(state.protocol);
|
||||
json[D_JSON_IRHVAC_MODEL] = state.model;
|
||||
json[D_JSON_IRHVAC_POWER] = IRac::boolToString(state.power);
|
||||
json[D_JSON_IRHVAC_MODE] = IRac::opmodeToString(state.mode);
|
||||
JsonGeneratorObject json;
|
||||
json.add(PSTR(D_JSON_IRHVAC_VENDOR), typeToString(state.protocol));
|
||||
json.add(PSTR(D_JSON_IRHVAC_MODEL), state.model);
|
||||
|
||||
// Home Assistant wants mode to be off if power is also off & vice-versa.
|
||||
if (state.mode == stdAc::opmode_t::kOff || !state.power) {
|
||||
json[D_JSON_IRHVAC_MODE] = IRac::opmodeToString(stdAc::opmode_t::kOff);
|
||||
json[D_JSON_IRHVAC_POWER] = IRac::boolToString(false);
|
||||
}
|
||||
json[D_JSON_IRHVAC_CELSIUS] = IRac::boolToString(state.celsius);
|
||||
if (floorf(state.degrees) == state.degrees) {
|
||||
json[D_JSON_IRHVAC_TEMP] = floorf(state.degrees); // integer
|
||||
json.add(PSTR(D_JSON_IRHVAC_MODE), IRac::opmodeToString(stdAc::opmode_t::kOff));
|
||||
json.add(PSTR(D_JSON_IRHVAC_POWER), IRac::boolToString(false));
|
||||
} else {
|
||||
json[D_JSON_IRHVAC_TEMP] = RawJson(String(state.degrees, 1)); // non-integer, limit to only 1 sub-digit
|
||||
json.add(PSTR(D_JSON_IRHVAC_MODE), IRac::opmodeToString(state.mode));
|
||||
json.add(PSTR(D_JSON_IRHVAC_POWER), IRac::boolToString(state.power));
|
||||
}
|
||||
json.add(PSTR(D_JSON_IRHVAC_CELSIUS), IRac::boolToString(state.celsius));
|
||||
if (floorf(state.degrees) == state.degrees) {
|
||||
json.add(PSTR(D_JSON_IRHVAC_TEMP), (int32_t) floorf(state.degrees)); // integer
|
||||
} else {
|
||||
// TODO can do better here
|
||||
json.addStrRaw(PSTR(D_JSON_IRHVAC_TEMP), String(state.degrees, 1).c_str()); // non-integer, limit to only 1 sub-digit
|
||||
}
|
||||
json[D_JSON_IRHVAC_FANSPEED] = IRac::fanspeedToString(state.fanspeed);
|
||||
json[D_JSON_IRHVAC_SWINGV] = IRac::swingvToString(state.swingv);
|
||||
json[D_JSON_IRHVAC_SWINGH] = IRac::swinghToString(state.swingh);
|
||||
json[D_JSON_IRHVAC_QUIET] = IRac::boolToString(state.quiet);
|
||||
json[D_JSON_IRHVAC_TURBO] = IRac::boolToString(state.turbo);
|
||||
json[D_JSON_IRHVAC_ECONO] = IRac::boolToString(state.econo);
|
||||
json[D_JSON_IRHVAC_LIGHT] = IRac::boolToString(state.light);
|
||||
json[D_JSON_IRHVAC_FILTER] = IRac::boolToString(state.filter);
|
||||
json[D_JSON_IRHVAC_CLEAN] = IRac::boolToString(state.clean);
|
||||
json[D_JSON_IRHVAC_BEEP] = IRac::boolToString(state.beep);
|
||||
json[D_JSON_IRHVAC_SLEEP] = state.sleep;
|
||||
|
||||
String payload = "";
|
||||
payload.reserve(200);
|
||||
json.printTo(payload);
|
||||
json.add(PSTR(D_JSON_IRHVAC_FANSPEED), IRac::fanspeedToString(state.fanspeed));
|
||||
json.add(PSTR(D_JSON_IRHVAC_SWINGV), IRac::swingvToString(state.swingv));
|
||||
json.add(PSTR(D_JSON_IRHVAC_SWINGH), IRac::swinghToString(state.swingh));
|
||||
json.add(PSTR(D_JSON_IRHVAC_QUIET), IRac::boolToString(state.quiet));
|
||||
json.add(PSTR(D_JSON_IRHVAC_TURBO), IRac::boolToString(state.turbo));
|
||||
json.add(PSTR(D_JSON_IRHVAC_ECONO), IRac::boolToString(state.econo));
|
||||
json.add(PSTR(D_JSON_IRHVAC_LIGHT), IRac::boolToString(state.light));
|
||||
json.add(PSTR(D_JSON_IRHVAC_FILTER), IRac::boolToString(state.filter));
|
||||
json.add(PSTR(D_JSON_IRHVAC_CLEAN), IRac::boolToString(state.clean));
|
||||
json.add(PSTR(D_JSON_IRHVAC_BEEP), IRac::boolToString(state.beep));
|
||||
json.add(PSTR(D_JSON_IRHVAC_SLEEP), state.sleep);
|
||||
|
||||
String payload = json.toString(); // copy string before returning, the original is on the stack
|
||||
return payload;
|
||||
}
|
||||
|
||||
|
@ -311,12 +312,9 @@ uint32_t IrRemoteCmndIrHvacJson(void)
|
|||
state.clean = false; // Turn off any Cleaning options if we can.
|
||||
state.clock = -1; // Don't set any current time if we can avoid it.
|
||||
|
||||
if (root[PSTR(D_JSON_IRHVAC_VENDOR)]) { state.protocol = strToDecodeType(root.getStr(PSTR(D_JSON_IRHVAC_VENDOR), "")); }
|
||||
if (root[PSTR(D_JSON_IRHVAC_PROTOCOL)]) { state.protocol = strToDecodeType(root.getStr(PSTR(D_JSON_IRHVAC_PROTOCOL), "")); }
|
||||
// UpperCase_P(parm_uc, PSTR(D_JSON_IRHVAC_VENDOR));
|
||||
// if (json.containsKey(parm_uc)) { state.protocol = strToDecodeType(json[parm_uc]); }
|
||||
// UpperCase_P(parm_uc, PSTR(D_JSON_IRHVAC_PROTOCOL));
|
||||
// if (json.containsKey(parm_uc)) { state.protocol = strToDecodeType(json[parm_uc]); } // also support 'protocol'
|
||||
JsonParserToken val;
|
||||
if (val = root[PSTR(D_JSON_IRHVAC_VENDOR)]) { state.protocol = strToDecodeType(val.getStr()); }
|
||||
if (val = root[PSTR(D_JSON_IRHVAC_PROTOCOL)]) { state.protocol = strToDecodeType(val.getStr()); }
|
||||
if (decode_type_t::UNKNOWN == state.protocol) { return IE_UNSUPPORTED_HVAC; }
|
||||
if (!IRac::isProtocolSupported(state.protocol)) { return IE_UNSUPPORTED_HVAC; }
|
||||
|
||||
|
@ -331,10 +329,10 @@ uint32_t IrRemoteCmndIrHvacJson(void)
|
|||
}
|
||||
}
|
||||
|
||||
if (root[PSTR(D_JSON_IRHVAC_MODEL)]) { state.model = IRac::strToModel(PSTR(D_JSON_IRHVAC_MODEL)); }
|
||||
if (root[PSTR(D_JSON_IRHVAC_MODE)]) { state.mode = IRac::strToOpmode(PSTR(D_JSON_IRHVAC_MODE)); }
|
||||
if (root[PSTR(D_JSON_IRHVAC_SWINGV)]) { state.swingv = IRac::strToSwingV(PSTR(D_JSON_IRHVAC_SWINGV)); }
|
||||
if (root[PSTR(D_JSON_IRHVAC_SWINGH)]) { state.swingh = IRac::strToSwingH(PSTR(D_JSON_IRHVAC_SWINGH)); }
|
||||
if (val = root[PSTR(D_JSON_IRHVAC_MODEL)]) { state.model = IRac::strToModel(val.getStr()); }
|
||||
if (val = root[PSTR(D_JSON_IRHVAC_MODE)]) { state.mode = IRac::strToOpmode(val.getStr()); }
|
||||
if (val = root[PSTR(D_JSON_IRHVAC_SWINGV)]) { state.swingv = IRac::strToSwingV(val.getStr()); }
|
||||
if (val = root[PSTR(D_JSON_IRHVAC_SWINGH)]) { state.swingh = IRac::strToSwingH(val.getStr()); }
|
||||
state.degrees = root.getFloat(PSTR(D_JSON_IRHVAC_TEMP), state.degrees);
|
||||
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("model %d, mode %d, fanspeed %d, swingv %d, swingh %d"),
|
||||
// state.model, state.mode, state.fanspeed, state.swingv, state.swingh);
|
||||
|
@ -378,40 +376,32 @@ void CmndIrHvac(void)
|
|||
|
||||
uint32_t IrRemoteCmndIrSendJson(void)
|
||||
{
|
||||
char parm_uc[12]; // used to convert JSON keys to uppercase
|
||||
// ArduinoJSON entry used to calculate jsonBuf: JSON_OBJECT_SIZE(3) + 40 = 96
|
||||
// IRsend { "protocol": "RC5", "bits": 12, "data":"0xC86" }
|
||||
// IRsend { "protocol": "SAMSUNG", "bits": 32, "data": 551502015 }
|
||||
char dataBufUc[XdrvMailbox.data_len + 1];
|
||||
UpperCase(dataBufUc, XdrvMailbox.data);
|
||||
RemoveSpace(dataBufUc);
|
||||
if (strlen(dataBufUc) < 8) { return IE_INVALID_JSON; }
|
||||
|
||||
DynamicJsonBuffer jsonBuf;
|
||||
JsonObject &json = jsonBuf.parseObject(dataBufUc);
|
||||
if (!json.success()) { return IE_INVALID_JSON; }
|
||||
RemoveSpace(XdrvMailbox.data); // TODO is this really needed?
|
||||
JsonParser parser(XdrvMailbox.data);
|
||||
JsonParserObject root = parser.getRootObject();
|
||||
if (!root) { return IE_INVALID_JSON; }
|
||||
|
||||
// IRsend { "protocol": "SAMSUNG", "bits": 32, "data": 551502015 }
|
||||
// IRsend { "protocol": "NEC", "bits": 32, "data":"0x02FDFE80", "repeat": 2 }
|
||||
decode_type_t protocol = decode_type_t::UNKNOWN;
|
||||
uint16_t bits = 0;
|
||||
uint64_t data;
|
||||
uint8_t repeat = 0;
|
||||
JsonParserToken value;
|
||||
|
||||
UpperCase_P(parm_uc, PSTR(D_JSON_IRHVAC_VENDOR));
|
||||
if (json.containsKey(parm_uc)) { protocol = strToDecodeType(json[parm_uc]); }
|
||||
UpperCase_P(parm_uc, PSTR(D_JSON_IRHVAC_PROTOCOL));
|
||||
if (json.containsKey(parm_uc)) { protocol = strToDecodeType(json[parm_uc]); } // also support 'protocol'
|
||||
decode_type_t protocol = decode_type_t::UNKNOWN;
|
||||
value = root[PSTR(D_JSON_IRHVAC_VENDOR)];
|
||||
if (root) { protocol = strToDecodeType(value.getStr()); }
|
||||
value = root[PSTR(D_JSON_IRHVAC_PROTOCOL)];
|
||||
if (root) { protocol = strToDecodeType(value.getStr()); }
|
||||
if (decode_type_t::UNKNOWN == protocol) { return IE_UNSUPPORTED_PROTOCOL; }
|
||||
|
||||
UpperCase_P(parm_uc, PSTR(D_JSON_IR_BITS));
|
||||
if (json.containsKey(parm_uc)) { bits = json[parm_uc]; }
|
||||
UpperCase_P(parm_uc, PSTR(D_JSON_IR_REPEAT));
|
||||
if (json.containsKey(parm_uc)) { repeat = json[parm_uc]; }
|
||||
UpperCase_P(parm_uc, PSTR(D_JSON_IR_DATALSB)); // accept LSB values
|
||||
if (json.containsKey(parm_uc)) { data = reverseBitsInBytes64(strtoull(json[parm_uc], nullptr, 0)); }
|
||||
UpperCase_P(parm_uc, PSTR(D_JSON_IR_DATA)); // or classical MSB (takes priority)
|
||||
if (json.containsKey(parm_uc)) { data = strtoull(json[parm_uc], nullptr, 0); }
|
||||
uint16_t bits = root.getUInt(PSTR(D_JSON_IR_BITS), 0);
|
||||
uint16_t repeat = root.getUInt(PSTR(D_JSON_IR_REPEAT), 0);
|
||||
|
||||
uint64_t data;
|
||||
value = root[PSTR(D_JSON_IR_DATALSB)];
|
||||
if (root) { data = reverseBitsInBytes64(value.getULong()); } // accept LSB values
|
||||
value = root[PSTR(D_JSON_IR_DATA)];
|
||||
if (value) { data = value.getULong(); } // or classical MSB (takes priority)
|
||||
if (0 == bits) { return IE_SYNTAX_IRSEND; }
|
||||
|
||||
// check if the IRSend<x> is greater than repeat, but can be overriden with JSON
|
||||
|
|
|
@ -337,90 +337,6 @@ void CmndTimer(void)
|
|||
Settings.timer[index -1].data = Settings.timer[XdrvMailbox.payload -1].data; // Copy timer
|
||||
}
|
||||
} else {
|
||||
#if 0
|
||||
//#ifndef USE_RULES
|
||||
#if defined(USE_RULES)==0 && defined(USE_SCRIPT)==0
|
||||
if (devices_present) {
|
||||
#endif
|
||||
char dataBufUc[XdrvMailbox.data_len + 1];
|
||||
UpperCase(dataBufUc, XdrvMailbox.data);
|
||||
StaticJsonBuffer<256> jsonBuffer;
|
||||
JsonObject& root = jsonBuffer.parseObject(dataBufUc);
|
||||
if (!root.success()) {
|
||||
Response_P(PSTR("{\"" D_CMND_TIMER "%d\":\"" D_JSON_INVALID_JSON "\"}"), index); // JSON decode failed
|
||||
error = 1;
|
||||
}
|
||||
else {
|
||||
char parm_uc[10];
|
||||
index--;
|
||||
if (root[UpperCase_P(parm_uc, PSTR(D_JSON_TIMER_ARM))].success()) {
|
||||
Settings.timer[index].arm = (root[parm_uc] != 0);
|
||||
}
|
||||
#ifdef USE_SUNRISE
|
||||
if (root[UpperCase_P(parm_uc, PSTR(D_JSON_TIMER_MODE))].success()) {
|
||||
Settings.timer[index].mode = (uint8_t)root[parm_uc] & 0x03;
|
||||
}
|
||||
#endif
|
||||
if (root[UpperCase_P(parm_uc, PSTR(D_JSON_TIMER_TIME))].success()) {
|
||||
uint16_t itime = 0;
|
||||
int8_t value = 0;
|
||||
uint8_t sign = 0;
|
||||
char time_str[10];
|
||||
|
||||
strlcpy(time_str, root[parm_uc], sizeof(time_str));
|
||||
const char *substr = strtok(time_str, ":");
|
||||
if (substr != nullptr) {
|
||||
if (strchr(substr, '-')) {
|
||||
sign = 1;
|
||||
substr++;
|
||||
}
|
||||
value = atoi(substr);
|
||||
if (sign) { value += 12; } // Allow entering timer offset from -11:59 to -00:01 converted to 12:01 to 23:59
|
||||
if (value > 23) { value = 23; }
|
||||
itime = value * 60;
|
||||
substr = strtok(nullptr, ":");
|
||||
if (substr != nullptr) {
|
||||
value = atoi(substr);
|
||||
if (value < 0) { value = 0; }
|
||||
if (value > 59) { value = 59; }
|
||||
itime += value;
|
||||
}
|
||||
}
|
||||
Settings.timer[index].time = itime;
|
||||
}
|
||||
if (root[UpperCase_P(parm_uc, PSTR(D_JSON_TIMER_WINDOW))].success()) {
|
||||
Settings.timer[index].window = (uint8_t)root[parm_uc] & 0x0F;
|
||||
TimerSetRandomWindow(index);
|
||||
}
|
||||
if (root[UpperCase_P(parm_uc, PSTR(D_JSON_TIMER_DAYS))].success()) {
|
||||
// SMTWTFS = 1234567 = 0011001 = 00TW00S = --TW--S
|
||||
Settings.timer[index].days = 0;
|
||||
const char *tday = root[parm_uc];
|
||||
uint8_t i = 0;
|
||||
char ch = *tday++;
|
||||
while ((ch != '\0') && (i < 7)) {
|
||||
if (ch == '-') { ch = '0'; }
|
||||
uint8_t mask = 1 << i++;
|
||||
Settings.timer[index].days |= (ch == '0') ? 0 : mask;
|
||||
ch = *tday++;
|
||||
}
|
||||
}
|
||||
if (root[UpperCase_P(parm_uc, PSTR(D_JSON_TIMER_REPEAT))].success()) {
|
||||
Settings.timer[index].repeat = (root[parm_uc] != 0);
|
||||
}
|
||||
if (root[UpperCase_P(parm_uc, PSTR(D_JSON_TIMER_OUTPUT))].success()) {
|
||||
uint8_t device = ((uint8_t)root[parm_uc] -1) & 0x0F;
|
||||
Settings.timer[index].device = (device < devices_present) ? device : 0;
|
||||
}
|
||||
if (root[UpperCase_P(parm_uc, PSTR(D_JSON_TIMER_ACTION))].success()) {
|
||||
uint8_t action = (uint8_t)root[parm_uc] & 0x03;
|
||||
Settings.timer[index].power = (devices_present) ? action : 3; // If no devices than only allow rules
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
//#ifndef USE_RULES
|
||||
#else
|
||||
//#ifndef USE_RULES
|
||||
#if defined(USE_RULES)==0 && defined(USE_SCRIPT)==0
|
||||
if (devices_present) {
|
||||
|
@ -509,7 +425,6 @@ void CmndTimer(void)
|
|||
index++;
|
||||
}
|
||||
//#ifndef USE_RULES
|
||||
#endif
|
||||
#if defined(USE_RULES)==0 && defined(USE_SCRIPT)==0
|
||||
} else {
|
||||
Response_P(PSTR("{\"" D_CMND_TIMER "%d\":\"" D_JSON_TIMER_NO_DEVICE "\"}"), index); // No outputs defined so nothing to control
|
||||
|
|
|
@ -497,40 +497,6 @@ bool RulesRuleMatch(uint8_t rule_set, String &event, String &rule)
|
|||
rule_name = rule_name.substring(0, pos); // "SUBTYPE1#CURRENT"
|
||||
}
|
||||
|
||||
#if 0
|
||||
// StaticJsonBuffer<1280> jsonBuf; // Was 1024 until 20200811
|
||||
DynamicJsonBuffer jsonBuf; // Was static until 20200812
|
||||
JsonObject &root = jsonBuf.parseObject(event);
|
||||
if (!root.success()) {
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("RUL: Event too long (%d)"), event.length());
|
||||
return false;
|
||||
} // No valid JSON data
|
||||
JsonObject *obj = &root;
|
||||
String subtype;
|
||||
uint32_t i = 0;
|
||||
while ((pos = rule_name.indexOf("#")) > 0) { // "SUBTYPE1#SUBTYPE2#CURRENT"
|
||||
subtype = rule_name.substring(0, pos);
|
||||
const JsonVariant & val = GetCaseInsensitive(*obj, subtype.c_str());
|
||||
if (nullptr == &val) { return false; } // not found
|
||||
obj = &(val.as<JsonObject>());
|
||||
if (!obj->success()) { return false; } // not a JsonObject
|
||||
|
||||
rule_name = rule_name.substring(pos +1);
|
||||
if (i++ > 10) { return false; } // Abandon possible loop
|
||||
|
||||
yield();
|
||||
}
|
||||
|
||||
const JsonVariant & val = GetCaseInsensitive(*obj, rule_name.c_str());
|
||||
if (nullptr == &val) { return false; } // last level not found
|
||||
const char* str_value;
|
||||
if (rule_name_idx) {
|
||||
str_value = (*obj)[rule_name][rule_name_idx -1]; // "CURRENT[1]"
|
||||
} else {
|
||||
str_value = (*obj)[rule_name]; // "CURRENT"
|
||||
}
|
||||
#else
|
||||
|
||||
String buf = event; // copy the string into a new buffer that will be modified
|
||||
JsonParser parser((char*)buf.c_str());
|
||||
JsonParserObject obj = parser.getRootObject();
|
||||
|
@ -563,8 +529,6 @@ bool RulesRuleMatch(uint8_t rule_set, String &event, String &rule)
|
|||
} else {
|
||||
str_value = val.getStr(); // "CURRENT"
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//AddLog_P2(LOG_LEVEL_DEBUG, PSTR("RUL: Name %s, Value |%s|, TrigCnt %d, TrigSt %d, Source %s, Json %s"),
|
||||
// rule_name.c_str(), rule_svalue, Rules.trigger_count[rule_set], bitRead(Rules.triggers[rule_set], Rules.trigger_count[rule_set]), event.c_str(), (str_value) ? str_value : "none");
|
||||
|
|
Loading…
Reference in New Issue