mirror of
https://github.com/IoTManagerProject/IoTManager.git
synced 2026-03-27 06:32:19 +03:00
Убираем нумерацию папок модулей
This commit is contained in:
77
src/modules/exec/ButtonIn/ButtonIn.cpp
Normal file
77
src/modules/exec/ButtonIn/ButtonIn.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
#include "Global.h"
|
||||
#include "classes/IoTItem.h"
|
||||
|
||||
extern IoTGpio IoTgpio;
|
||||
|
||||
|
||||
class ButtonIn : public IoTItem {
|
||||
private:
|
||||
int _pin;
|
||||
bool _execLevel;
|
||||
int _fixState;
|
||||
String _pinMode;
|
||||
int _lastButtonState = LOW;
|
||||
unsigned long _lastDebounceTime = 0;
|
||||
unsigned long _debounceDelay = 50;
|
||||
int _buttonState;
|
||||
int _reading;
|
||||
|
||||
public:
|
||||
ButtonIn(String parameters): IoTItem(parameters) {
|
||||
jsonRead(parameters, "pin", _pin);
|
||||
jsonRead(parameters, "execLevel", _execLevel);
|
||||
jsonRead(parameters, "pinMode", _pinMode);
|
||||
jsonRead(parameters, "debounceDelay", _debounceDelay);
|
||||
jsonRead(parameters, "fixState", _fixState);
|
||||
//Serial.printf("vvvvvvvvvvvvvvvv =%d \n", _fixState);
|
||||
|
||||
IoTgpio.pinMode(_pin, INPUT);
|
||||
if (_pinMode == "INPUT_PULLUP") IoTgpio.digitalWrite(_pin, HIGH);
|
||||
else if (_pinMode == "INPUT_PULLDOWN") IoTgpio.digitalWrite(_pin, LOW);
|
||||
|
||||
|
||||
// TODO: загрузить значение из памяти иначе пока просто считываем значение текущего состояния PIN
|
||||
_lastButtonState = _buttonState = IoTgpio.digitalRead(_pin);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
_reading = IoTgpio.digitalRead(_pin);
|
||||
if (_reading != _lastButtonState) {
|
||||
// reset the debouncing timer
|
||||
_lastDebounceTime = millis();
|
||||
}
|
||||
|
||||
if ((millis() - _lastDebounceTime) > _debounceDelay) {
|
||||
if (_reading != _buttonState) {
|
||||
_buttonState = _reading;
|
||||
|
||||
if (_fixState == 1 && _buttonState == _execLevel) {
|
||||
value.valD = !value.valD;
|
||||
regEvent(value.valD, "ButtonIn");
|
||||
}
|
||||
|
||||
if (_fixState == 2) {
|
||||
value.valD = !value.valD;
|
||||
regEvent(value.valD, "ButtonIn");
|
||||
}
|
||||
|
||||
if (_fixState == 0) {
|
||||
value.valD = _buttonState;
|
||||
regEvent(value.valD, "ButtonIn");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_lastButtonState = _reading;
|
||||
}
|
||||
|
||||
~ButtonIn() {};
|
||||
};
|
||||
|
||||
void* getAPI_ButtonIn(String subtype, String param) {
|
||||
if (subtype == F("ButtonIn")) {
|
||||
return new ButtonIn(param);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
41
src/modules/exec/ButtonIn/modinfo.json
Normal file
41
src/modules/exec/ButtonIn/modinfo.json
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"menuSection": "Исполнительные устройства",
|
||||
"configItem": [
|
||||
{
|
||||
"name": "Кнопка подключенная к пину",
|
||||
"type": "Writing",
|
||||
"subtype": "ButtonIn",
|
||||
"id": "btn",
|
||||
"widget": "toggle",
|
||||
"page": "Кнопки",
|
||||
"descr": "",
|
||||
"int": 0,
|
||||
"pin": 16,
|
||||
"execLevel": "1",
|
||||
"pinMode": "INPUT",
|
||||
"debounceDelay": 50,
|
||||
"fixState": 1
|
||||
}
|
||||
],
|
||||
"about": {
|
||||
"authorName": "Ilya Belyakov",
|
||||
"authorContact": "https://t.me/Biveraxe",
|
||||
"authorGit": "https://github.com/biveraxe",
|
||||
"specialThanks": "",
|
||||
"moduleName": "ButtonIn",
|
||||
"moduleVersion": "1.0",
|
||||
"moduleDesc": "Позволяет интерпретировать сигналы на цифровом пине как кнопку, т.е. создает в системе объект для чтения булевых значений с внешнего физического источника. Может вести себя как кнопка или как переключатель.",
|
||||
"propInfo": {
|
||||
"pin": "Укажите GPIO номер пина для чтения состояний подключенной кнопки",
|
||||
"execLevel": "Высокий 1 или низкий 0 уровень переключения состояния",
|
||||
"pinMode": "Может быть INPUT_PULLUP INPUT_PULLDOWN INPUT",
|
||||
"debounceDelay": "Время обработки дребезга",
|
||||
"fixState": "Поведение входа, срабатывание на переходе или на фиксации уровня (триггерный режим)"
|
||||
}
|
||||
},
|
||||
"defActive": true,
|
||||
"devices": {
|
||||
"esp32_4mb": [],
|
||||
"esp8266_4mb": []
|
||||
}
|
||||
}
|
||||
59
src/modules/exec/ButtonOut/ButtonOut.cpp
Normal file
59
src/modules/exec/ButtonOut/ButtonOut.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
#include "Global.h"
|
||||
#include "classes/IoTItem.h"
|
||||
|
||||
extern IoTGpio IoTgpio;
|
||||
|
||||
|
||||
class ButtonOut : public IoTItem {
|
||||
private:
|
||||
int _pin, _inv;
|
||||
|
||||
public:
|
||||
ButtonOut(String parameters): IoTItem(parameters) {
|
||||
jsonRead(parameters, "pin", _pin);
|
||||
jsonRead(parameters, "inv", _inv);
|
||||
|
||||
IoTgpio.pinMode(_pin, OUTPUT);
|
||||
//TODO: прочитать состояние из памяти
|
||||
IoTgpio.digitalWrite(_pin, _inv?HIGH:LOW); // пока нет памяти, устанавливаем значение в ноль
|
||||
value.valD = 0;
|
||||
}
|
||||
|
||||
void doByInterval() {
|
||||
//value.valD = IoTgpio.analogRead(_pin);
|
||||
|
||||
//regEvent(value.valD, "ButtonOut"); //обязательный вызов хотяб один
|
||||
}
|
||||
|
||||
IoTValue execute(String command, std::vector<IoTValue> ¶m) {
|
||||
// реакция на вызов команды модуля из сценария
|
||||
// String command - имя команды после ID. (ID.Команда())
|
||||
// param - вектор ("массив") значений параметров переданных вместе с командой: ID.Команда("пар1", 22, 33) -> param[0].ValS = "пар1", param[1].ValD = 22
|
||||
|
||||
if (command == "change") {
|
||||
value.valD = 1 - IoTgpio.digitalRead(_pin);
|
||||
IoTgpio.digitalWrite(_pin, value.valD);
|
||||
regEvent(value.valD, "ButtonOut");
|
||||
}
|
||||
|
||||
return {}; // команда поддерживает возвращаемое значения. Т.е. по итогу выполнения команды или общения с внешней системой, можно вернуть значение в сценарий для дальнейшей обработки
|
||||
}
|
||||
|
||||
void setValue(IoTValue Value) {
|
||||
value = Value;
|
||||
IoTgpio.digitalWrite(_pin, _inv?!value.valD:value.valD);
|
||||
if (value.isDecimal) regEvent(value.valD, "ButtonOut");
|
||||
else regEvent(value.valS, "ButtonOut");
|
||||
}
|
||||
//=======================================================================================================
|
||||
|
||||
~ButtonOut() {};
|
||||
};
|
||||
|
||||
void* getAPI_ButtonOut(String subtype, String param) {
|
||||
if (subtype == F("ButtonOut")) {
|
||||
return new ButtonOut(param);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
35
src/modules/exec/ButtonOut/modinfo.json
Normal file
35
src/modules/exec/ButtonOut/modinfo.json
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"menuSection": "Исполнительные устройства",
|
||||
"configItem": [
|
||||
{
|
||||
"name": "Кнопка управляющая пином (Реле)",
|
||||
"type": "Writing",
|
||||
"subtype": "ButtonOut",
|
||||
"id": "btn",
|
||||
"widget": "toggle",
|
||||
"page": "Кнопки",
|
||||
"descr": "",
|
||||
"int": 0,
|
||||
"inv": 0,
|
||||
"pin": 2
|
||||
}
|
||||
],
|
||||
"about": {
|
||||
"authorName": "Ilya Belyakov",
|
||||
"authorContact": "https://t.me/Biveraxe",
|
||||
"authorGit": "https://github.com/biveraxe",
|
||||
"specialThanks": "",
|
||||
"moduleName": "ButtonOut",
|
||||
"moduleVersion": "1.0",
|
||||
"moduleDesc": "Управляем состоянием конкретного пина по модели реле.",
|
||||
"propInfo": {
|
||||
"pin": "Укажите GPIO номер пина для управления выходом",
|
||||
"inv": "Инвертировать выходные сигналы"
|
||||
}
|
||||
},
|
||||
"defActive": true,
|
||||
"devices": {
|
||||
"esp32_4mb": [],
|
||||
"esp8266_4mb": []
|
||||
}
|
||||
}
|
||||
157
src/modules/exec/EspCam/EspCam.cpp
Normal file
157
src/modules/exec/EspCam/EspCam.cpp
Normal file
@@ -0,0 +1,157 @@
|
||||
#include "Global.h"
|
||||
#include "classes/IoTItem.h"
|
||||
|
||||
#include "esp_camera.h"
|
||||
#include "soc/soc.h" // Disable brownour problems
|
||||
#include "soc/rtc_cntl_reg.h" // Disable brownour problems
|
||||
|
||||
|
||||
// Pin definition for CAMERA_MODEL_AI_THINKER
|
||||
#define PWDN_GPIO_NUM 32
|
||||
#define RESET_GPIO_NUM -1
|
||||
#define XCLK_GPIO_NUM 0
|
||||
#define SIOD_GPIO_NUM 26
|
||||
#define SIOC_GPIO_NUM 27
|
||||
|
||||
#define Y9_GPIO_NUM 35
|
||||
#define Y8_GPIO_NUM 34
|
||||
#define Y7_GPIO_NUM 39
|
||||
#define Y6_GPIO_NUM 36
|
||||
#define Y5_GPIO_NUM 21
|
||||
#define Y4_GPIO_NUM 19
|
||||
#define Y3_GPIO_NUM 18
|
||||
#define Y2_GPIO_NUM 5
|
||||
#define VSYNC_GPIO_NUM 25
|
||||
#define HREF_GPIO_NUM 23
|
||||
#define PCLK_GPIO_NUM 22
|
||||
|
||||
#define PICBUF_SIZE 50000
|
||||
|
||||
|
||||
IoTItem* globalItem = nullptr;
|
||||
bool webTicker = false;
|
||||
|
||||
void handleGetCam() {
|
||||
//Serial.printf("try send pic by size=%d", lastPhotoBSize);
|
||||
if (globalItem && globalItem->value.extBinInfoSize) {
|
||||
//Serial.printf("try send pic by size=%d", globalItem->value.extBinInfoSize);
|
||||
HTTP.send_P(200, "image/jpeg", (char*)globalItem->value.extBinInfo, globalItem->value.extBinInfoSize);
|
||||
if (webTicker) globalItem->regEvent("webAsk", "EspCam");
|
||||
} else HTTP.send(200, "text/json", "Item EspCam not prepared yet or camera hasn't taken a picture yet");
|
||||
}
|
||||
|
||||
class EspCam : public IoTItem {
|
||||
private:
|
||||
camera_fb_t * fb = NULL;
|
||||
bool _useLed, _ticker, _webTicker;
|
||||
|
||||
public:
|
||||
EspCam(String parameters): IoTItem(parameters) {
|
||||
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
|
||||
|
||||
jsonRead(parameters, "useLed", _useLed); // используем = 1 или нет = 0 подсветку (вспышку)
|
||||
jsonRead(parameters, "ticker", _ticker); // тикать = 1 - сообщаем всем, что сделали снимок и он готов
|
||||
jsonRead(parameters, "webTicker", _webTicker); // сообщать всем, что через веб попросили отдать картинку с камеры
|
||||
webTicker = _webTicker;
|
||||
globalItem = this; // выносим адрес переменной экземпляра для доступа к данным из обработчика событий веб
|
||||
|
||||
pinMode(4, OUTPUT);
|
||||
digitalWrite(4, LOW);
|
||||
|
||||
camera_config_t config;
|
||||
config.ledc_channel = LEDC_CHANNEL_0;
|
||||
config.ledc_timer = LEDC_TIMER_0;
|
||||
config.pin_d0 = Y2_GPIO_NUM;
|
||||
config.pin_d1 = Y3_GPIO_NUM;
|
||||
config.pin_d2 = Y4_GPIO_NUM;
|
||||
config.pin_d3 = Y5_GPIO_NUM;
|
||||
config.pin_d4 = Y6_GPIO_NUM;
|
||||
config.pin_d5 = Y7_GPIO_NUM;
|
||||
config.pin_d6 = Y8_GPIO_NUM;
|
||||
config.pin_d7 = Y9_GPIO_NUM;
|
||||
config.pin_xclk = XCLK_GPIO_NUM;
|
||||
config.pin_pclk = PCLK_GPIO_NUM;
|
||||
config.pin_vsync = VSYNC_GPIO_NUM;
|
||||
config.pin_href = HREF_GPIO_NUM;
|
||||
config.pin_sscb_sda = SIOD_GPIO_NUM;
|
||||
config.pin_sscb_scl = SIOC_GPIO_NUM;
|
||||
config.pin_pwdn = PWDN_GPIO_NUM;
|
||||
config.pin_reset = RESET_GPIO_NUM;
|
||||
config.xclk_freq_hz = 20000000;
|
||||
config.pixel_format = PIXFORMAT_JPEG;
|
||||
|
||||
value.extBinInfo = (uint8_t*)malloc(sizeof(uint8_t) * PICBUF_SIZE);
|
||||
|
||||
if(psramFound()){
|
||||
config.frame_size = FRAMESIZE_SVGA; // FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA
|
||||
config.jpeg_quality = 20; //0-63 lower number means higher quality
|
||||
config.fb_count = 1;
|
||||
Serial.printf("Camera psramFound\n");
|
||||
} else {
|
||||
config.frame_size = FRAMESIZE_SVGA;
|
||||
config.jpeg_quality = 20;
|
||||
config.fb_count = 1;
|
||||
}
|
||||
|
||||
// Init Camera
|
||||
esp_err_t err = esp_camera_init(&config);
|
||||
if (err != ESP_OK) {
|
||||
Serial.printf("Camera init failed with error 0x%x\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
HTTP.on("/getcam", HTTP_GET, handleGetCam);
|
||||
}
|
||||
|
||||
void take_picture() {
|
||||
if (_useLed) digitalWrite(4, HIGH); //Turn on the flash
|
||||
|
||||
// Take Picture with Camera
|
||||
fb = esp_camera_fb_get();
|
||||
if(!fb || fb->len >= PICBUF_SIZE) {
|
||||
if (fb) {
|
||||
Serial.printf("Camera capture failed size=%d\n", fb->len);
|
||||
esp_camera_fb_return(fb);
|
||||
} else Serial.printf("Camera capture failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// if (value.extBinInfoSize < fb->len) {
|
||||
// if (value.extBinInfo) free(value.extBinInfo);
|
||||
// value.extBinInfo = (uint8_t*)malloc(sizeof(uint8_t) * fb->len);
|
||||
// }
|
||||
memcpy(value.extBinInfo, fb->buf, fb->len);
|
||||
value.extBinInfoSize = fb->len;
|
||||
|
||||
Serial.printf("try send pic by size=%d", fb->len);
|
||||
|
||||
if (_useLed) digitalWrite(4, LOW);
|
||||
if (_ticker) regEvent("shot", "EspCam");
|
||||
esp_camera_fb_return(fb);
|
||||
}
|
||||
|
||||
void doByInterval() {
|
||||
take_picture();
|
||||
}
|
||||
|
||||
IoTValue execute(String command, std::vector<IoTValue> ¶m) {
|
||||
if (command == "shot") {
|
||||
take_picture();
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
~EspCam() {
|
||||
free(value.extBinInfo);
|
||||
//globalItem = nullptr;
|
||||
};
|
||||
};
|
||||
|
||||
void* getAPI_EspCam(String subtype, String param) {
|
||||
if (subtype == F("EspCam")) {
|
||||
return new EspCam(param);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
42
src/modules/exec/EspCam/modinfo.json
Normal file
42
src/modules/exec/EspCam/modinfo.json
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"menuSection": "Исполнительные устройства",
|
||||
|
||||
"configItem": [{
|
||||
"name": "Camera OV2640 (ESPcam)",
|
||||
"type": "Reading",
|
||||
"subtype": "EspCam",
|
||||
"id": "EspCam",
|
||||
"widget": "",
|
||||
"page": "",
|
||||
"descr": "",
|
||||
|
||||
"int": 60,
|
||||
"useLed": 0,
|
||||
"ticker": 0,
|
||||
"webTicker": 0
|
||||
}],
|
||||
|
||||
"about": {
|
||||
"authorName": "Ilya Belyakov",
|
||||
"authorContact": "https://t.me/Biveraxe",
|
||||
"authorGit": "https://github.com/biveraxe",
|
||||
"specialThanks": "",
|
||||
"moduleName": "EspCam",
|
||||
"moduleVersion": "1.0",
|
||||
"moduleDesc": "Предназначен для специальной платы esp32 со встроенной камерой. Добавляет в прошивку функцию создания фото и сохранения в оперативную память. Для сброса на флешкарту необходимо использовать парный модуль SDcard. Это экспериментальные модули и в будущем планируется пересобрать их.",
|
||||
"propInfo": {
|
||||
"int": "Пауза в секундах во время постоянной съемки.",
|
||||
"useLed": "использовать диод подсветки при съемке.",
|
||||
"ticker": "Генерировать(1) или нет(0) событие с интервалом int",
|
||||
"webTicker": "Генерировать(1) или нет(0) событие при обращении через веб-страницу с текущим фото в памяти."
|
||||
}
|
||||
},
|
||||
|
||||
"defActive": false,
|
||||
|
||||
"devices": {
|
||||
"esp32_4mb": [
|
||||
"espressif/esp32-camera @ ^2.0.0"
|
||||
]
|
||||
}
|
||||
}
|
||||
112
src/modules/exec/IarduinoRTC/IarduinoRTC.cpp
Normal file
112
src/modules/exec/IarduinoRTC/IarduinoRTC.cpp
Normal file
@@ -0,0 +1,112 @@
|
||||
#include "Global.h"
|
||||
#include "classes/IoTItem.h"
|
||||
#include "classes/IoTRTC.h"
|
||||
|
||||
#include <iarduino_RTC.h>
|
||||
#include "iarduino_RTC_DS1302.h" // Подключаем файл iarduino_RTC_DS1302.h
|
||||
#include "iarduino_RTC_DS1307.h" // Подключаем файл iarduino_RTC_DS1307.h
|
||||
#include "iarduino_RTC_DS3231.h" // Подключаем файл iarduino_RTC_DS3231.h
|
||||
#include "iarduino_RTC_RX8025.h"
|
||||
|
||||
extern IoTRTC *watch;
|
||||
|
||||
|
||||
class IarduinoRTC : public IoTItem {
|
||||
private:
|
||||
int _chipNum, _rst, _clk, _dat, _ticker;
|
||||
String _defFormat;
|
||||
iarduino_RTC_BASE *RTCDriver;
|
||||
|
||||
public:
|
||||
|
||||
IarduinoRTC(String parameters): IoTItem(parameters) {
|
||||
jsonRead(parameters, "chipNum", _chipNum);
|
||||
jsonRead(parameters, "rst", _rst);
|
||||
jsonRead(parameters, "clk", _clk);
|
||||
jsonRead(parameters, "dat", _dat);
|
||||
jsonRead(parameters, "defFormat", _defFormat);
|
||||
jsonRead(parameters, "ticker", _ticker);
|
||||
|
||||
switch (_chipNum) {
|
||||
case 0:
|
||||
RTCDriver = new iarduino_RTC_NTP();
|
||||
break;
|
||||
case 1:
|
||||
RTCDriver = new iarduino_RTC_DS1302(_rst, _clk, _dat);
|
||||
break;
|
||||
case 2:
|
||||
RTCDriver = new iarduino_RTC_DS1307();
|
||||
break;
|
||||
case 3:
|
||||
RTCDriver = new iarduino_RTC_DS3231();
|
||||
break;
|
||||
case 4:
|
||||
RTCDriver = new iarduino_RTC_RX8025();
|
||||
break;
|
||||
}
|
||||
if (RTCDriver) RTCDriver->begin();
|
||||
}
|
||||
|
||||
void doByInterval() {
|
||||
value.isDecimal = false;
|
||||
value.valS = watch->gettime(_defFormat.c_str());
|
||||
if (_ticker) regEvent(value.valS, "time ticker");
|
||||
}
|
||||
|
||||
IoTValue execute(String command, std::vector<IoTValue> ¶m) {
|
||||
IoTValue tmpValue;
|
||||
if (command == "getTime") {
|
||||
if (param.size()) {
|
||||
tmpValue.isDecimal = false;
|
||||
tmpValue.valS = watch->gettime(param[0].valS.c_str());
|
||||
return tmpValue;
|
||||
}
|
||||
} else if (command == "saveSysTime") {
|
||||
tm localTimeVar;
|
||||
time_t timeNowVar;
|
||||
time(&timeNowVar);
|
||||
localTimeVar = *localtime(&timeNowVar);
|
||||
watch->settime(localTimeVar.tm_sec, localTimeVar.tm_min, localTimeVar.tm_hour, localTimeVar.tm_mday, localTimeVar.tm_mon+1, localTimeVar.tm_year-100, localTimeVar.tm_wday);
|
||||
} else if (command == "setTime") {
|
||||
if (param.size()) {
|
||||
watch->settime(param[0].valD, param[1].valD, param[2].valD, param[3].valD, param[4].valD, param[5].valD, param[6].valD);
|
||||
}
|
||||
} else if (command == "setUnixTime") {
|
||||
if (param.size()) {
|
||||
watch->settimeUnix(param[0].valD);
|
||||
}
|
||||
} else if (command == "getHours") {
|
||||
tmpValue.valD = watch->Hours; // Часы 0-23
|
||||
return tmpValue;
|
||||
} else if (command == "getMinutes") {
|
||||
tmpValue.valD = watch->minutes; // Минуты 0-59
|
||||
return tmpValue;
|
||||
} else if (command == "getSeconds") {
|
||||
tmpValue.valD = watch->seconds; // Секунды 0-59
|
||||
return tmpValue;
|
||||
} else if (command == "getMonth") {
|
||||
tmpValue.valD = watch->month; // Месяц 1-12
|
||||
return tmpValue;
|
||||
} else if (command == "getDay") {
|
||||
tmpValue.valD = watch->day; // День месяца 1-31
|
||||
return tmpValue;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
iarduino_RTC_BASE* getRtcDriver() {
|
||||
return RTCDriver;
|
||||
}
|
||||
|
||||
~IarduinoRTC() {};
|
||||
};
|
||||
|
||||
|
||||
void* getAPI_IarduinoRTC(String subtype, String param) {
|
||||
if (subtype == F("IarduinoRTC")) {
|
||||
return new IarduinoRTC(param);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
47
src/modules/exec/IarduinoRTC/modinfo.json
Normal file
47
src/modules/exec/IarduinoRTC/modinfo.json
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"menuSection": "Исполнительные устройства",
|
||||
|
||||
"configItem": [{
|
||||
"name": "Поддержка DS1302(1), DS1307(2), DS3231(3), RX8025(4)",
|
||||
"type": "Reading",
|
||||
"subtype": "IarduinoRTC",
|
||||
"id": "RTC",
|
||||
"widget": "",
|
||||
"page": "",
|
||||
"descr": "",
|
||||
|
||||
"int": "1",
|
||||
"chipNum": 1,
|
||||
"rst": 16,
|
||||
"clk": 5,
|
||||
"dat": 4,
|
||||
"defFormat": "d-m-Y",
|
||||
"ticker": 0
|
||||
}],
|
||||
|
||||
"about": {
|
||||
"authorName": "Ilya Belyakov",
|
||||
"authorContact": "https://t.me/Biveraxe",
|
||||
"authorGit": "https://github.com/biveraxe",
|
||||
"specialThanks": "Sergey @Serghei63",
|
||||
"moduleName": "IarduinoRTC",
|
||||
"moduleVersion": "1.0",
|
||||
"moduleDesc": "Позволяет использовать часы реального времени в виде внешнего физического модуля или виртуального с синхронизацией через сеть Интернет.",
|
||||
"propInfo": {
|
||||
"int": "Период времени в секундах между опросами времени с RTC",
|
||||
"chipNum": "Выбор источника: 0 - время с Интернет, 1 - модуль DS1302, 2 - модуль DS1307, 3 - модуль DS3231, 4 - модуль RX38025",
|
||||
"rst": "Номер пина для подключения вашего модуля часов. (не всегда используется).",
|
||||
"clk": "Номер пина для SDL вашего модуля часов",
|
||||
"dat": "Номер пина для SDA вашего модуля часов",
|
||||
"defFormat": "Вывод информации в формате defFormat",
|
||||
"ticker": "Генерировать(1) или нет(0) события при каждом тике модуля = int. Позволяет не применять модуль таймера, если нужно просто тактировать работу."
|
||||
}
|
||||
},
|
||||
|
||||
"defActive": true,
|
||||
|
||||
"devices": {
|
||||
"esp32_4mb": [],
|
||||
"esp8266_4mb": []
|
||||
}
|
||||
}
|
||||
73
src/modules/exec/IoTServo/IoTServo.cpp
Normal file
73
src/modules/exec/IoTServo/IoTServo.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
#include "Global.h"
|
||||
#include "classes/IoTItem.h"
|
||||
#include "classes/IoTGpio.h"
|
||||
|
||||
extern IoTGpio IoTgpio;
|
||||
|
||||
#include <Servo.h>
|
||||
|
||||
class IoTServo : public IoTItem {
|
||||
private:
|
||||
Servo servObj;
|
||||
int _apin, _oldValue;
|
||||
int _locmap1, _locmap2, _locmap3, _locmap4;
|
||||
|
||||
public:
|
||||
IoTServo(String parameters): IoTItem(parameters) {
|
||||
int pin;
|
||||
jsonRead(parameters, "pin", pin);
|
||||
servObj.attach(pin);
|
||||
|
||||
jsonRead(parameters, "apin", _apin);
|
||||
if (_apin >= 0) IoTgpio.pinMode(_apin, INPUT);
|
||||
|
||||
String map;
|
||||
jsonRead(parameters, F("amap"), map, false);
|
||||
if (map != "") {
|
||||
_locmap1 = selectFromMarkerToMarker(map, ",", 0).toInt();
|
||||
_locmap2 = selectFromMarkerToMarker(map, ",", 1).toInt();
|
||||
_locmap3 = selectFromMarkerToMarker(map, ",", 2).toInt();
|
||||
_locmap4 = selectFromMarkerToMarker(map, ",", 3).toInt();
|
||||
}
|
||||
}
|
||||
|
||||
void doByInterval() {
|
||||
if (_apin >= 0) {
|
||||
value.valD = map(IoTgpio.analogRead(_apin), _locmap1, _locmap2, _locmap3, _locmap4);
|
||||
if (abs(_oldValue - value.valD) > 5) {
|
||||
_oldValue = value.valD;
|
||||
servObj.write(_oldValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IoTValue execute(String command, std::vector<IoTValue> ¶m) {
|
||||
if (command == "rotate") {
|
||||
if (param.size()) {
|
||||
value.valD = param[0].valD;
|
||||
servObj.write(value.valD);
|
||||
regEvent(value.valD, "IoTServo");
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void setValue(IoTValue Value) {
|
||||
value = Value;
|
||||
if (value.isDecimal & (_oldValue != value.valD)) {
|
||||
_oldValue = value.valD;
|
||||
servObj.write(_oldValue);
|
||||
regEvent(value.valD, "IoTServo");
|
||||
}
|
||||
}
|
||||
|
||||
~IoTServo() {};
|
||||
};
|
||||
|
||||
void* getAPI_IoTServo(String subtype, String param) {
|
||||
if (subtype == F("IoTServo")) {
|
||||
return new IoTServo(param);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
43
src/modules/exec/IoTServo/modinfo.json
Normal file
43
src/modules/exec/IoTServo/modinfo.json
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"menuSection": "Исполнительные устройства",
|
||||
|
||||
"configItem": [{
|
||||
"name": "Сервопривод",
|
||||
"type": "Writing",
|
||||
"subtype": "IoTServo",
|
||||
"id": "servo",
|
||||
"widget": "range",
|
||||
"page": "servo",
|
||||
"descr": "угол",
|
||||
|
||||
"int": 1,
|
||||
"pin": 12,
|
||||
"apin": -1,
|
||||
"amap": "0, 4096, 0, 180"
|
||||
}],
|
||||
|
||||
"about": {
|
||||
"authorName": "Ilya Belyakov",
|
||||
"authorContact": "https://t.me/Biveraxe",
|
||||
"authorGit": "https://github.com/biveraxe",
|
||||
"specialThanks": "Oleg @Threedreality, Sergey @Serghei63",
|
||||
"moduleName": "IoTServo",
|
||||
"moduleVersion": "1.0",
|
||||
"moduleDesc": "Предназначен для управления сервоприводом по уровню аналогово сигнала.",
|
||||
"propInfo": {
|
||||
"int": "Пауза в секундах между опросами аналогового входа. Если 0, то читаем постоянно",
|
||||
"pin": "Пин, к которому подключен сервопривод",
|
||||
"apin": "Номер GPIO аналогового пина. Если -1, то функция отключена.",
|
||||
"amap": "Настройки преобразования значений аналога в нужный диапазон сервы, имеет смысл, если аналог включен."
|
||||
}
|
||||
},
|
||||
|
||||
"defActive": true,
|
||||
|
||||
"devices": {
|
||||
"esp32_4mb": [
|
||||
"https://github.com/RoboticsBrno/ServoESP32"
|
||||
],
|
||||
"esp8266_4mb": []
|
||||
}
|
||||
}
|
||||
72
src/modules/exec/Mcp23017/Mcp23017.cpp
Normal file
72
src/modules/exec/Mcp23017/Mcp23017.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
#include "Global.h"
|
||||
#include "classes/IoTItem.h"
|
||||
#include "classes/IoTGpio.h"
|
||||
#include <Adafruit_MCP23X17.h>
|
||||
|
||||
|
||||
class Mcp23017 : public IoTItem, IoTGpio {
|
||||
private:
|
||||
|
||||
public:
|
||||
Adafruit_MCP23X17 mcp;
|
||||
|
||||
Mcp23017(String parameters, int index): IoTItem(parameters), IoTGpio(index) {
|
||||
|
||||
}
|
||||
|
||||
void doByInterval() {
|
||||
|
||||
|
||||
//regEvent(value.valD, "Mcp23017");
|
||||
}
|
||||
|
||||
IoTGpio* getGpioDriver() {
|
||||
return this;
|
||||
}
|
||||
|
||||
void pinMode(uint8_t pin, uint8_t mode) {
|
||||
mcp.pinMode(pin, mode);
|
||||
}
|
||||
|
||||
void digitalWrite(uint8_t pin, uint8_t val) {
|
||||
mcp.digitalWrite(pin, val);
|
||||
}
|
||||
|
||||
int digitalRead(uint8_t pin) {
|
||||
return mcp.digitalRead(pin);
|
||||
}
|
||||
|
||||
void digitalInvert(uint8_t pin) {
|
||||
mcp.digitalWrite(pin, 1 - mcp.digitalRead(pin));
|
||||
}
|
||||
|
||||
~Mcp23017() {};
|
||||
};
|
||||
|
||||
|
||||
void* getAPI_Mcp23017(String subtype, String param) {
|
||||
if (subtype == F("Mcp23017")) {
|
||||
String addr;
|
||||
jsonRead(param, "addr", addr);
|
||||
Serial.printf("deviceAddress %s = %02x \n", addr.c_str(), hexStringToUint8(addr));
|
||||
|
||||
String index_str;
|
||||
jsonRead(param, "index", index_str);
|
||||
int index = index_str.toInt();
|
||||
if (index > 4) {
|
||||
Serial.println("MCP23X17 wrong index. Must be 0 - 4");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Mcp23017* newItem = new Mcp23017(param, index);
|
||||
if (!newItem->mcp.begin_I2C(hexStringToUint8(addr))) {
|
||||
Serial.println("MCP23X17 Init Error.");
|
||||
delete newItem;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return newItem;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
45
src/modules/exec/Mcp23017/modinfo.json
Normal file
45
src/modules/exec/Mcp23017/modinfo.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"menuSection": "Исполнительные устройства",
|
||||
|
||||
"configItem": [{
|
||||
"name": "Расширитель портов Mcp23017",
|
||||
"type": "Reading",
|
||||
"subtype": "Mcp23017",
|
||||
"id": "Mcp",
|
||||
"widget": "",
|
||||
"page": "",
|
||||
"descr": "",
|
||||
|
||||
"int": "0",
|
||||
"addr": "0x20",
|
||||
"index": 1
|
||||
}],
|
||||
|
||||
"about": {
|
||||
"authorName": "Ilya Belyakov",
|
||||
"authorContact": "https://t.me/Biveraxe",
|
||||
"authorGit": "https://github.com/biveraxe",
|
||||
"specialThanks": "",
|
||||
"moduleName": "Mcp23017",
|
||||
"moduleVersion": "1.0",
|
||||
"moduleDesc": "Добавляет в систему дополнительные GPIO для элементов, которые поддерживают такую функцию.",
|
||||
"propInfo": {
|
||||
"int": "Не используется",
|
||||
"addr": "Адрес устройства на шине, обычно 0x20",
|
||||
"index": "Значения от 1 до 4, где при выборе 1 будет нумерация pin 100-115, при выборе 2 200-215 и т.д."
|
||||
}
|
||||
},
|
||||
|
||||
"defActive": true,
|
||||
|
||||
"devices": {
|
||||
"esp32_4mb": [
|
||||
"adafruit/Adafruit MCP23017 Arduino Library@^2.0.2",
|
||||
"adafruit/Adafruit BusIO @ ^1.13.0"
|
||||
],
|
||||
"esp8266_4mb": [
|
||||
"adafruit/Adafruit MCP23017 Arduino Library@^2.0.2",
|
||||
"adafruit/Adafruit BusIO @ ^1.13.0"
|
||||
]
|
||||
}
|
||||
}
|
||||
135
src/modules/exec/Mp3/Mp3.cpp
Normal file
135
src/modules/exec/Mp3/Mp3.cpp
Normal file
@@ -0,0 +1,135 @@
|
||||
#include "Global.h"
|
||||
#include "classes/IoTItem.h"
|
||||
|
||||
#include "SoftwareSerial.h" // Подключаем библиотеку SoftwareSerial
|
||||
#include "DFRobotDFPlayerMini.h" // Подключаем библиотеку DFPlayerMini_Fast
|
||||
|
||||
|
||||
class Mp3 : public IoTItem {
|
||||
private:
|
||||
SoftwareSerial* mySerial;
|
||||
DFRobotDFPlayerMini* myMP3;
|
||||
|
||||
public:
|
||||
Mp3(String parameters): IoTItem(parameters) {
|
||||
String tmpstr;
|
||||
int volumetmp;
|
||||
jsonRead(parameters, "pins", tmpstr);
|
||||
int pinRx = selectFromMarkerToMarker(tmpstr, ",", 0).toInt();
|
||||
int pinTx = selectFromMarkerToMarker(tmpstr, ",", 1).toInt();
|
||||
mySerial = new SoftwareSerial(pinRx, pinTx);
|
||||
pinMode(pinRx, INPUT);
|
||||
pinMode(pinTx, OUTPUT);
|
||||
|
||||
jsonRead(parameters, "volume", volumetmp);
|
||||
|
||||
if (mySerial) {
|
||||
mySerial->begin(9600);
|
||||
myMP3 = new DFRobotDFPlayerMini();
|
||||
}
|
||||
if (myMP3) {
|
||||
myMP3->begin(*mySerial);
|
||||
myMP3->volume(volumetmp);
|
||||
}
|
||||
|
||||
value.isDecimal = false; // значение объекта всегда будет строка
|
||||
}
|
||||
|
||||
void doByInterval() {
|
||||
if (myMP3 && myMP3->available()) {
|
||||
switch (myMP3->readType()) {
|
||||
case TimeOut:
|
||||
value.valS = F("Time Out!");
|
||||
break;
|
||||
case WrongStack:
|
||||
value.valS = F("Stack Wrong!");
|
||||
break;
|
||||
case DFPlayerCardInserted:
|
||||
value.valS = F("Card Inserted!");
|
||||
break;
|
||||
case DFPlayerCardRemoved:
|
||||
value.valS = F("Card Removed!");
|
||||
break;
|
||||
case DFPlayerCardOnline:
|
||||
value.valS = F("Card Online!");
|
||||
break;
|
||||
case DFPlayerPlayFinished:
|
||||
value.valS = F("Play Finished!");
|
||||
break;
|
||||
case DFPlayerError:
|
||||
switch (myMP3->read()) {
|
||||
case Busy:
|
||||
value.valS = F("Card not found");
|
||||
break;
|
||||
case Sleeping:
|
||||
value.valS = F("Sleeping");
|
||||
break;
|
||||
case SerialWrongStack:
|
||||
value.valS = F("Get Wrong Stack");
|
||||
break;
|
||||
case CheckSumNotMatch:
|
||||
value.valS = F("Check Sum Not Match");
|
||||
break;
|
||||
case FileIndexOut:
|
||||
value.valS = F("File Index Out of Bound");
|
||||
break;
|
||||
case FileMismatch:
|
||||
value.valS = F("Cannot Find File");
|
||||
break;
|
||||
case Advertise:
|
||||
value.valS = F("In Advertise");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IoTValue execute(String command, std::vector<IoTValue> ¶m) {
|
||||
// реакция на вызов команды модуля из сценария
|
||||
// String command - имя команды после ID. (ID.Команда())
|
||||
// param - вектор ("массив") значений параметров переданных вместе с командой: ID.Команда("пар1", 22, 33) -> param[0].ValS = "пар1", param[1].ValD = 22
|
||||
|
||||
if (myMP3) {
|
||||
if (command == "enableLoop") {
|
||||
myMP3->enableLoop();
|
||||
} else if (command == "disableLoop") {
|
||||
myMP3->disableLoop();
|
||||
} else if (command == "randomAll") {
|
||||
myMP3->randomAll();
|
||||
} else if (command == "stop") {
|
||||
myMP3->stop();
|
||||
} else if (command == "volume") {
|
||||
if (param.size()) {
|
||||
myMP3->volume(param[0].valD);
|
||||
}
|
||||
} else if (command == "playFolder") {
|
||||
if (param.size()) {
|
||||
myMP3->playFolder(param[0].valD, param[1].valD); // (folderNum, fileNum)
|
||||
}
|
||||
} else if (command == "play") {
|
||||
myMP3->play(1); //Play the first mp3
|
||||
} else if (command == "next") {
|
||||
myMP3->next(); //Play next mp3
|
||||
} else if (command == "previous") {
|
||||
myMP3->previous(); //Play previous mp3
|
||||
}
|
||||
}
|
||||
|
||||
return {}; // команда поддерживает возвращаемое значения. Т.е. по итогу выполнения команды или общения с внешней системой, можно вернуть значение в сценарий для дальнейшей обработки
|
||||
}
|
||||
|
||||
~Mp3() {};
|
||||
};
|
||||
|
||||
void* getAPI_Mp3(String subtype, String param) {
|
||||
if (subtype == F("Mp3")) {
|
||||
return new Mp3(param);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
43
src/modules/exec/Mp3/modinfo.json
Normal file
43
src/modules/exec/Mp3/modinfo.json
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"menuSection": "Исполнительные устройства",
|
||||
|
||||
"configItem": [{
|
||||
"name": "MP3 плеер",
|
||||
"type": "Reading",
|
||||
"subtype": "Mp3",
|
||||
"id": "mp3",
|
||||
"widget": "",
|
||||
"page": "",
|
||||
"descr": "",
|
||||
|
||||
"int": 1,
|
||||
"pins": "14,12",
|
||||
"volume": 20
|
||||
}],
|
||||
|
||||
"about": {
|
||||
"authorName": "Ilya Belyakov",
|
||||
"authorContact": "https://t.me/Biveraxe",
|
||||
"authorGit": "https://github.com/biveraxe",
|
||||
"specialThanks": "",
|
||||
"moduleName": "Mp3",
|
||||
"moduleVersion": "1.0",
|
||||
"moduleDesc": "Позволяет управлять модулем проигрывания MP3 файлов с SD-карты по serial интерфейсу (DFplayer mini).",
|
||||
"propInfo": {
|
||||
"int": "Периодичность в секундах опроса состояния плеера.",
|
||||
"pins": "Список GPIO через запятую, к которым подключен плеер.",
|
||||
"volume": "Уровень громкости при инициализации."
|
||||
}
|
||||
},
|
||||
|
||||
"defActive": true,
|
||||
|
||||
"devices": {
|
||||
"esp32_4mb": [
|
||||
"dfrobot/DFRobotDFPlayerMini @ ^1.0.5"
|
||||
],
|
||||
"esp8266_4mb": [
|
||||
"dfrobot/DFRobotDFPlayerMini @ ^1.0.5"
|
||||
]
|
||||
}
|
||||
}
|
||||
74
src/modules/exec/Pwm32/Pwm32.cpp
Normal file
74
src/modules/exec/Pwm32/Pwm32.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
#include "Global.h"
|
||||
#include "classes/IoTItem.h"
|
||||
#include "Arduino.h"
|
||||
|
||||
#include "esp32-hal.h"
|
||||
#include "esp32-hal-ledc.h"
|
||||
|
||||
extern IoTGpio IoTgpio;
|
||||
|
||||
class Pwm32 : public IoTItem {
|
||||
private:
|
||||
int _pin;
|
||||
int _freq;
|
||||
int _apin, _oldValue;
|
||||
bool _freezVal = true;
|
||||
int _ledChannel;
|
||||
int _resolution;
|
||||
|
||||
public:
|
||||
Pwm32(String parameters): IoTItem(parameters) {
|
||||
_interval = _interval / 1000; // корректируем величину интервала int, теперь он в миллисекундах
|
||||
|
||||
jsonRead(parameters, "pin", _pin);
|
||||
jsonRead(parameters, "freq", _freq);
|
||||
jsonRead(parameters, "ledChannel", _ledChannel);
|
||||
jsonRead(parameters, "PWM_resolution", _resolution);
|
||||
|
||||
pinMode(_pin, OUTPUT);
|
||||
ledcSetup(_ledChannel, _freq, _resolution);
|
||||
ledcAttachPin(_pin, _ledChannel);
|
||||
ledcWrite(_ledChannel, value.valD);
|
||||
|
||||
_resolution = pow(2, _resolution); // переводим биты в значение
|
||||
|
||||
jsonRead(parameters, "apin", _apin);
|
||||
if (_apin >= 0) IoTgpio.pinMode(_apin, INPUT);
|
||||
}
|
||||
|
||||
void doByInterval() {
|
||||
if (_apin >= 0) {
|
||||
value.valD = map(IoTgpio.analogRead(_apin), 0, 4095, 0, _resolution);
|
||||
if (value.valD > _resolution - 6) value.valD = _resolution; // нивелируем погрешность установки мин и макс
|
||||
else if (value.valD < 9) value.valD = 0; // из-за смягчения значений
|
||||
if (abs(_oldValue - value.valD) > 20) {
|
||||
_oldValue = value.valD;
|
||||
ledcWrite(_ledChannel, value.valD);
|
||||
_freezVal = false;
|
||||
} else {
|
||||
if (!_freezVal) { // отправляем событие только раз после серии изменений, чтоб не спамить события
|
||||
regEvent(value.valD, "Pwm32");
|
||||
_freezVal = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setValue(IoTValue Value) {
|
||||
value = Value;
|
||||
ledcWrite(_ledChannel, value.valD);
|
||||
regEvent(value.valD, "Pwm32");
|
||||
}
|
||||
//=======================================================================================================
|
||||
|
||||
~Pwm32() {};
|
||||
};
|
||||
|
||||
|
||||
void* getAPI_Pwm32(String subtype, String param) {
|
||||
if (subtype == F("Pwm32")) {
|
||||
return new Pwm32(param);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
44
src/modules/exec/Pwm32/modinfo.json
Normal file
44
src/modules/exec/Pwm32/modinfo.json
Normal file
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"menuSection": "Исполнительные устройства",
|
||||
|
||||
"configItem": [{
|
||||
"name": "PWM ESP32",
|
||||
"type": "Writing",
|
||||
"subtype": "Pwm32",
|
||||
"id": "pwm",
|
||||
"widget": "range",
|
||||
"page": "Кнопки",
|
||||
"descr": "PWM",
|
||||
"int": 0,
|
||||
"pin": 2,
|
||||
"freq": 5000,
|
||||
"ledChannel": 2,
|
||||
"PWM_resolution": 10,
|
||||
"val": 0,
|
||||
"apin": -1
|
||||
}],
|
||||
|
||||
"about": {
|
||||
"authorName": "Avaks",
|
||||
"authorContact": "https://t.me/Avaks",
|
||||
"authorGit": "https://github.com/avaksru",
|
||||
"specialThanks": "Serghei Crasnicov @Serghei63",
|
||||
"moduleName": "Pwm32",
|
||||
"moduleVersion": "1.0",
|
||||
"moduleDesc": "Позволяет управлять Широтно-Импульсной Модуляцией на конкретном пине платы.",
|
||||
"propInfo": {
|
||||
"int": "Количество миллисекунд между опросами аналога. 0 - выключено.",
|
||||
"pin": "Управляемый пин",
|
||||
"apin": "Номер GPIO аналогового пина. Если -1, то функция отключена.",
|
||||
"ledChannel": "Канал ШИМ",
|
||||
"PWM_resolution": "Разрешение, определяет диапазон значений от 1 до 16 => от 1 до 65536",
|
||||
"freq": "Частота"
|
||||
}
|
||||
},
|
||||
|
||||
"defActive": true,
|
||||
|
||||
"devices": {
|
||||
"esp32_4mb": []
|
||||
}
|
||||
}
|
||||
64
src/modules/exec/Pwm8266/Pwm8266.cpp
Normal file
64
src/modules/exec/Pwm8266/Pwm8266.cpp
Normal file
@@ -0,0 +1,64 @@
|
||||
#include "Global.h"
|
||||
#include "classes/IoTItem.h"
|
||||
#include "Arduino.h"
|
||||
|
||||
extern IoTGpio IoTgpio;
|
||||
|
||||
class Pwm8266 : public IoTItem {
|
||||
private:
|
||||
int _pin;
|
||||
int _freq;
|
||||
int _apin, _oldValue;
|
||||
bool _freezVal = true;
|
||||
|
||||
public:
|
||||
Pwm8266(String parameters): IoTItem(parameters) {
|
||||
_interval = _interval / 1000; // корректируем величину интервала int, теперь он в миллисекундах
|
||||
|
||||
jsonRead(parameters, "pin", _pin);
|
||||
jsonRead(parameters, "freq", _freq);
|
||||
|
||||
IoTgpio.pinMode(_pin, OUTPUT);
|
||||
analogWriteFreq(_freq);
|
||||
IoTgpio.analogWrite(_pin, value.valD);
|
||||
|
||||
jsonRead(parameters, "apin", _apin);
|
||||
if (_apin >= 0) IoTgpio.pinMode(_apin, INPUT);
|
||||
}
|
||||
|
||||
void doByInterval() {
|
||||
if (_apin >= 0) {
|
||||
value.valD = IoTgpio.analogRead(_apin);
|
||||
if (value.valD > 1018) value.valD = 1024; // нивелируем погрешность установки мин и макс
|
||||
else if (value.valD < 9) value.valD = 0; // из-за смягчения значений
|
||||
if (abs(_oldValue - value.valD) > 5) {
|
||||
_oldValue = value.valD;
|
||||
analogWrite(_pin,value.valD);
|
||||
_freezVal = false;
|
||||
} else {
|
||||
if (!_freezVal) { // отправляем событие только раз после серии изменений, чтоб не спамить события
|
||||
regEvent(value.valD, "Pwm8266");
|
||||
_freezVal = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setValue(IoTValue Value) {
|
||||
value = Value;
|
||||
IoTgpio.analogWrite(_pin, value.valD);
|
||||
regEvent(value.valD, "Pwm8266");
|
||||
}
|
||||
//=======================================================================================================
|
||||
|
||||
~Pwm8266() {};
|
||||
};
|
||||
|
||||
|
||||
void* getAPI_Pwm8266(String subtype, String param) {
|
||||
if (subtype == F("Pwm8266")) {
|
||||
return new Pwm8266(param);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
40
src/modules/exec/Pwm8266/modinfo.json
Normal file
40
src/modules/exec/Pwm8266/modinfo.json
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"menuSection": "Исполнительные устройства",
|
||||
|
||||
"configItem": [{
|
||||
"name": "PWM ESP8266",
|
||||
"type": "Writing",
|
||||
"subtype": "Pwm8266",
|
||||
"id": "pwm",
|
||||
"widget": "range",
|
||||
"page": "Кнопки",
|
||||
"descr": "PWM",
|
||||
"int": 0,
|
||||
"pin": 15,
|
||||
"freq": 5000,
|
||||
"val": 0,
|
||||
"apin": -1
|
||||
}],
|
||||
|
||||
"about": {
|
||||
"authorName": "Avaks",
|
||||
"authorContact": "https://t.me/Avaks",
|
||||
"authorGit": "https://github.com/avaksru",
|
||||
"specialThanks": "Serghei Crasnicov @Serghei63",
|
||||
"moduleName": "Pwm8266",
|
||||
"moduleVersion": "1.0",
|
||||
"moduleDesc": "Позволяет управлять Широтно-Импульсной Модуляцией на конкретном пине платы.",
|
||||
"propInfo": {
|
||||
"int": "Количество миллисекунд между опросами аналога. 0 - выключено.",
|
||||
"pin": "Управляемый пин",
|
||||
"apin": "Номер GPIO аналогового пина. Если -1, то функция отключена.",
|
||||
"freq": "Частота"
|
||||
}
|
||||
},
|
||||
|
||||
"defActive": true,
|
||||
|
||||
"devices": {
|
||||
"esp8266_4mb": []
|
||||
}
|
||||
}
|
||||
70
src/modules/exec/SDcard/SDcard.cpp
Normal file
70
src/modules/exec/SDcard/SDcard.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
#include "Global.h"
|
||||
#include "classes/IoTItem.h"
|
||||
|
||||
|
||||
#include "FS.h" // SD Card ESP32
|
||||
#include "SD_MMC.h" // SD Card ESP32
|
||||
|
||||
class SDcard : public IoTItem {
|
||||
private:
|
||||
|
||||
public:
|
||||
SDcard(String parameters): IoTItem(parameters) {
|
||||
// jsonRead(parameters, "useLed", _useLed); // используем = 1 или нет = 0 подсветку (вспышку)
|
||||
// jsonRead(parameters, "ticker", _ticker); // тикать = 1 - сообщаем всем, что сделали снимок и он готов
|
||||
// jsonRead(parameters, "webTicker", _webTicker); // сообщать всем, что через веб попросили отдать картинку с камеры
|
||||
|
||||
Serial.println("Starting SD Card");
|
||||
if(!SD_MMC.begin()){
|
||||
Serial.println("SD Card Mount Failed");
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t cardType = SD_MMC.cardType();
|
||||
if(cardType == CARD_NONE){
|
||||
Serial.println("No SD Card attached");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void savePicture(String path, IoTValue srcValue) {
|
||||
if (srcValue.extBinInfoSize) {
|
||||
fs::FS &fs = SD_MMC;
|
||||
File file = fs.open(path.c_str(), FILE_WRITE);
|
||||
if(!file){
|
||||
Serial.println("Failed to open file in writing mode");
|
||||
}
|
||||
else {
|
||||
file.write(srcValue.extBinInfo, srcValue.extBinInfoSize); // payload (image), payload length
|
||||
Serial.printf("Picture file name: %s | bufsize: %d\n", path.c_str(), srcValue.extBinInfoSize);
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
void doByInterval() {
|
||||
|
||||
}
|
||||
|
||||
IoTValue execute(String command, std::vector<IoTValue> ¶m) {
|
||||
if (command == "saveBin") {
|
||||
if (param.size() == 2) {
|
||||
savePicture (param[0].valS, param[1]);
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
~SDcard() {
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
void* getAPI_SDcard(String subtype, String param) {
|
||||
if (subtype == F("SDcard")) {
|
||||
return new SDcard(param);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
36
src/modules/exec/SDcard/modinfo.json
Normal file
36
src/modules/exec/SDcard/modinfo.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"menuSection": "Исполнительные устройства",
|
||||
|
||||
"configItem": [{
|
||||
"name": "SD карта",
|
||||
"type": "Writing",
|
||||
"subtype": "SDcard",
|
||||
"id": "sd",
|
||||
"widget": "",
|
||||
"page": "",
|
||||
"descr": "",
|
||||
|
||||
"int": 1
|
||||
}],
|
||||
|
||||
"about": {
|
||||
"authorName": "Ilya Belyakov",
|
||||
"authorContact": "https://t.me/Biveraxe",
|
||||
"authorGit": "https://github.com/biveraxe",
|
||||
"specialThanks": "",
|
||||
"moduleName": "SDcard",
|
||||
"moduleVersion": "1.0",
|
||||
"moduleDesc": "Предназначен для специальной платы esp32 со встроенной камерой. Добавляет в прошивку функцию сохранения фото из оперативной памяти. Работает в паре с EspCam. Это экспериментальные модули и в будущем планируется пересобрать их.",
|
||||
"propInfo": {
|
||||
"int": "Не используется."
|
||||
}
|
||||
},
|
||||
|
||||
"defActive": false,
|
||||
|
||||
"devices": {
|
||||
"esp32_4mb": [
|
||||
"espressif/esp32-camera @ ^2.0.0"
|
||||
]
|
||||
}
|
||||
}
|
||||
138
src/modules/exec/SysExt/SysExt.cpp
Normal file
138
src/modules/exec/SysExt/SysExt.cpp
Normal file
@@ -0,0 +1,138 @@
|
||||
#include "Global.h"
|
||||
#include "classes/IoTItem.h"
|
||||
#include "classes/IoTRTC.h"
|
||||
extern IoTRTC *watch;
|
||||
|
||||
// Пример модуля расширения возможностей системы на примере добавления новых команд в сценарии
|
||||
// При комбинации использования doByInterval() и execute() можно обеспечить интеграцию с внешними сервисами, такими как Telegram, например.
|
||||
//
|
||||
|
||||
class SysExt : public IoTItem {
|
||||
public:
|
||||
SysExt(String parameters): IoTItem(parameters) {
|
||||
// инициализация внутренних переменных и объектов для взаимодействия с внешними системами
|
||||
//jsonRead(parameters, "addr", addr); // получаем параметры из настроек модуля. Наименования могут быть любыми.
|
||||
}
|
||||
|
||||
void doByInterval() {
|
||||
// выполнение периодических проверок каждые Int секунд из настроек модуля
|
||||
|
||||
//regEvent(Значение, Описание); // регистрация найденного события после проверок для запуска сценариев и других реакций в системе
|
||||
}
|
||||
|
||||
//void loop() {
|
||||
// выполнение необходимых проверок в теле основного цикла программы.
|
||||
// ВАЖНО: 1. при использовании loop() отключается doByInterval()
|
||||
// 2. любые заминки в данном цикле повлияют на общую работу системы
|
||||
//}
|
||||
|
||||
IoTValue execute(String command, std::vector<IoTValue> ¶m) {
|
||||
// реакция на вызов команды модуля из сценария
|
||||
// String command - имя команды после ID. (ID.Команда())
|
||||
// param - вектор ("массив") значений параметров переданных вместе с командой: ID.Команда("пар1", 22, 33) -> param[0].ValS = "пар1", param[1].ValD = 22
|
||||
|
||||
if (command == "reboot") { // выполняем код при вызове спец команды из сценария: ID.reboot();
|
||||
ESP.restart();
|
||||
} else if (command == "digitalRead") {
|
||||
if (param.size()) {
|
||||
IoTgpio.pinMode(param[0].valD, INPUT);
|
||||
value.valD = IoTgpio.digitalRead(param[0].valD);
|
||||
return value;
|
||||
}
|
||||
} else if (command == "analogRead") {
|
||||
if (param.size()) {
|
||||
IoTgpio.pinMode(param[0].valD, INPUT);
|
||||
value.valD = IoTgpio.analogRead(param[0].valD);
|
||||
return value;
|
||||
}
|
||||
} else if (command == "digitalWrite") {
|
||||
if (param.size() == 2) {
|
||||
IoTgpio.pinMode(param[0].valD, OUTPUT);
|
||||
IoTgpio.digitalWrite(param[0].valD, param[1].valD);
|
||||
return {};
|
||||
}
|
||||
} else if (command == "digitalInvert") {
|
||||
if (param.size()) {
|
||||
IoTgpio.pinMode(param[0].valD, OUTPUT);
|
||||
IoTgpio.digitalInvert(param[0].valD);
|
||||
return {};
|
||||
}
|
||||
} else if (command == "getTime") {
|
||||
if (param.size()) {
|
||||
value.isDecimal = false;
|
||||
value.valS = watch->gettime(param[0].valS.c_str());
|
||||
return value;
|
||||
}
|
||||
} else if (command == "getHours") {
|
||||
value.valD = watch->Hours; // Часы 0-23
|
||||
value.isDecimal = true;
|
||||
return value;
|
||||
} else if (command == "getMinutes") {
|
||||
value.valD = watch->minutes; // Минуты 0-59
|
||||
value.isDecimal = true;
|
||||
return value;
|
||||
} else if (command == "getSeconds") {
|
||||
value.valD = watch->seconds; // Секунды 0-59
|
||||
value.isDecimal = true;
|
||||
return value;
|
||||
} else if (command == "getMonth") {
|
||||
value.valD = watch->month; // Месяц 1-12
|
||||
value.isDecimal = true;
|
||||
return value;
|
||||
} else if (command == "getDay") {
|
||||
value.valD = watch->day; // День месяца 1-31
|
||||
value.isDecimal = true;
|
||||
return value;
|
||||
} else if (command == "deepSleep") {
|
||||
if (param.size()) {
|
||||
Serial.printf("Ушел спать на %d сек...", (int)param[0].valD);
|
||||
#ifdef ESP32
|
||||
esp_sleep_enable_timer_wakeup(param[0].valD * 1000000);
|
||||
delay(1000);
|
||||
esp_deep_sleep_start();
|
||||
#else
|
||||
ESP.deepSleep(param[0].valD * 1000000);
|
||||
#endif
|
||||
}
|
||||
return {};
|
||||
}
|
||||
// } else if (command == "ModemSleep") {
|
||||
// Serial.printf("Выключил все радио...");
|
||||
// #ifdef ESP32
|
||||
// WiFi.setSleep(true);
|
||||
// if (!setCpuFrequencyMhz(80)){
|
||||
// Serial2.println("Not valid frequency!");
|
||||
// }
|
||||
// #else
|
||||
// //WiFi.disconnect();
|
||||
// adc_power_off();
|
||||
// WiFi.disconnect(true); // Disconnect from the network
|
||||
// WiFi.mode(WIFI_OFF); // Switch WiFi off
|
||||
// #endif
|
||||
// return {};
|
||||
// } else if (command == "ModemWakeup") {
|
||||
// Serial.printf("Включил все радио...");
|
||||
// #ifdef ESP32
|
||||
// setCpuFrequencyMhz(240);
|
||||
// #else
|
||||
// WiFi.forceSleepWake();
|
||||
// delay(1);
|
||||
// // восстанавливаем коннект тут
|
||||
|
||||
// wifi_set_sleep_type(NONE_SLEEP_T);
|
||||
// #endif
|
||||
// return {};
|
||||
// }
|
||||
return {}; // команда поддерживает возвращаемое значения. Т.е. по итогу выполнения команды или общения с внешней системой, можно вернуть значение в сценарий для дальнейшей обработки
|
||||
}
|
||||
|
||||
~SysExt() {};
|
||||
};
|
||||
|
||||
void* getAPI_SysExt(String subtype, String param) {
|
||||
if (subtype == F("SysExt")) {
|
||||
return new SysExt(param);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
34
src/modules/exec/SysExt/modinfo.json
Normal file
34
src/modules/exec/SysExt/modinfo.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"menuSection": "Исполнительные устройства",
|
||||
|
||||
"configItem": [{
|
||||
"name": "Доп. функции системы",
|
||||
"type": "Reading",
|
||||
"subtype": "SysExt",
|
||||
"id": "SysExt",
|
||||
"widget": "",
|
||||
"page": "",
|
||||
"descr": "",
|
||||
"int": 15
|
||||
}],
|
||||
|
||||
"about": {
|
||||
"authorName": "Ilya Belyakov",
|
||||
"authorContact": "https://t.me/Biveraxe",
|
||||
"authorGit": "https://github.com/biveraxe",
|
||||
"specialThanks": "",
|
||||
"moduleName": "SysExt",
|
||||
"moduleVersion": "1.0",
|
||||
"moduleDesc": "Добавляет в систему дополнительные функции. Например, возможность прямого управления GPIO из сценариев.",
|
||||
"propInfo": {
|
||||
"int": "Не используется"
|
||||
}
|
||||
},
|
||||
|
||||
"defActive": true,
|
||||
|
||||
"devices": {
|
||||
"esp32_4mb": [],
|
||||
"esp8266_4mb": []
|
||||
}
|
||||
}
|
||||
141
src/modules/exec/Telegram/Telegram.cpp
Normal file
141
src/modules/exec/Telegram/Telegram.cpp
Normal file
@@ -0,0 +1,141 @@
|
||||
#include "Global.h"
|
||||
#include "classes/IoTItem.h"
|
||||
|
||||
#include "CTBot.h"
|
||||
|
||||
String uint64ToString(uint64_t input) {
|
||||
String result = "";
|
||||
uint8_t base = 10;
|
||||
|
||||
do {
|
||||
char c = input % base;
|
||||
input /= base;
|
||||
|
||||
if (c < 10)
|
||||
c +='0';
|
||||
else
|
||||
c += 'A' - 10;
|
||||
result = c + result;
|
||||
} while (input);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
class Telegram : public IoTItem {
|
||||
private:
|
||||
CTBot _myBot;
|
||||
String _token;
|
||||
bool _autos;
|
||||
bool _receiveMsg;
|
||||
int64_t _chatID;
|
||||
|
||||
String _prevMsg = "";
|
||||
|
||||
void telegramMsgParse(String msg) {
|
||||
if (msg.indexOf("set") != -1) {
|
||||
msg = deleteBeforeDelimiter(msg, "_");
|
||||
generateOrder(selectToMarker(msg, "_"), selectToMarkerLast(msg, "_"));
|
||||
_myBot.sendMessage(_chatID, "order done");
|
||||
SerialPrint("<-", F("Telegram"), "chat ID: " + uint64ToString(_chatID) + ", msg: " + String(msg));
|
||||
} else if (msg.indexOf("get") != -1) {
|
||||
msg = deleteBeforeDelimiter(msg, "_");
|
||||
IoTItem* item = findIoTItem(msg);
|
||||
if (item) {
|
||||
_myBot.sendMessage(_chatID, item->getValue());
|
||||
SerialPrint("<-", F("Telegram"), "chat ID: " + uint64ToString(_chatID) + ", msg: " + String(msg));
|
||||
}
|
||||
} else if (msg.indexOf("all") != -1) {
|
||||
String list = returnListOfParams();
|
||||
_myBot.sendMessage(_chatID, list);
|
||||
SerialPrint("<-", F("Telegram"), "chat ID: " + uint64ToString(_chatID) + "\n" + list);
|
||||
} else if (msg.indexOf("help") != -1) {
|
||||
_myBot.sendMessage(_chatID, "ID: " + chipId);
|
||||
_myBot.sendMessage(_chatID, "chatID: " + uint64ToString(_chatID));
|
||||
_myBot.sendMessage(_chatID, F("Wrong order, use /all to get all values, /get_id to get value, or /set_id_value to set value"));
|
||||
} else {
|
||||
setValue(msg);
|
||||
}
|
||||
}
|
||||
|
||||
String returnListOfParams() {
|
||||
String out;
|
||||
for (std::list<IoTItem*>::iterator it = IoTItems.begin(); it != IoTItems.end(); ++it) {
|
||||
if ((*it)->iAmLocal) out = out + (*it)->getID() + ": " + (*it)->getValue() + "\n";
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
public:
|
||||
Telegram(String parameters): IoTItem(parameters) {
|
||||
jsonRead(parameters, "token", _token);
|
||||
jsonRead(parameters, "autos", _autos);
|
||||
jsonRead(parameters, "receiveMsg", _receiveMsg);
|
||||
|
||||
String tmp;
|
||||
jsonRead(parameters, "chatID", tmp);
|
||||
_chatID = atoll(tmp.c_str());
|
||||
|
||||
#ifdef ESP32
|
||||
_myBot.useDNS(true);
|
||||
#endif
|
||||
|
||||
_myBot.setTelegramToken(_token);
|
||||
_myBot.enableUTF8Encoding(true);
|
||||
}
|
||||
|
||||
void doByInterval() {
|
||||
if (_receiveMsg) {
|
||||
TBMessage msg;
|
||||
if (_myBot.getNewMessage(msg)) {
|
||||
SerialPrint("->", F("Telegram"), "chat ID: " + uint64ToString(msg.sender.id) + ", msg: " + msg.text);
|
||||
if (_autos) {
|
||||
_chatID = msg.sender.id;
|
||||
}
|
||||
telegramMsgParse(String(msg.text));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IoTValue execute(String command, std::vector<IoTValue> ¶m) {
|
||||
if (command == "sendMsg") {
|
||||
if (param.size()) {
|
||||
String strTmp;
|
||||
if (param[0].isDecimal) strTmp = param[0].valD; else strTmp = param[0].valS;
|
||||
sendTelegramMsg(false, strTmp);
|
||||
}
|
||||
} else if (command == "sendOftenMsg") {
|
||||
if (param.size()) {
|
||||
String strTmp;
|
||||
if (param[0].isDecimal) strTmp = param[0].valD; else strTmp = param[0].valS;
|
||||
sendTelegramMsg(true, strTmp);
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void sendTelegramMsg(bool often, String msg) {
|
||||
if (often) {
|
||||
_myBot.sendMessage(_chatID, msg);
|
||||
SerialPrint("<-", F("Telegram"), "chat ID: " + uint64ToString(_chatID) + ", msg: " + msg);
|
||||
} else {
|
||||
if (_prevMsg != msg) {
|
||||
_prevMsg = msg;
|
||||
_myBot.sendMessage(_chatID, msg);
|
||||
SerialPrint("<-", F("Telegram"), "chat ID: " + uint64ToString(_chatID) + ", msg: " + msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~Telegram() {
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
void* getAPI_Telegram(String subtype, String param) {
|
||||
if (subtype == F("Telegram")) {
|
||||
return new Telegram(param);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
46
src/modules/exec/Telegram/modinfo.json
Normal file
46
src/modules/exec/Telegram/modinfo.json
Normal file
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"menuSection": "Исполнительные устройства",
|
||||
|
||||
"configItem": [{
|
||||
"name": "Телеграм-Бот",
|
||||
"type": "Writing",
|
||||
"subtype": "Telegram",
|
||||
"id": "tg",
|
||||
"widget": "",
|
||||
"page": "",
|
||||
"descr": "",
|
||||
"int": 10,
|
||||
|
||||
"token": "",
|
||||
"autos": 1,
|
||||
"receiveMsg": 0,
|
||||
"chatID": ""
|
||||
}],
|
||||
|
||||
"about": {
|
||||
"authorName": "Ilya Belyakov",
|
||||
"authorContact": "https://t.me/Biveraxe",
|
||||
"authorGit": "https://github.com/biveraxe",
|
||||
"specialThanks": "",
|
||||
"moduleName": "Telegram",
|
||||
"moduleVersion": "1.0",
|
||||
"moduleDesc": "Добавляет возможность отправлять сообщения от имени бота контакту в Телеграм-чате и получать команды.",
|
||||
"propInfo": {
|
||||
"token": "Токен для авторизации бота в системе Telegram",
|
||||
"autos": "Автоматически(1) или нет(0) запоминать ChatID по входящим сообщениям. Т.е. бот будет информировать тех, кто последний прислал сообщение.",
|
||||
"receiveMsg": "Обрабатывать(1) или нет(0) входящие сообщения.",
|
||||
"chatID": "ИД диалога с контактом. Необходим для отправки сообщений именно вам."
|
||||
}
|
||||
},
|
||||
|
||||
"defActive": false,
|
||||
|
||||
"devices": {
|
||||
"esp32_4mb": [
|
||||
"CTBot @2.1.9"
|
||||
],
|
||||
"esp8266_4mb": [
|
||||
"CTBot @2.1.9"
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user