Добавляем планировщик по типу Cron

This commit is contained in:
2022-10-31 19:33:01 +03:00
parent b8f403f1f1
commit 868c7bf4f2
7 changed files with 1653 additions and 98 deletions

View File

@@ -8,28 +8,43 @@
},
{
"global": 0,
"name": "1. График",
"name": "1. Будильник (Cron)",
"type": "Writing",
"subtype": "Cron",
"id": "cron",
"widget": "anydataDef",
"page": "Таймеры",
"descr": "Будильник",
"int": 1,
"val": "*/15 * * * * *",
"formatNextAlarm": "dd.mm.yy hh:mm:ss",
"needSave": 0,
"num": 1
},
{
"global": 0,
"name": "2. График",
"type": "Writing",
"subtype": "Loging",
"id": "log",
"widget": "chart2",
"page": "Графики",
"descr": "Температура",
"num": 1,
"num": 2,
"int": 5,
"logid": "t",
"points": 300
},
{
"global": 0,
"name": "2. График дневного расхода",
"name": "3. График дневного расхода",
"type": "Writing",
"subtype": "LogingDaily",
"id": "log",
"widget": "chart3",
"page": "Графики",
"descr": "Температура",
"num": 2,
"num": 3,
"int": 1,
"logid": "t",
"points": 365,
@@ -37,7 +52,7 @@
},
{
"global": 0,
"name": "3. Таймер",
"name": "4. Таймер",
"type": "Writing",
"subtype": "Timer",
"id": "timer",
@@ -49,11 +64,11 @@
"ticker": 1,
"repeat": 1,
"needSave": 0,
"num": 3
"num": 4
},
{
"global": 0,
"name": "4. Окно ввода числа (переменная)",
"name": "5. Окно ввода числа (переменная)",
"type": "Reading",
"subtype": "Variable",
"id": "value",
@@ -63,11 +78,11 @@
"descr": "Введите число",
"int": "0",
"val": "0.0",
"num": 4
"num": 5
},
{
"global": 0,
"name": "5. Окно ввода времени",
"name": "6. Окно ввода времени",
"type": "Reading",
"subtype": "Variable",
"id": "time",
@@ -77,11 +92,11 @@
"descr": "Введите время",
"int": "0",
"val": "02:00",
"num": 5
"num": 6
},
{
"global": 0,
"name": "6. Окно ввода даты",
"name": "7. Окно ввода даты",
"type": "Reading",
"subtype": "Variable",
"id": "time",
@@ -91,11 +106,11 @@
"descr": "Введите дату",
"int": "0",
"val": "24.05.2022",
"num": 6
"num": 7
},
{
"global": 0,
"name": "7. Окно ввода текста",
"name": "8. Окно ввода текста",
"type": "Reading",
"subtype": "Variable",
"id": "txt",
@@ -105,11 +120,11 @@
"descr": "Введите текст",
"int": "0",
"val": "текст",
"num": 7
"num": 8
},
{
"global": 0,
"name": "8. Виртуальная кнопка",
"name": "9. Виртуальная кнопка",
"type": "Reading",
"subtype": "VButton",
"id": "vbtn",
@@ -119,13 +134,13 @@
"descr": "Кнопка",
"int": "0",
"val": "0",
"num": 8
"num": 9
},
{
"header": "Сенсоры"
},
{
"name": "9. Acs712 Ток",
"name": "10. Acs712 Ток",
"type": "Reading",
"subtype": "Acs712",
"id": "amp",
@@ -135,11 +150,11 @@
"round": 3,
"pin": 39,
"int": 5,
"num": 9
"num": 10
},
{
"global": 0,
"name": "10. AHTXX Температура",
"name": "11. AHTXX Температура",
"type": "Reading",
"subtype": "AhtXXt",
"id": "Temp20",
@@ -150,11 +165,11 @@
"addr": "0x38",
"shtType": 1,
"round": 1,
"num": 10
"num": 11
},
{
"global": 0,
"name": "11. AHTXX Влажность",
"name": "12. AHTXX Влажность",
"type": "Reading",
"subtype": "AhtXXh",
"id": "Hum20",
@@ -165,11 +180,11 @@
"addr": "0x38",
"shtType": 1,
"round": 1,
"num": 11
"num": 12
},
{
"global": 0,
"name": "12. Аналоговый сенсор",
"name": "13. Аналоговый сенсор",
"type": "Reading",
"subtype": "AnalogAdc",
"id": "t",
@@ -183,11 +198,11 @@
"pin": 0,
"int": 15,
"avgSteps": 1,
"num": 12
"num": 13
},
{
"global": 0,
"name": "13. BME280 Температура",
"name": "14. BME280 Температура",
"type": "Reading",
"subtype": "Bme280t",
"id": "tmp3",
@@ -197,11 +212,11 @@
"int": 15,
"addr": "0x77",
"round": 1,
"num": 13
"num": 14
},
{
"global": 0,
"name": "14. BME280 Давление",
"name": "15. BME280 Давление",
"type": "Reading",
"subtype": "Bme280p",
"id": "Press3",
@@ -211,11 +226,11 @@
"int": 15,
"addr": "0x77",
"round": 1,
"num": 14
"num": 15
},
{
"global": 0,
"name": "15. BME280 Влажность",
"name": "16. BME280 Влажность",
"type": "Reading",
"subtype": "Bme280h",
"id": "Hum3",
@@ -225,11 +240,11 @@
"int": 15,
"addr": "0x77",
"round": 1,
"num": 15
"num": 16
},
{
"global": 0,
"name": "16. BMP280 Температура",
"name": "17. BMP280 Температура",
"type": "Reading",
"subtype": "Bmp280t",
"id": "tmp3",
@@ -239,11 +254,11 @@
"int": 15,
"addr": "0x77",
"round": 1,
"num": 16
"num": 17
},
{
"global": 0,
"name": "17. BMP280 Давление",
"name": "18. BMP280 Давление",
"type": "Reading",
"subtype": "Bmp280p",
"id": "Press3",
@@ -253,11 +268,11 @@
"int": 15,
"addr": "0x77",
"round": 1,
"num": 17
"num": 18
},
{
"global": 0,
"name": "18. DHT11 Температура",
"name": "19. DHT11 Температура",
"type": "Reading",
"subtype": "Dht1122t",
"id": "tmp3",
@@ -267,11 +282,11 @@
"int": 15,
"pin": 0,
"senstype": "dht11",
"num": 18
"num": 19
},
{
"global": 0,
"name": "19. DHT11 Влажность",
"name": "20. DHT11 Влажность",
"type": "Reading",
"subtype": "Dht1122h",
"id": "Hum3",
@@ -281,11 +296,11 @@
"int": 15,
"pin": 0,
"senstype": "dht11",
"num": 19
"num": 20
},
{
"global": 0,
"name": "20. DS18B20 Температура",
"name": "21. DS18B20 Температура",
"type": "Reading",
"subtype": "Ds18b20",
"id": "dstmp",
@@ -297,11 +312,11 @@
"index": 0,
"addr": "",
"round": 1,
"num": 20
"num": 21
},
{
"global": 0,
"name": "21. GY21 Температура",
"name": "22. GY21 Температура",
"type": "Reading",
"subtype": "GY21t",
"id": "tmp4",
@@ -310,11 +325,11 @@
"descr": "Температура",
"round": 1,
"int": 15,
"num": 21
"num": 22
},
{
"global": 0,
"name": "22. GY21 Влажность",
"name": "23. GY21 Влажность",
"type": "Reading",
"subtype": "GY21h",
"id": "Hum4",
@@ -323,11 +338,11 @@
"descr": "Влажность",
"round": 1,
"int": 15,
"num": 22
"num": 23
},
{
"global": 0,
"name": "23. HDC1080 Температура",
"name": "24. HDC1080 Температура",
"type": "Reading",
"subtype": "Hdc1080t",
"id": "Temp1080",
@@ -337,11 +352,11 @@
"int": 15,
"addr": "0x40",
"round": 1,
"num": 23
"num": 24
},
{
"global": 0,
"name": "24. HDC1080 Влажность",
"name": "25. HDC1080 Влажность",
"type": "Reading",
"subtype": "Hdc1080h",
"id": "Hum1080",
@@ -351,11 +366,11 @@
"int": 15,
"addr": "0x40",
"round": 1,
"num": 24
"num": 25
},
{
"global": 0,
"name": "25. MAX6675 Температура",
"name": "26. MAX6675 Температура",
"type": "Reading",
"subtype": "Max6675t",
"id": "maxtmp",
@@ -366,11 +381,11 @@
"DO": 12,
"CS": 13,
"CLK": 14,
"num": 25
"num": 26
},
{
"global": 0,
"name": "26. PZEM 004t Напряжение",
"name": "27. PZEM 004t Напряжение",
"type": "Reading",
"subtype": "Pzem004v",
"id": "v",
@@ -380,11 +395,11 @@
"int": 15,
"addr": "0xF8",
"round": 1,
"num": 26
"num": 27
},
{
"global": 0,
"name": "27. PZEM 004t Сила тока",
"name": "28. PZEM 004t Сила тока",
"type": "Reading",
"subtype": "Pzem004a",
"id": "a",
@@ -394,11 +409,11 @@
"int": 15,
"addr": "0xF8",
"round": 1,
"num": 27
"num": 28
},
{
"global": 0,
"name": "28. PZEM 004t Мощность",
"name": "29. PZEM 004t Мощность",
"type": "Reading",
"subtype": "Pzem004w",
"id": "w",
@@ -408,11 +423,11 @@
"int": 15,
"addr": "0xF8",
"round": 1,
"num": 28
"num": 29
},
{
"global": 0,
"name": "29. PZEM 004t Энергия",
"name": "30. PZEM 004t Энергия",
"type": "Reading",
"subtype": "Pzem004wh",
"id": "wh",
@@ -422,11 +437,11 @@
"int": 15,
"addr": "0xF8",
"round": 1,
"num": 29
"num": 30
},
{
"global": 0,
"name": "30. PZEM 004t Частота",
"name": "31. PZEM 004t Частота",
"type": "Reading",
"subtype": "Pzem004hz",
"id": "hz",
@@ -436,11 +451,11 @@
"int": 15,
"addr": "0xF8",
"round": 1,
"num": 30
"num": 31
},
{
"global": 0,
"name": "31. PZEM 004t Косинус",
"name": "32. PZEM 004t Косинус",
"type": "Reading",
"subtype": "Pzem004pf",
"id": "pf",
@@ -450,12 +465,12 @@
"int": 15,
"addr": "0xF8",
"round": 1,
"num": 31
"num": 32
},
{
"global": 0,
"name": "32. Сканер кнопок 433 MHz",
"num": 32,
"name": "33. Сканер кнопок 433 MHz",
"num": 33,
"type": "Reading",
"subtype": "RCswitch",
"id": "rsw",
@@ -465,7 +480,7 @@
},
{
"global": 0,
"name": "33. Sht20 Температура",
"name": "34. Sht20 Температура",
"type": "Reading",
"subtype": "Sht20t",
"id": "tmp2",
@@ -474,11 +489,11 @@
"descr": "Температура",
"int": 15,
"round": 1,
"num": 33
"num": 34
},
{
"global": 0,
"name": "34. Sht20 Влажность",
"name": "35. Sht20 Влажность",
"type": "Reading",
"subtype": "Sht20h",
"id": "Hum2",
@@ -487,11 +502,11 @@
"descr": "Влажность",
"int": 15,
"round": 1,
"num": 34
"num": 35
},
{
"global": 0,
"name": "35. Sht30 Температура",
"name": "36. Sht30 Температура",
"type": "Reading",
"subtype": "Sht30t",
"id": "tmp30",
@@ -500,11 +515,11 @@
"descr": "SHT30 Температура",
"int": 15,
"round": 1,
"num": 35
"num": 36
},
{
"global": 0,
"name": "36. Sht30 Влажность",
"name": "37. Sht30 Влажность",
"type": "Reading",
"subtype": "Sht30h",
"id": "Hum30",
@@ -513,12 +528,12 @@
"descr": "SHT30 Влажность",
"int": 15,
"round": 1,
"num": 36
"num": 37
},
{
"global": 0,
"name": "37. HC-SR04 Ультразвуковой дальномер",
"num": 37,
"name": "38. HC-SR04 Ультразвуковой дальномер",
"num": 38,
"type": "Reading",
"subtype": "Sonar",
"id": "sonar",
@@ -531,7 +546,7 @@
},
{
"global": 0,
"name": "38. UART",
"name": "39. UART",
"type": "Reading",
"subtype": "UART",
"page": "",
@@ -541,14 +556,14 @@
"tx": 12,
"rx": 13,
"speed": 9600,
"num": 38
"num": 39
},
{
"header": "Исполнительные устройства"
},
{
"global": 0,
"name": "39. Кнопка подключенная к пину",
"name": "40. Кнопка подключенная к пину",
"type": "Writing",
"subtype": "ButtonIn",
"id": "btn",
@@ -562,11 +577,11 @@
"pinMode": "INPUT",
"debounceDelay": 50,
"fixState": 0,
"num": 39
"num": 40
},
{
"global": 0,
"name": "40. Управление пином",
"name": "41. Управление пином",
"type": "Writing",
"subtype": "ButtonOut",
"needSave": 0,
@@ -577,11 +592,11 @@
"int": 0,
"inv": 0,
"pin": 2,
"num": 40
"num": 41
},
{
"global": 0,
"name": "41. Сервопривод",
"name": "42. Сервопривод",
"type": "Writing",
"subtype": "IoTServo",
"id": "servo",
@@ -592,11 +607,11 @@
"pin": 12,
"apin": -1,
"amap": "0, 4096, 0, 180",
"num": 41
"num": 42
},
{
"global": 0,
"name": "42. Расширитель портов Mcp23017",
"name": "43. Расширитель портов Mcp23017",
"type": "Reading",
"subtype": "Mcp23017",
"id": "Mcp",
@@ -606,11 +621,11 @@
"int": "0",
"addr": "0x20",
"index": 1,
"num": 42
"num": 43
},
{
"global": 0,
"name": "43. MP3 плеер",
"name": "44. MP3 плеер",
"type": "Reading",
"subtype": "Mp3",
"id": "mp3",
@@ -620,11 +635,11 @@
"int": 1,
"pins": "14,12",
"volume": 20,
"num": 43
"num": 44
},
{
"global": 0,
"name": "44. Расширитель портов Pcf8574",
"name": "45. Расширитель портов Pcf8574",
"type": "Reading",
"subtype": "Pcf8574",
"id": "Pcf",
@@ -634,11 +649,11 @@
"int": "0",
"addr": "0x20",
"index": 1,
"num": 44
"num": 45
},
{
"global": 0,
"name": "45. PWM ESP8266",
"name": "46. PWM ESP8266",
"type": "Writing",
"subtype": "Pwm8266",
"id": "pwm",
@@ -650,11 +665,11 @@
"freq": 5000,
"val": 0,
"apin": -1,
"num": 45
"num": 46
},
{
"global": 0,
"name": "46. Телеграм-Лайт",
"name": "47. Телеграм-Лайт",
"type": "Writing",
"subtype": "TelegramLT",
"id": "tg",
@@ -663,14 +678,14 @@
"descr": "",
"token": "",
"chatID": "",
"num": 46
"num": 47
},
{
"header": "Экраны"
},
{
"global": 0,
"name": "47. LCD экран 2004",
"name": "48. LCD экран 2004",
"type": "Reading",
"subtype": "Lcd2004",
"id": "Lcd",
@@ -682,10 +697,10 @@
"size": "20,4",
"coord": "0,0",
"id2show": "id датчика",
"num": 47
"num": 48
},
{
"name": "48. LCD экран 1602",
"name": "49. LCD экран 1602",
"type": "Reading",
"subtype": "Lcd2004",
"id": "Lcd",
@@ -697,11 +712,11 @@
"size": "16,2",
"coord": "0,0",
"id2show": "id датчика",
"num": 48
"num": 49
},
{
"global": 0,
"name": "49. Strip ws2812b",
"name": "50. Strip ws2812b",
"type": "Reading",
"subtype": "Ws2812b",
"id": "strip",
@@ -717,6 +732,6 @@
"min": "15",
"max": "30",
"idshow": "t",
"num": 49
"num": 50
}
]

View File

@@ -158,6 +158,7 @@ lib_deps =
marcoschwartz/LiquidCrystal_I2C@^1.1.4
adafruit/Adafruit NeoPixel@^1.10.6
build_src_filter =
+<modules/virtual/Cron>
+<modules/virtual/Loging>
+<modules/virtual/LogingDaily>
+<modules/virtual/Timer>
@@ -210,6 +211,7 @@ lib_deps =
dfrobot/DFRobotDFPlayerMini @ ^1.0.5
adafruit/Adafruit BusIO @ ^1.13.2
marcoschwartz/LiquidCrystal_I2C@^1.1.4
adafruit/Adafruit NeoPixel@^1.10.6
build_src_filter =
+<modules/virtual/Loging>
+<modules/virtual/LogingDaily>
@@ -241,4 +243,5 @@ build_src_filter =
+<modules/exec/Pwm32>
+<modules/exec/TelegramLT>
+<modules/display/Lcd2004>
+<modules/display/Ws2812b>

View File

@@ -1,5 +1,6 @@
#include "ESPConfiguration.h"
void* getAPI_Cron(String subtype, String params);
void* getAPI_Loging(String subtype, String params);
void* getAPI_LogingDaily(String subtype, String params);
void* getAPI_Timer(String subtype, String params);
@@ -34,6 +35,7 @@ void* getAPI_Ws2812b(String subtype, String params);
void* getAPI(String subtype, String params) {
void* tmpAPI;
if ((tmpAPI = getAPI_Cron(subtype, params)) != nullptr) return tmpAPI;
if ((tmpAPI = getAPI_Loging(subtype, params)) != nullptr) return tmpAPI;
if ((tmpAPI = getAPI_LogingDaily(subtype, params)) != nullptr) return tmpAPI;
if ((tmpAPI = getAPI_Timer(subtype, params)) != nullptr) return tmpAPI;

View File

@@ -0,0 +1,111 @@
#include "NTP.h"
#include "Global.h"
#include "classes/IoTItem.h"
extern "C" {
#include "ccronexpr/ccronexpr.h"
}
class Cron : public IoTItem {
private:
bool _pause = false;
String _format = "";
cron_expr _expr;
time_t _nextAlarm = 0;
public:
Cron(String parameters): IoTItem(parameters) {
jsonRead(parameters, F("formatNextAlarm"), _format);
initCron();
}
void initCron() {
const char* err = NULL;
memset(&_expr, 0, sizeof(_expr));
cron_parse_expr(value.valS.c_str(), &_expr, &err);
if (err) {
_pause = true;
_nextAlarm = 0;
memset(&_expr, 0, sizeof(_expr));
SerialPrint("E", "Cron", F("The Cron string did not apply."), _id);
} else
updateNextAlarm(true);
}
void updateNextAlarm(bool forced) {
if (!_pause && _time_isTrust) {
if (forced || (_nextAlarm <= gmtTimeToLocal(unixTime))) {
// update alarm if next trigger is not yet in the future
_nextAlarm = cron_next(&_expr, gmtTimeToLocal(unixTime));
}
}
}
String getNextAlarmF() {
if (_pause) return "Pause";
if (!_time_isTrust) return "No time";
struct tm* timeinfo;
char buffer [80];
timeinfo = localtime(&_nextAlarm);
strftime(buffer, 80, _format.c_str(), timeinfo);
return buffer;
}
String getValue() {
return getNextAlarmF();
}
void setValue(const IoTValue& Value, bool genEvent) {
value = Value;
_pause = false;
initCron();
if (_needSave) {
jsonWriteStr_(valuesFlashJson, _id, value.valS);
needSaveValues = true;
}
bool _needSaveBak = _needSave;
_needSave = false;
regEvent(getNextAlarmF(), F("Cron alarm"), false, false);
_needSave = _needSaveBak;
}
void doByInterval() {
if (!_pause && _time_isTrust && (gmtTimeToLocal(unixTime) >= _nextAlarm)) {
updateNextAlarm(true);
bool _needSaveBak = _needSave;
_needSave = false;
regEvent(getNextAlarmF(), F("Cron alarm"));
_needSave = _needSaveBak;
}
}
IoTValue execute(String command, std::vector<IoTValue> &param) {
if (command == "stop") {
_pause = true;
} else if (command == "continue") {
_pause = false;
updateNextAlarm(false);
}
bool _needSaveBak = _needSave;
_needSave = false;
regEvent(getNextAlarmF(), F("Cron alarm"), false, false);
_needSave = _needSaveBak;
return {};
}
~Cron() {};
};
void* getAPI_Cron(String subtype, String param) {
if (subtype == F("Cron")) {
return new Cron(param);
} else {
return nullptr;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,95 @@
/*
* Copyright 2015, alex at staticlibs.net
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* File: ccronexpr.h
* Author: alex
*
* Created on February 24, 2015, 9:35 AM
*/
#ifndef CCRONEXPR_H
#define CCRONEXPR_H
#define CRON_USE_LOCAL_TIME
#if defined(__cplusplus) && !defined(CRON_COMPILE_AS_CXX)
extern "C" {
#endif
#ifndef ANDROID
#include <time.h>
#else /* ANDROID */
#include <time64.h>
#endif /* ANDROID */
#include <stdint.h> /*added for use if uint*_t data types*/
/**
* Parsed cron expression
*/
typedef struct {
uint8_t seconds[8];
uint8_t minutes[8];
uint8_t hours[3];
uint8_t days_of_week[1];
uint8_t days_of_month[4];
uint8_t months[2];
} cron_expr;
/**
* Parses specified cron expression.
*
* @param expression cron expression as nul-terminated string,
* should be no longer that 256 bytes
* @param pointer to cron expression structure, it's client code responsibility
* to free/destroy it afterwards
* @param error output error message, will be set to string literal
* error message in case of error. Will be set to NULL on success.
* The error message should NOT be freed by client.
*/
void cron_parse_expr(const char* expression, cron_expr* target, const char** error);
/**
* Uses the specified expression to calculate the next 'fire' date after
* the specified date. All dates are processed as UTC (GMT) dates
* without timezones information. To use local dates (current system timezone)
* instead of GMT compile with '-DCRON_USE_LOCAL_TIME'
*
* @param expr parsed cron expression to use in next date calculation
* @param date start date to start calculation from
* @return next 'fire' date in case of success, '((time_t) -1)' in case of error.
*/
time_t cron_next(cron_expr* expr, time_t date);
/**
* Uses the specified expression to calculate the previous 'fire' date after
* the specified date. All dates are processed as UTC (GMT) dates
* without timezones information. To use local dates (current system timezone)
* instead of GMT compile with '-DCRON_USE_LOCAL_TIME'
*
* @param expr parsed cron expression to use in previous date calculation
* @param date start date to start calculation from
* @return previous 'fire' date in case of success, '((time_t) -1)' in case of error.
*/
time_t cron_prev(cron_expr* expr, time_t date);
#if defined(__cplusplus) && !defined(CRON_COMPILE_AS_CXX)
} /* extern "C"*/
#endif
#endif /* CCRONEXPR_H */

View File

@@ -0,0 +1,57 @@
{
"menuSection": "Виртуальные элементы",
"configItem": [
{
"global": 0,
"name": "Будильник (Cron)",
"type": "Writing",
"subtype": "Cron",
"id": "cron",
"widget": "anydataDef",
"page": "Таймеры",
"descr": "Будильник",
"int": 1,
"val": "*/15 * * * * *",
"formatNextAlarm": "%H:%M:%S",
"needSave": 0
}
],
"about": {
"authorName": "Ilya Belyakov",
"authorContact": "https://t.me/Biveraxe",
"authorGit": "https://github.com/biveraxe",
"specialThanks": "",
"moduleName": "Cron",
"moduleVersion": "1.0",
"usedRam": {
"esp32_4mb": 15,
"esp8266_4mb": 15
},
"title": "Будильник типа Cron",
"moduleDesc": "Планировщик времени для периодического выполнения заданий в определённое время. Генерирует событие в указанное время по формату Cron https://ru.wikipedia.org/wiki/Cron ",
"propInfo": {
"formatNextAlarm": "Формат представления даты и времени срабатывания следующего уведомления. http://cppstudio.com/post/621/",
"needSave": "Требуется сохранять(1) или нет(0) состояние в энерго независимую память."
},
"retInfo": "Содержит время следующего срабатывания.",
"funcInfo": [
{
"name": "stop",
"descr": "Поставить процесс на паузу, при этом не будет событий.",
"params": []
},
{
"name": "continue",
"descr": "Продолжить выполнение с момента остановки.",
"params": []
}
]
},
"defActive": true,
"usedLibs": {
"esp32_4mb": [],
"esp8266_4mb": [],
"esp8266_1mb": [],
"esp8266_1mb_ota": []
}
}