diff --git a/src/modules/sensors/ExampleModule/ExampleModule.cpp b/src/modules/sensors/ExampleModule/ExampleModule.cpp new file mode 100644 index 00000000..871fe1e7 --- /dev/null +++ b/src/modules/sensors/ExampleModule/ExampleModule.cpp @@ -0,0 +1,234 @@ +//======================================================================================================= +// Это файл сенсора, в нем осуществляется чтение сенсора. +// для добавления сенсора вам нужно скопировать этот файл и заменить в нем текст ExamleModule на название вашего сенсора +// Название должно быть уникальным, коротким и отражать суть сенсора. + +// Обязательные библиотеки из ядра IoTM +#include "Global.h" +#include "classes/IoTItem.h" + +//!Здесь подключаем стороннюю библиотеку при необходимости (ExternalLibrary заменить) +//#include +#include "ExternalLibrary.h" //удалить, только для примера. Внешние библиотеки правильно в <> + +//! Объяевляем класс IoTGpio для работы с GPIO +extern IoTGpio IoTgpio; + +//========================================================================================================= +//========================================================================================================= +// Объявление сторонней библиотекит с использованием глобавльных объектов +//======================================================================================================= +//! Объявляем стороннюю библиотеку при необходимости (ExternalLibrary заменить) +// !!! ЗДЕСЬ И ДАЛЕЕ libXX НАЗВАТЬ уникальным именем) +ExternalLibrary *libXX = nullptr; + +// Функция инициализации библиотечного класса, возвращает Единстрвенный указать на библиотеку +// instanceLibXX НАЗВАТЬ по наименованию модуля (instanceДатчикХ) +// ПРИ НЕОБХДИМОСТИ передаем любые нужные параметры для инициализации библиотеки (в данном случае PIN) +// !!! ВЫзвать данную функцию нужно хотябы один раз, +// но в каждом конструкторе класса модуля ExampleModule_A, ExampleModule_B и т.д. +// или можно вывывать постоянно при обращении к библиотеке, типа: instanceLibXX().READ_LIB_DATA_OTHER(); +ExternalLibrary *instanceLibXX(int pin) +{ + if (!libXX) + { // Если библиотека ранее инициализировалась, то просто вернем указатель + // Инициализируем библиотеку + libXX = new ExternalLibrary(); + libXX->begin(pin); // При необходимости делаем begin библиотеке + } + return libXX; +} + + +//========================================================================================================= +//========================================================================================================= +// Первый класс модуля для определения 1-го элемента (параметра) +// Служит для запроса и отображения парметра/элемента датчика +// IoTManager система модульная: один парметр - один элемент (класс) +// +//========================================================================================================= +//========================================================================================================= +// ребенок - родитель +class ExampleModule_A : public IoTItem +{ +private: + //======================================================================================================= + // Секция переменных. + // Это секция где Вы можете объявлять переменные и объекты arduino библиотек, что бы + // впоследствии использовать их в loop и setup + unsigned int _pin; + // пользовательская переменная, в данном случае для считывания аналогового сигнала + int adc; + +public: + //======================================================================================================= + // setup() + // это аналог setup из arduino. Здесь вы можете выполнять методы инициализации сенсора. + // Такие как ...begin и подставлять в них параметры полученные из web интерфейса. + // Все параметры хранятся в перемененной parameters, вы можете прочитать любой параметр используя jsonRead функции: + // jsonReadStr, jsonReadBool, jsonReadInt + ExampleModule_A(String parameters) : IoTItem(parameters) + { + //Читаем пользовательскую переменную PIN, должна быть объявлена в в modeinfo.json + _pin = jsonReadInt(parameters, "pin"); + // другой вариант чтения парметров модуля + jsonRead(parameters, F("int"), _interval, false); + } + + //======================================================================================================= + // doByInterval() - основная функция периодической работы + // это аналог loop из arduino, но вызываемый каждые int секунд, заданные в настройках. Здесь вы должны выполнить чтение вашего сенсора + // а затем выполнить regEvent - это регистрация произошедшего события чтения + // здесь так же доступны все переменные из секции переменных, и полученные в setup + // если у сенсора несколько величин то делайте несколько regEvent + // не используйте delay - помните, что данный loop общий для всех модулей. Если у вас планируется длительная операция, постарайтесь разбить ее на порции + // и выполнить за несколько тактов + void doByInterval() + { + // Пример получения данных из библиотеки, где READ_LIB_DATA_OTHER - функция Вашей библиотеки + value.valD = instanceLibXX(_pin)->READ_LIB_DATA_OTHER(); + // Здесь Наменование произвольным но понятным к какому модулю относится + regEvent(value.valD, "ExampleModule"); // обязательный вызов хотяб один для регистрации события в ядре IoTM + } + + //======================================================================================================= + // loop(), если не нужно переопределять, удалить. + // полный аналог loop() из arduino. Нужно помнить, что все модули имеют равный поочередный доступ к центральному loop(), поэтому, необходимо следить + // за задержками в алгоритме и не создавать пауз. Кроме того, данная версия перегружает родительскую, поэтому doByInterval() отключается, если + // не повторить механизм расчета интервалов. + void loop() + { + // Пример получения данных с аналоговым датчиком + adc = IoTgpio.analogRead(_pin); + + // Блок вызова doByInterval, так как если определили loop, то сам он не вызовится + currentMillis = millis(); + difference = currentMillis - prevMillis; + if (difference >= _interval) + { + prevMillis = millis(); + this->doByInterval(); + } + } + + ~ExampleModule_A(){}; +}; + +//========================================================================================================= +//========================================================================================================= +// Второй класс модуля для определения 2-го элемента (параметра) +// Делается по аналогии с первым классом, служит для запроса и отображения другого парметра если их несколько с одного датчика +// IoTManager система модульная: один парметр - один элемент (класс) +// +// Содержит описание дополнительных методов onModuleOrder и execute +//========================================================================================================= +//========================================================================================================= +class ExampleModule_B : public IoTItem +{ +private: +//Пользовательские переменные + unsigned int _pin; +public: + ExampleModule_B(String parameters) : IoTItem(parameters) + { + //Читаем пользовательскую переменную PIN, должна быть объявлена в в modeinfo.json + _pin = jsonReadInt(parameters, "pin"); + //Можно инициализировать библиотеку один раз, а потом используем указатель + instanceLibXX(_pin); + libXX->READ_LIB_DATA_OTHER(); + } + + void doByInterval() + { + // Пример получения данных из библиотеки, где READ_LIB_DATA_OTHER - функция Вашей библиотеки + value.valD = libXX->READ_LIB_DATA_OTHER(); + // Здесь Наменование произвольным но понятным к какому модулю относится + regEvent(value.valD, "ExampleModule"); // обязательный вызов хотяб один для регистрации события в ядре IoTM + } + +//================ обработка кнопок из конфигурации =================== + // Хук (переопределение виртуальной функции) для обработки кнопки (в value будут данные с собственной панели ввода) + // Что бы кнопка была без поля ввода, нужно в modeinfo.json указать "btn-Example": nil + void onModuleOrder(String &key, String &value) + { + if (key == "Example") // название кнопки btn-Example + { + SerialPrint("i", F("Sensor ExampleModule"), "User run calibration " + value); + // ЧТО ТО Делаем + } + } + +//================ обработка команд из сценария=================== + // Хук (переопределение виртуальной функции) для обработки команды из сценария (в param будут даныые переданные в функции в сценарии) + IoTValue execute(String command, std::vector ¶m) + { + if (command == "expampleFunc") + { + if (param.size()) + { + // Забираем данные из другого модуля по его ID + // Если в сценарии передадим id модуля + String value = getItemValue(param[0].valS); + // Что то делаем с этим параметром + return {}; + } + } + else if (command == "expample2") + { + if (param.size() == 2) + { + SerialPrint("i", F("Sensor ExampleModule"), "expample2: " + param[0].valS + ", " + param[1].valS); + // Передаем полученные данные на дальнейшую обработку + // foo(param[0].valS, param[1].valS); + return {}; + } + } + else if (command == "expampleAny") + { + if (param.size() >= 1) + { + int sizeOfParam = param.size(); + for (unsigned int i = 0; i < sizeOfParam; i++) + { + SerialPrint("i", F("Sensor ExampleModule"), "expampleAny: " + param[i].valS); + // Что то делаем с каждым принятым значением + // foo(param[i].valD); + } + } + } + return {}; + } + + void foo(String logid, String value) + { + // Прсото пример кокой-то функции + } + + ~ExampleModule_B(){}; +}; + + +//========================================================================================================= +//========================================================================================================= +// Функция для связи модуля с ядром IoTM +// !!! ЗДЕСЬ getAPI_ИМЯ ИМЯ должно совпадать с "moduleName" из modeinfo.json +// после замены названия сенсора, на функцию можно не обращать внимания +// если сенсор предполагает использование общего объекта библиотеки для нескольких экземпляров сенсора, то в данной функции необходимо предусмотреть +// создание и контроль соответствующих глобальных переменных +//========================================================================================================= +//========================================================================================================= +void *getAPI_ExampleModule(String subtype, String param) +{ + if (subtype == F("ExampleModule_A")) + { // !!! ЗДЕСЬ subtype ДОЛЖЕН СОВПАДАТЬ С subtype из modeinfo.json + return new ExampleModule_A(param); + } + else if (subtype == F("ExampleModule_B")) + { // !!! ЗДЕСЬ subtype ДОЛЖЕН СОВПАДАТЬ С subtype из modeinfo.json + return new ExampleModule_B(param); + } + else + { + return nullptr; + } +} diff --git a/src/modules/sensors/ExampleModule/ExternalLibrary.h b/src/modules/sensors/ExampleModule/ExternalLibrary.h new file mode 100644 index 00000000..f19737de --- /dev/null +++ b/src/modules/sensors/ExampleModule/ExternalLibrary.h @@ -0,0 +1,38 @@ +#pragma once + +/******************************************************************************* + ** ** + ** УДАЛИТЬ ЭТО ПРОСТО ПРИМЕР БИБЛИОТЕКИ ** + ** ** + *******************************************************************************/ + +class ExternalLibrary +{ +private: + /* data */ +public: + ExternalLibrary(/* args */); + + ~ExternalLibrary(); + void begin (int pin); + float READ_LIB_DATA_OTHER(); +}; + +ExternalLibrary::ExternalLibrary(/* args */) +{ +} + +ExternalLibrary::~ExternalLibrary() +{ +} + +void ExternalLibrary::begin(int pin) +{ + +} + +float ExternalLibrary::READ_LIB_DATA_OTHER() +{ + static float f = 0; + return f++; +} \ No newline at end of file diff --git a/src/modules/sensors/ExampleModule/modinfo.json b/src/modules/sensors/ExampleModule/modinfo.json new file mode 100644 index 00000000..083b37a3 --- /dev/null +++ b/src/modules/sensors/ExampleModule/modinfo.json @@ -0,0 +1,82 @@ +{ + "menuSection": "Сенсоры", + "configItem": [ + { + "global": 0, + "name": "Пример датчика А", + "type": "Reading", + "subtype": "ExampleModule_A", + "id": "Tmp", + "widget": "anydataTmp", + "page": "Сенсоры", + "descr": "Температура", + "int": 15, + "pin": "32", + "round": 1 + }, + { + "global": 0, + "name": "Пример датчика Б", + "type": "Reading", + "subtype": "ExampleModule_B", + "id": "Press", + "widget": "anydataMm", + "page": "Сенсоры", + "descr": "Давление", + "int": 15, + "pin": "32", + "round": 1, + "btn-Example": 100 + } + ], + "about": { + "authorName": "NAME", + "authorContact": "https://t.me/NAME", + "authorGit": "https://github.com/NAME", + "exampleURL": "https://iotmanager.org/wiki", + "specialThanks": "", + "moduleName": "ExampleModule", + "moduleVersion": "1.0", + "usedRam": { + "esp32_4mb": 15, + "esp8266_4mb": 15 + }, + "title": "Название модуля", + "moduleDesc": "Описание модуля. Что позволяет получить. Особенности работы", + "propInfo": { + "pin": "Аналоговый GPIO номер, к которому подключен датчик.", + "int": "Количество секунд между опросами датчика", + "btn-Example": "Кнопка Example. В поле указать ......" + }, + "funcInfo": [ + { + "name": "expampleFunc", + "descr": "Пример функции вызываемой из сценария. Принимает Id другого модуля и смотрит его значение", + "params": ["ID стороннего модуля"] + }, + { + "name": "expample2", + "descr": "Второй Пример функции вызываемой из сценария.", + "params": ["Описание педедаваемого параметра", + "параметр 2"] + }, + { + "name": "expampleAny", + "descr": "Третий Пример функции вызываемой из сценария. С неограниченным числом параметров", + "params": ["Описание педедаваемых параметров"] + } + ] + }, + "defActive": false, + "usedLibs": { + "esp32_4mb": [], + "esp32s2_4mb": [], + "esp8266_4mb": [], + "esp8266_1mb": [], + "esp8266_1mb_ota": [], + "esp8285_1mb": [], + "esp8285_1mb_ota": [], + "esp8266_2mb": [], + "esp8266_2mb_ota": [] + } +} \ No newline at end of file