From e6e3497c4054cdaf0df5d2e21bbbcdb5327f15d8 Mon Sep 17 00:00:00 2001 From: Dmitry Borisenko <67171972+IoTManagerProject@users.noreply.github.com> Date: Fri, 14 Jan 2022 21:48:43 +0100 Subject: [PATCH] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20?= =?UTF-8?q?=D1=81=D1=86=D0=B5=D0=BD=D0=B0=D1=80=D0=B8=D0=B8=20=D0=B8=20?= =?UTF-8?q?=D0=BA=D0=BB=D0=B0=D1=81=D1=81=20=D1=81=D0=B5=D0=BD=D1=81=D0=BE?= =?UTF-8?q?=D1=80=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/Buffers.h | 7 + include/Global.h | 7 + include/Main.h | 1 - include/classes/IoTSensor.h | 26 ++ include/classes/ScenarioClass3.h | 255 ++++++++++++++++++++ include/utils/Pretty.h | 4 - include/utils/StringUtils.h | 39 +++ lib/ESP8266-StringCommand/StringCommand.cpp | 137 +++++++++++ lib/ESP8266-StringCommand/StringCommand.h | 77 ++++++ lib/ESP8266-StringCommand/keywords.txt | 23 ++ lib/ESP8266-StringCommand/readme.md | 5 + src/AsyncWebServer.cpp | 2 +- src/Buffers.cpp | 46 ++++ src/Config.cpp | 2 + src/Global.cpp | 5 + src/classes/IoTSensor.cpp | 39 +++ src/classes/ScenarioClass3.cpp | 3 + src/utils/Pretty.cpp | 12 - src/utils/StringUtils.cpp | 170 +++++++++++++ src/utils/TimeUtils.cpp | 30 +-- 20 files changed, 857 insertions(+), 33 deletions(-) create mode 100644 include/Buffers.h create mode 100644 include/classes/IoTSensor.h create mode 100644 include/classes/ScenarioClass3.h delete mode 100644 include/utils/Pretty.h create mode 100644 include/utils/StringUtils.h create mode 100644 lib/ESP8266-StringCommand/StringCommand.cpp create mode 100644 lib/ESP8266-StringCommand/StringCommand.h create mode 100644 lib/ESP8266-StringCommand/keywords.txt create mode 100644 lib/ESP8266-StringCommand/readme.md create mode 100644 src/Buffers.cpp create mode 100644 src/classes/IoTSensor.cpp create mode 100644 src/classes/ScenarioClass3.cpp delete mode 100644 src/utils/Pretty.cpp create mode 100644 src/utils/StringUtils.cpp diff --git a/include/Buffers.h b/include/Buffers.h new file mode 100644 index 00000000..78026740 --- /dev/null +++ b/include/Buffers.h @@ -0,0 +1,7 @@ +#pragma once +#include "Global.h" +#include "MqttClient.h" + +void eventGen2(String eventName, String eventValue); +extern void spaceCmdExecute(String &cmdStr); +extern String getValueJson(String &key); \ No newline at end of file diff --git a/include/Global.h b/include/Global.h index 375cfa9e..b7534005 100644 --- a/include/Global.h +++ b/include/Global.h @@ -7,6 +7,7 @@ #include #include #include +#include #ifdef ESP32 #include "WiFi.h" @@ -46,6 +47,7 @@ #include "Utils/FileUtils.h" #include "Utils/JsonUtils.h" #include "Utils/SerialPrint.h" +#include "Utils/StringUtils.h" /********************************************************************************************************************* *****************************************глобальные объекты классов*************************************************** @@ -54,6 +56,7 @@ extern TickerScheduler ts; extern WiFiClient espClient; extern PubSubClient mqtt; +extern StringCommand sCmd; #ifdef ASYNC_WEB_SERVER extern AsyncWebServer server; #endif @@ -79,6 +82,10 @@ extern String settingsFlashJson; extern String paramsFlashJson; extern String paramsHeapJson; +// buf +extern String orderBuf; +extern String eventBuf; + // Mqtt extern String mqttServer; extern int mqttPort; diff --git a/include/Main.h b/include/Main.h index 3579eddc..1bab4924 100644 --- a/include/Main.h +++ b/include/Main.h @@ -2,7 +2,6 @@ // #include "EspFileSystem.h" #include "Global.h" -#include "Utils/Pretty.h" #include "Utils/WiFiUtils.h" #include "AsyncWebServer.h" #include "StandWebServer.h" diff --git a/include/classes/IoTSensor.h b/include/classes/IoTSensor.h new file mode 100644 index 00000000..f4fb061c --- /dev/null +++ b/include/classes/IoTSensor.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +class IoTSensor { + public: + IoTSensor(); + ~IoTSensor(); + + void loop(); + virtual void doByInterval(); + void init(String key, String id, unsigned long interval); + void regEvent(String value, String consoleInfo); + + String getKey(); + String getID(); + + unsigned long currentMillis; + unsigned long prevMillis; + unsigned long difference; + + protected: + String _key; + String _id; + unsigned long _interval; +}; \ No newline at end of file diff --git a/include/classes/ScenarioClass3.h b/include/classes/ScenarioClass3.h new file mode 100644 index 00000000..4e25cc83 --- /dev/null +++ b/include/classes/ScenarioClass3.h @@ -0,0 +1,255 @@ +#pragma once +#include "Global.h" +#include "MqttClient.h" +#include "Buffers.h" + +class Scenario { + public: + void loop2() { + if (!jsonReadBool(settingsFlashJson, "scen")) { + return; + } + String allBlocks = scenario; + allBlocks += "\n"; + + String incommingEvent = selectToMarker(eventBuf, ","); + + String incommingEventKey = selectToMarker(incommingEvent, " "); + String incommingEventValue = selectToMarkerLast(incommingEvent, " "); + + while (allBlocks.length()) { + String oneBlock = selectToMarker(allBlocks, "end\n"); + String condition = selectToMarker(oneBlock, "\n"); + + //логическое и + if (condition.indexOf("&&") != -1) { + condition = condition += " && "; + + //посчитаем количество условий + int conditionCnt = itemsCount2(condition, "&&") - 1; + + //создадим и заполним динамический массив + bool *arr = new bool[conditionCnt]; + for (int i = 0; i < conditionCnt; i++) { + arr[i] = false; + } + + //есть ли входящее событие хотя бы в одном из условий и удавлетварено ли оно? + int evenInConditionNum = -1; + for (int i = 0; i < conditionCnt; i++) { + String buf = selectFromMarkerToMarker(condition, " && ", i); + if (isScenarioNeedToDo(buf, incommingEventKey, incommingEventValue, 1)) { + arr[i] = true; + evenInConditionNum = i; + } + } + + //если да то проверяем остальные условия по json + if (evenInConditionNum >= 0) { + for (int i = 0; i < conditionCnt; i++) { + String buf = selectFromMarkerToMarker(condition, " && ", i); + if (i != evenInConditionNum) { + if (isScenarioNeedToDoJson(buf)) { + arr[i] = true; + } + } + } + } + + //все элементы массива должны быть true + bool result = true; + for (int i = 0; i < conditionCnt; i++) { + if (!arr[i]) { + result = false; + } + } + + delete[] arr; + + if (result) { + oneBlock = deleteBeforeDelimiter(oneBlock, "\n"); + oneBlock.replace("end", ""); + + // SerialPrint("I", "Event done", incommingEvent); + SerialPrint("I", F("Scenario"), F("All conditions are matched")); + spaceCmdExecute(oneBlock); + } + + //логическое или + } else if (condition.indexOf("||") != -1) { + condition = condition += " || "; + + //посчитаем количество условий + int conditionCnt = itemsCount2(condition, "||") - 1; + + //создадим и заполним динамический массив + bool *arr = new bool[conditionCnt]; + for (int i = 0; i < conditionCnt; i++) { + arr[i] = false; + } + + //есть ли входящее событие хотя бы в одном из условий и удавлетварено ли оно? + int evenInConditionNum = -1; + for (int i = 0; i < conditionCnt; i++) { + String buf = selectFromMarkerToMarker(condition, " || ", i); + if (isScenarioNeedToDo(buf, incommingEventKey, incommingEventValue, 1)) { + arr[i] = true; + evenInConditionNum = i; + } + } + + //если да то проверяем остальные условия по json + if (evenInConditionNum >= 0) { + for (int i = 0; i < conditionCnt; i++) { + String buf = selectFromMarkerToMarker(condition, " || ", i); + if (i != evenInConditionNum) { + if (isScenarioNeedToDoJson(buf)) { + arr[i] = true; + } + } + } + } + + //хотя бы один элемент массива должн быть true + bool result = false; + for (int i = 0; i < conditionCnt; i++) { + if (arr[i]) { + result = true; + } + } + + delete[] arr; + + if (result) { + oneBlock = deleteBeforeDelimiter(oneBlock, "\n"); + oneBlock.replace("end", ""); + + // SerialPrint("I", "Event done", incommingEvent); + SerialPrint("I", F("Scenario"), F("One of all condition are matched")); + spaceCmdExecute(oneBlock); + } + + //если гистерезис + } else if (condition.indexOf("+-") != -1) { + if (isScenarioNeedToDo(condition, incommingEventKey, incommingEventValue, 2)) { + oneBlock = deleteBeforeDelimiter(oneBlock, "\n"); + oneBlock.replace("end", ""); + + // SerialPrint("I", "Event done", incommingEvent); + SerialPrint("I", F("Scenario"), "Condition are matched: " + condition); + spaceCmdExecute(oneBlock); + } + + //остальные случаи + } else { + if (isScenarioNeedToDo(condition, incommingEventKey, incommingEventValue, 1)) { + oneBlock = deleteBeforeDelimiter(oneBlock, "\n"); + oneBlock.replace("end", ""); + + // SerialPrint("I", "Event done", incommingEvent); + SerialPrint("I", F("Scenario"), "Condition are matched: " + condition); + spaceCmdExecute(oneBlock); + } + } + allBlocks = deleteBeforeDelimiter(allBlocks, "end\n"); + } + eventBuf = deleteBeforeDelimiter(eventBuf, ","); + } + + private: + bool isScenarioNeedToDo(String &condition, String &incommingEventKey, String &incommingEventValue, int type) { + bool res = false; + String setEventKey = selectFromMarkerToMarker(condition, " ", 0); + if (isEventExist(incommingEventKey, setEventKey)) { + String setEventSign; + String setEventValue; + if (type == 1) preCalculation(condition, setEventSign, setEventValue); + if (type == 2) preCalculationGisteresis(condition, setEventSign, setEventValue); + if (isConditionMatch(setEventSign, incommingEventValue, setEventValue)) { + res = true; + } + } + return res; + } + + bool isScenarioNeedToDoJson(String &condition) { + bool res = false; + String setEventKey = selectFromMarkerToMarker(condition, " ", 0); + String setEventSign; + String setEventValue; + preCalculation(condition, setEventSign, setEventValue); + String jsonValue = getValueJson(setEventKey); + if (isConditionMatch(setEventSign, jsonValue, setEventValue)) { + res = true; + } + return res; + } + + // bool isScenarioNeedToDoJson2(String &condition, String &incommingEventKey, String &incommingEventValue) { + // bool res = false; + // String setEventKey = selectFromMarkerToMarker(condition, " ", 0); + // if (isEventExist(incommingEventKey, setEventKey)) { + // String setEventSign; + // String setEventValue; + // preCalculation(condition, setEventSign, setEventValue); + // if (isConditionMatch(setEventSign, incommingEventValue, setEventValue)) { + // res = true; + // } + // } + // return res; + // } + + void preCalculation(String &condition, String &setEventSign, String &setEventValue) { + setEventSign = selectFromMarkerToMarker(condition, " ", 1); + setEventValue = selectFromMarkerToMarker(condition, " ", 2); + if (!isDigitDotCommaStr(setEventValue)) { + setEventValue = getValueJson(setEventValue); + } + } + + void preCalculationGisteresis(String &condition, String &setEventSign, String &setEventValue) { + setEventSign = selectFromMarkerToMarker(condition, " ", 1); + setEventValue = selectFromMarkerToMarker(condition, " ", 2); + if (!isDigitDotCommaStr(setEventValue)) { + String setEventValueName = selectToMarker(setEventValue, "+-"); + String gisteresisValue = selectToMarkerLast(setEventValue, "+-"); + gisteresisValue.replace("+-", ""); + String value = getValueJson(setEventValueName); + String upValue = String(value.toFloat() + gisteresisValue.toFloat()); + String lowValue = String(value.toFloat() - gisteresisValue.toFloat()); + if (setEventSign == ">") { + setEventValue = upValue; + } else if (setEventSign == "<") { + setEventValue = lowValue; + } + } + } + + bool isEventExist(String &incommingEventKey, String &setEventKey) { + bool res = false; + if (incommingEventKey == setEventKey) { + res = true; + } + return res; + } + + bool isConditionMatch(String &setEventSign, String &incommingEventValue, String &setEventValue) { + boolean flag = false; + if (setEventSign == "=") { + flag = incommingEventValue == setEventValue; + } else if (setEventSign == "!=") { + flag = incommingEventValue != setEventValue; + } else if (setEventSign == "<") { + flag = incommingEventValue.toFloat() < setEventValue.toFloat(); + } else if (setEventSign == ">") { + flag = incommingEventValue.toFloat() > setEventValue.toFloat(); + } else if (setEventSign == ">=") { + flag = incommingEventValue.toFloat() >= setEventValue.toFloat(); + } else if (setEventSign == "<=") { + flag = incommingEventValue.toFloat() <= setEventValue.toFloat(); + } + return flag; + } +}; + +extern Scenario *myScenario; diff --git a/include/utils/Pretty.h b/include/utils/Pretty.h deleted file mode 100644 index b5235955..00000000 --- a/include/utils/Pretty.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once -#include "Global.h" - -String prettyBytes(size_t size); \ No newline at end of file diff --git a/include/utils/StringUtils.h b/include/utils/StringUtils.h new file mode 100644 index 00000000..816baf8d --- /dev/null +++ b/include/utils/StringUtils.h @@ -0,0 +1,39 @@ +#pragma once + +#include "Global.h" + +void hex2string(byte array[], unsigned int len, char buffer[]); + +int string2hex(const char* str, unsigned char* bytes); + +uint8_t hexStringToUint8(String hex); + +uint16_t hexStringToUint16(String hex); + +String selectToMarkerLast(String str, String found); + +String selectToMarker(String str, String found); + +String extractInner(String str); + +String deleteAfterDelimiter(String str, String found); + +String deleteBeforeDelimiter(String str, String found); + +String deleteBeforeDelimiterTo(String str, String found); + +String deleteToMarkerLast(String str, String found); + +String selectFromMarkerToMarker(String str, String found, int number); + +size_t itemsCount2(String str, const String& separator); + +char* stringToChar(String& str); + +size_t itemsCount(String& str, const char* delim); + +boolean isDigitStr(const String& str); + +boolean isDigitDotCommaStr(const String& str); + +String prettyBytes(size_t size); diff --git a/lib/ESP8266-StringCommand/StringCommand.cpp b/lib/ESP8266-StringCommand/StringCommand.cpp new file mode 100644 index 00000000..3d53dcd7 --- /dev/null +++ b/lib/ESP8266-StringCommand/StringCommand.cpp @@ -0,0 +1,137 @@ +/** + * SerialCommand - A Wiring/Arduino library to tokenize and parse commands + * received over a serial port. + * + * Copyright (C) 2012 Stefan Rado + * Copyright (C) 2011 Steven Cogswell + * http://husks.wordpress.com + * + * Version 20120522 + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this library. If not, see . + */ +#include "StringCommand.h" + +/** + * Constructor makes sure some things are set. + */ +StringCommand::StringCommand() + : commandList(NULL), + commandCount(0), + defaultHandler(NULL), + term('\n'), // default terminator for commands, newline character + last(NULL), + main(NULL) +{ + strcpy(delim, " "); // strtok_r needs a null-terminated string + clearBuffer(); +} + +/** + * Adds a "command" and a handler function to the list of available commands. + * This is used for matching a found token in the buffer, and gives the pointer + * to the handler function to deal with it. + */ +void StringCommand::addCommand(const char *command, void (*function)()) { + #ifdef SERIALCOMMAND_DEBUG + Serial.print("Adding command ("); + Serial.print(commandCount); + Serial.print("): "); + Serial.println(command); + #endif + + commandList = (StringCommandCallback *) realloc(commandList, (commandCount + 1) * sizeof(StringCommandCallback)); + strncpy(commandList[commandCount].command, command, SERIALCOMMAND_MAXCOMMANDLENGTH); + commandList[commandCount].function = function; + commandCount++; +} + +/** + * This sets up a handler to be called in the event that the receveived command string + * isn't in the list of commands. + */ +void StringCommand::setDefaultHandler(void (*function)(const char *)) { + defaultHandler = function; +} + + +/** + * This checks the Serial stream for characters, and assembles them into a buffer. + * When the terminator character (default '\n') is seen, it starts parsing the + * buffer for a prefix command, and calls handlers setup by addCommand() member + */ +void StringCommand::readStr(String sBuffer ) { + sBuffer.toCharArray(buffer, SERIALCOMMAND_BUFFER); + #ifdef SERIALCOMMAND_DEBUG + Serial.print("Received: "); + Serial.println(buffer); + #endif + + char *command = strtok_r(buffer, delim, &last); // Search for command at start of buffer + if (command != NULL) { + boolean matched = false; + for (int i = 0; i < commandCount; i++) { + #ifdef SERIALCOMMAND_DEBUG + Serial.print("Comparing ["); + Serial.print(command); + Serial.print("] to ["); + Serial.print(commandList[i].command); + Serial.println("]"); + #endif + + + + // Compare the found command against the list of known commands for a match + if (strncmp(command, commandList[i].command, SERIALCOMMAND_MAXCOMMANDLENGTH) == 0) { + #ifdef SERIALCOMMAND_DEBUG + Serial.print("Matched Command: "); + Serial.println(command); + #endif + + // Execute the stored handler function for the command + (*commandList[i].function)(); + matched = true; + break; + } + } + + + if (!matched && (defaultHandler != NULL)) { + (*defaultHandler)(command); + } + + + clearBuffer(); + } +} + +/* + * Clear the input buffer. + */ +void StringCommand::clearBuffer() { + buffer[0] = '\0'; + bufPos = 0; +} + +/** + * Retrieve the next token ("word" or "argument") from the command buffer. + * Returns NULL if no more tokens exist. + */ +char *StringCommand::next() { + return strtok_r(NULL, delim, &last); +} + +char *StringCommand::order() { + return strtok_r(buffer, delim, &main); +} diff --git a/lib/ESP8266-StringCommand/StringCommand.h b/lib/ESP8266-StringCommand/StringCommand.h new file mode 100644 index 00000000..b37d5a1a --- /dev/null +++ b/lib/ESP8266-StringCommand/StringCommand.h @@ -0,0 +1,77 @@ +/** + * SerialCommand - A Wiring/Arduino library to tokenize and parse commands + * received over a serial port. + * + * Copyright (C) 2012 Stefan Rado + * Copyright (C) 2011 Steven Cogswell + * http://husks.wordpress.com + * + * Version 20120522 + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this library. If not, see . + */ +#ifndef StringCommand_h +#define StringCommand_h + +#if defined(WIRING) && WIRING >= 100 + #include +#elif defined(ARDUINO) && ARDUINO >= 100 + #include +#else + #include +#endif +#include + +// Size of the input buffer in bytes (maximum length of one command plus arguments) +#define SERIALCOMMAND_BUFFER 128 //256 +// Maximum length of a command excluding the terminating null +#define SERIALCOMMAND_MAXCOMMANDLENGTH 16 + +// Uncomment the next line to run the library in debug mode (verbose messages) +//#define SERIALCOMMAND_DEBUG + + +class StringCommand { + public: + StringCommand(); // Constructor + void addCommand(const char *command, void(*function)()); // Add a command to the processing dictionary. + void setDefaultHandler(void (*function)(const char *)); // A handler to call when no valid command received. + + void readStr(String sBuffer ); // Main entry point. + void clearBuffer(); // Clears the input buffer. + char *next(); // Returns pointer to next token found in command buffer (for getting arguments to commands). + char *order(); + + private: + // Command/handler dictionary + struct StringCommandCallback { + char command[SERIALCOMMAND_MAXCOMMANDLENGTH + 1]; + void (*function)(); + }; // Data structure to hold Command/Handler function key-value pairs + StringCommandCallback *commandList; // Actual definition for command/handler array + byte commandCount; + + // Pointer to the default handler function + void (*defaultHandler)(const char *); + + char delim[2]; // null-terminated list of character to be used as delimeters for tokenizing (default " ") + char term; // Character that signals end of command (default '\n') + + char buffer[SERIALCOMMAND_BUFFER + 1]; // Buffer of stored characters while waiting for terminator character + byte bufPos; // Current position in the buffer + char *last; // State variable used by strtok_r during processing + char *main; +}; + +#endif //StringCommand_h diff --git a/lib/ESP8266-StringCommand/keywords.txt b/lib/ESP8266-StringCommand/keywords.txt new file mode 100644 index 00000000..c9799b2c --- /dev/null +++ b/lib/ESP8266-StringCommand/keywords.txt @@ -0,0 +1,23 @@ +####################################### +# Datatypes (KEYWORD1) +####################################### + +StringCommand KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +addCommand KEYWORD2 +setDefaultHandler KEYWORD2 +readString KEYWORD2 +clearBuffer KEYWORD2 +next KEYWORD2 + +####################################### +# Instances (KEYWORD2) +####################################### + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/lib/ESP8266-StringCommand/readme.md b/lib/ESP8266-StringCommand/readme.md new file mode 100644 index 00000000..731ee5e2 --- /dev/null +++ b/lib/ESP8266-StringCommand/readme.md @@ -0,0 +1,5 @@ +StringCommand +============= +Библиотека для ESP8266 позволяющая связать запуск пользовательских функций с строковой переменной. + + diff --git a/src/AsyncWebServer.cpp b/src/AsyncWebServer.cpp index 6e4522c4..e6375dc1 100644 --- a/src/AsyncWebServer.cpp +++ b/src/AsyncWebServer.cpp @@ -42,7 +42,7 @@ void asyncWebServerInit() { // динамические данные // server.on("/config.live.json", HTTP_GET, [](AsyncWebServerRequest *request) { - // request->send(200, "application/json", configLiveJson); + // request->send(200, "application/json", paramsFlashJson); //}); // // server.on("/config.store.json", HTTP_GET, [](AsyncWebServerRequest *request) { diff --git a/src/Buffers.cpp b/src/Buffers.cpp new file mode 100644 index 00000000..bcdd3cce --- /dev/null +++ b/src/Buffers.cpp @@ -0,0 +1,46 @@ +#include "Buffers.h" + +//генеирует событие +void eventGen2(String eventName, String eventValue) { + if (!jsonReadBool(settingsFlashJson, "scen")) { + return; + } + String event = eventName + " " + eventValue + ","; + eventBuf += event; + + SerialPrint("I", "Event add", eventName + " " + eventValue); + + if (jsonReadBool(settingsFlashJson, "MqttOut")) { + if (eventName != "timenow") { + publishEvent(eventName, eventValue); + } + } +} + +void spaceCmdExecute(String& cmdStr) { + cmdStr += "\r\n"; + cmdStr.replace("\r\n", "\n"); + cmdStr.replace("\r", "\n"); + while (cmdStr.length()) { + String buf = selectToMarker(cmdStr, "\n"); + if (buf != "") { + sCmd.readStr(buf); + SerialPrint("I", F("Order done W"), buf); + } + cmdStr = deleteBeforeDelimiter(cmdStr, "\n"); + } +} + +String getValueJson(String& key) { + String live = jsonReadStr(paramsHeapJson, key); + String store = jsonReadStr(paramsFlashJson, key); + if (live != nullptr) { + return live; + } else if (store != nullptr) { + return store; + } else if (store == nullptr && live == nullptr) { + return "no value"; + } else { + return "data error"; + } +} diff --git a/src/Config.cpp b/src/Config.cpp index fd52db65..6b20f4b0 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -10,6 +10,8 @@ void configure(String& path) { //============================= } else if (value == F("pwm-out")) { //============================= + } else if (value == F("analog-adc")) { + //============================= } else { SerialPrint(F("E"), F("Config"), F("config.json error, type not exist")); } diff --git a/src/Global.cpp b/src/Global.cpp index d45bff58..26c346ea 100644 --- a/src/Global.cpp +++ b/src/Global.cpp @@ -7,6 +7,7 @@ TickerScheduler ts(MYTEST + 1); WiFiClient espClient; PubSubClient mqtt(espClient); +StringCommand sCmd; #ifdef ASYNC_WEB_SERVER AsyncWebServer server(80); #endif @@ -33,6 +34,10 @@ String settingsFlashJson = "{}"; //переменная в которой хр String paramsFlashJson = "{}"; //переменная в которой хранятся все параметры, находится в оперативной памяти и синхронизированна с flash памятью String paramsHeapJson = "{}"; //переменная в которой хранятся все параметры, находится в оперативной памяти только +// buf +String orderBuf = ""; +String eventBuf = ""; + // Mqtt String mqttServer = ""; int mqttPort = 0; diff --git a/src/classes/IoTSensor.cpp b/src/classes/IoTSensor.cpp new file mode 100644 index 00000000..07db9b67 --- /dev/null +++ b/src/classes/IoTSensor.cpp @@ -0,0 +1,39 @@ +#include "Utils/JsonUtils.h" +#include "Utils/SerialPrint.h" +#include "Classes/ScenarioClass3.h" +#include "Classes/IoTSensor.h" + +void IoTSensor::init(String key, String id, unsigned long interval) { + _interval = interval * 1000; + _key = key; + _id = id; +} + +IoTSensor::IoTSensor() {} +IoTSensor::~IoTSensor() {} + +String IoTSensor::getKey() { + return _key; +} + +String IoTSensor::getID() { + return _id; +}; + +void IoTSensor::loop() { + currentMillis = millis(); + difference = currentMillis - prevMillis; + if (difference >= _interval) { + prevMillis = millis(); + this->doByInterval(); + } +} + +void IoTSensor::regEvent(String value, String consoleInfo = "") { + eventGen2(_id, String(value)); + jsonWriteStr(paramsFlashJson, _id, String(value)); + publishStatus(_id, String(value)); + SerialPrint("I", "Sensor", "'" + _id + "' data: " + String(value) + "' " + consoleInfo); +} + +void IoTSensor::doByInterval() {} \ No newline at end of file diff --git a/src/classes/ScenarioClass3.cpp b/src/classes/ScenarioClass3.cpp new file mode 100644 index 00000000..5d638b9b --- /dev/null +++ b/src/classes/ScenarioClass3.cpp @@ -0,0 +1,3 @@ +#include "Classes/ScenarioClass3.h" + +Scenario* myScenario; diff --git a/src/utils/Pretty.cpp b/src/utils/Pretty.cpp deleted file mode 100644 index a0e8b453..00000000 --- a/src/utils/Pretty.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "Utils/Pretty.h" - -String prettyBytes(size_t size) { - if (size < 1024) - return String(size) + "b"; - else if (size < (1024 * 1024)) - return String(size / 1024.0) + "kB"; - else if (size < (1024 * 1024 * 1024)) - return String(size / 1024.0 / 1024.0) + "MB"; - else - return String(size / 1024.0 / 1024.0 / 1024.0) + "GB"; -} diff --git a/src/utils/StringUtils.cpp b/src/utils/StringUtils.cpp new file mode 100644 index 00000000..f0c87166 --- /dev/null +++ b/src/utils/StringUtils.cpp @@ -0,0 +1,170 @@ +#include "Utils/StringUtils.h" + +String selectToMarkerLast(String str, String found) { + int p = str.lastIndexOf(found); + return str.substring(p + found.length()); +} + +String selectToMarker(String str, String found) { + int p = str.indexOf(found); + return str.substring(0, p); +} + +String extractInner(String str) { + int p1 = str.indexOf("["); + int p2 = str.indexOf("]"); + return str.substring(p1 + 1, p2); +} + +String deleteAfterDelimiter(String str, String found) { + int p = str.indexOf(found); + return str.substring(0, p); +} + +String deleteBeforeDelimiter(String str, String found) { + int p = str.indexOf(found) + found.length(); + return str.substring(p); +} + +String deleteBeforeDelimiterTo(String str, String found) { + int p = str.indexOf(found); + return str.substring(p); +} + +String deleteToMarkerLast(String str, String found) { + int p = str.lastIndexOf(found); + return str.substring(0, p); +} + +String selectToMarkerPlus(String str, String found, int plus) { + int p = str.indexOf(found); + return str.substring(0, p + plus); +} + +String selectFromMarkerToMarker(String str, String tofind, int number) { + if (str.indexOf(tofind) == -1) { + return "not found"; + } + str += tofind; // добавим для корректного поиска + uint8_t i = 0; // Индекс перебора + do { + if (i == number) { + // если индекс совпал с позицией + return selectToMarker(str, tofind); + } + // отбросим проверенный блок до разделителя + str = deleteBeforeDelimiter(str, tofind); + i++; + } while (str.length() != 0); + + return "not found"; +} + +//преобразовываем байтовый массив в человеческий вид HEX в строке +void hex2string(byte array[], unsigned int len, char buffer[]) { + for (unsigned int i = 0; i < len; i++) { + byte nib1 = (array[i] >> 4) & 0x0F; + byte nib2 = (array[i] >> 0) & 0x0F; + buffer[i * 2 + 0] = nib1 < 0xA ? '0' + nib1 : 'A' + nib1 - 0xA; + buffer[i * 2 + 1] = nib2 < 0xA ? '0' + nib2 : 'A' + nib2 - 0xA; + } + buffer[len * 2] = '\0'; +} + +inline unsigned char ChartoHex(char ch) { + return ((ch >= 'A') ? (ch - 'A' + 0xA) : (ch - '0')) & 0x0F; +} + +// str - указатель на массив символов +// bytes - выходной буфер +// функция возвращает колл-во байт +// +int string2hex(const char* str, unsigned char* bytes) { + unsigned char Hi, Lo; + + int i = 0; + while ((Hi = *str++) && (Lo = *str++)) { + bytes[i++] = (ChartoHex(Hi) << 4) | ChartoHex(Lo); + } + + return i; +} + +uint8_t hexStringToUint8(String hex) { + uint8_t tmp = strtol(hex.c_str(), NULL, 0); + if (tmp >= 0x00 && tmp <= 0xFF) { + return tmp; + } +} + +uint16_t hexStringToUint16(String hex) { + uint16_t tmp = strtol(hex.c_str(), NULL, 0); + if (tmp >= 0x0000 && tmp <= 0xFFFF) { + return tmp; + } +} + +size_t itemsCount2(String str, const String& separator) { + // если строки поиск нет сразу выход + if (str.indexOf(separator) == -1) { + return 0; + } + // добавим для корректного поиска + str += separator; + size_t cnt = 0; + while (str.length()) { + // отбросим проверенный блок до разделителя + str = deleteBeforeDelimiter(str, separator); + cnt++; + } + return cnt; +} + +size_t itemsCount(String& str, const char* delim) { + size_t cnt = 0; + char* cstr = new char[str.length() + 1]; + strcpy(cstr, str.c_str()); + char* token; + while ((token = strtok_r(cstr, delim, &cstr))) { + cnt++; + // printf("%s\n", token); + } + delete[] cstr; + return cnt; +} + +char* stringToChar(String& str) { + char* mychar = new char[str.length() + 1]; + strcpy(mychar, str.c_str()); + return mychar; +} + +boolean isDigitStr(const String& str) { + for (size_t i = 0; i < str.length(); i++) { + if (!isDigit(str.charAt(i))) { + return false; + } + } + return str.length(); +} + +boolean isDigitDotCommaStr(const String& str) { + for (size_t i = 0; i < str.length(); i++) { + char latter = str.charAt(i); + if (!isDigit(latter) && latter != '.' && latter != '-') { + return false; + } + } + return true; +} + +String prettyBytes(size_t size) { + if (size < 1024) + return String(size) + "b"; + else if (size < (1024 * 1024)) + return String(size / 1024.0) + "kB"; + else if (size < (1024 * 1024 * 1024)) + return String(size / 1024.0 / 1024.0) + "MB"; + else + return String(size / 1024.0 / 1024.0 / 1024.0) + "GB"; +} diff --git a/src/utils/TimeUtils.cpp b/src/utils/TimeUtils.cpp index 9ad671a1..1aef83e5 100644 --- a/src/utils/TimeUtils.cpp +++ b/src/utils/TimeUtils.cpp @@ -115,18 +115,18 @@ void breakEpochToTime(unsigned long epoch, Time_t& tm) { tm.valid = (epoch > MIN_DATETIME); } -//void timeInit() { -// ts.add( -// TIME, 1000, [&](void*) { -// String timenow = timeNow->getTimeWOsec(); -// static String prevTime; -// if (prevTime != timenow) { -// prevTime = timenow; -// jsonWriteStr(configLiveJson, "timenow", timenow); -// eventGen2("timenow", timenow); -// SerialPrint("i", F("NTP"), timenow); -// } -// }, -// nullptr, true); -// SerialPrint("i", F("NTP"), F("Handle time init")); -//} +// void timeInit() { +// ts.add( +// TIME, 1000, [&](void*) { +// String timenow = timeNow->getTimeWOsec(); +// static String prevTime; +// if (prevTime != timenow) { +// prevTime = timenow; +// jsonWriteStr(paramsFlashJson, "timenow", timenow); +// eventGen2("timenow", timenow); +// SerialPrint("i", F("NTP"), timenow); +// } +// }, +// nullptr, true); +// SerialPrint("i", F("NTP"), F("Handle time init")); +// }