diff --git a/myProfile.json b/myProfile.json index de8ef3fd..c5e68598 100644 --- a/myProfile.json +++ b/myProfile.json @@ -133,6 +133,10 @@ "path": "src/modules/sensors/Emon", "active": false }, + { + "path": "src/modules/sensors/ExampleModule", + "active": false + }, { "path": "src/modules/sensors/ExternalMQTT", "active": false @@ -165,6 +169,10 @@ "path": "src/modules/sensors/Ina219", "active": false }, + { + "path": "src/modules/sensors/Ina226", + "active": false + }, { "path": "src/modules/sensors/IoTWiegand", "active": false diff --git a/platformio.ini b/platformio.ini index 2044bb55..de3940b4 100644 --- a/platformio.ini +++ b/platformio.ini @@ -8,7 +8,7 @@ lib_deps_external = knolleary/PubSubClient [env] -extra_scripts = pre:prebuildscript.py +extra_scripts = pre:tools/prebuildscript.py [env:esp8266_1mb_ota] lib_deps = @@ -505,16 +505,19 @@ build_src_filter = + + + [env:esp32s2_4mb_fromitems] lib_deps = build_src_filter = + + + + + + + + + - + + + + + + diff --git a/prebuildscript.py b/prebuildscript.py deleted file mode 100644 index dc8114f3..00000000 --- a/prebuildscript.py +++ /dev/null @@ -1,13 +0,0 @@ - -import os -import configparser - -config = configparser.ConfigParser() # создаём объекта парсера INI -config.read("platformio.ini") -deviceName = config["platformio"]["default_envs"] -# удаляем объектный файл где используется время сборки, для обновления -try: - os.remove("./.pio/build/"+deviceName+"/src/Main.cpp.o") -except OSError as e: - # If it fails, inform the user. - print("Error: %s - %s." % (e.filename, e.strerror)) \ No newline at end of file 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 diff --git a/src/modules/sensors/Ina219/Ina219.cpp b/src/modules/sensors/Ina219/Ina219.cpp index b81843f0..60269a1a 100644 --- a/src/modules/sensors/Ina219/Ina219.cpp +++ b/src/modules/sensors/Ina219/Ina219.cpp @@ -1,68 +1,60 @@ /****************************************************************** - Used Adafruit INA219 Current Sensor - Support for INA219 - https://github.com/adafruit/Adafruit_INA219 + Used GyverINA Current Sensor + Support for INA219 INA226 + https://github.com/GyverLibs/GyverINA - adapted for version 4dev @Serghei63 + adapted for version 4dev @Mit4bmw ******************************************************************/ #include "Global.h" #include "classes/IoTItem.h" #include -#include +#include #include -// Adafruit_INA219 ina219; -// Структура для хранения данных с датчика + + +// Структура для хранения настроек датчика struct Ina219Value { - float shuntvoltage = 0; - float busvoltage = 0; + float shunt = 0; + float maxV = 0; }; -// глобальные списки необходимы для хранения данных, полученных разными датчиками из модуля. Ключ - адрес -std::map ina219ValueArray; + +// глобальные списки необходимы для хранения Модуля Настроек. Ключ - адрес +std::map ina219SettingArray; // глобальные списки необходимы для хранения объектов используемых разными датчиками из модуля. Ключ - адрес -std::map ina219Array; +std::map ina219Array; // Функция инициализации библиотечного класса, возвращает Единстрвенный указать на библиотеку -Adafruit_INA219 *instanceIna219(uint8_t ADDR) +INA219 *instanceIna219(uint8_t ADDR) { /** default I2C address **/ if (ADDR == 0) - ADDR = INA219_ADDRESS; // 1000000 (A0+A1=GND) + ADDR = 0x40; // 1000000 (A0+A1=GND) // учитываем, что библиотека может работать с несколькими линиями на разных пинах, поэтому инициируем библиотеку, если линия ранее не использовалась if (ina219Array.find(ADDR) == ina219Array.end()) { - ina219Array[ADDR] = new Adafruit_INA219((uint8_t)ADDR); + if (ina219SettingArray.find(ADDR) == ina219SettingArray.end()) + ina219Array[ADDR] = new INA219(ina219SettingArray[ADDR]->shunt, ina219SettingArray[ADDR]->maxV, (uint8_t)ADDR); + else + ina219Array[ADDR] = new INA219(0.1f, 3.2f, (uint8_t)ADDR); // Стандартные значения для модуля INA219 (0.1 Ом, 3.2А, адрес 0x40) ina219Array[ADDR]->begin(); - ina219ValueArray[ADDR] = new Ina219Value; + // ina219ValueArray[ADDR] = new Ina219Value; } return ina219Array[ADDR]; } -/* -float shuntvoltage = 0; -float busvoltage = 0; -float current_mA = 0; -float loadvoltage = 0; -float power_mW = 0; -*/ -// shuntvoltage = ina219.getShuntVoltage_mV(); // Получение напряжение на шунте -// busvoltage = ina219.getBusVoltage_V(); // Получение значение напряжения V -// current_mA = ina219.getCurrent_mA(); // Получение значение тока в мА -// power_mW = ina219.getPower_mW(); // Получение значение мощности -// loadvoltage = busvoltage + (shuntvoltage / 1000); // Расчет напряжение на нагрузки - -class Ina219loadvoltage : public IoTItem +class Ina219voltage : public IoTItem { private: uint8_t _addr = 0; public: - Ina219loadvoltage(String parameters) : IoTItem(parameters) + Ina219voltage(String parameters) : IoTItem(parameters) { String sAddr; jsonRead(parameters, "addr", sAddr); @@ -74,37 +66,11 @@ public: void doByInterval() { - value.valD = ina219ValueArray[_addr]->busvoltage + (ina219ValueArray[_addr]->shuntvoltage / 1000); - regEvent(value.valD, "Ina219loadvoltage"); + value.valD = instanceIna219(_addr)->getVoltage(); + regEvent(value.valD, "Ina219voltage"); } - ~Ina219loadvoltage(){}; -}; - -class Ina219busvoltage : public IoTItem -{ -private: - uint8_t _addr = 0; - -public: - Ina219busvoltage(String parameters) : IoTItem(parameters) - { - String sAddr; - jsonRead(parameters, "addr", sAddr); - if (sAddr == "") - scanI2C(); - else - _addr = hexStringToUint8(sAddr); - } - - void doByInterval() - { - ina219ValueArray[_addr]->busvoltage = instanceIna219(_addr)->getBusVoltage_V(); - value.valD = ina219ValueArray[_addr]->busvoltage; - regEvent(value.valD, "Ina219busvoltage"); - } - - ~Ina219busvoltage(){}; + ~Ina219voltage(){}; }; class Ina219shuntvoltage : public IoTItem @@ -124,8 +90,7 @@ public: } void doByInterval() { - ina219ValueArray[_addr]->shuntvoltage = instanceIna219(_addr)->getShuntVoltage_mV(); - value.valD = ina219ValueArray[_addr]->shuntvoltage; + value.valD = instanceIna219(_addr)->getShuntVoltage(); regEvent(value.valD, "Ina219shuntvoltage"); } @@ -149,20 +114,20 @@ public: } void doByInterval() { - value.valD = instanceIna219(_addr)->getCurrent_mA(); + value.valD = instanceIna219(_addr)->getCurrent(); regEvent(value.valD, "Ina219curr"); } ~Ina219curr(){}; }; -class Ina219Power_mW : public IoTItem +class Ina219Power : public IoTItem { private: uint8_t _addr = 0; public: - Ina219Power_mW(String parameters) : IoTItem(parameters) + Ina219Power(String parameters) : IoTItem(parameters) { String sAddr; jsonRead(parameters, "addr", sAddr); @@ -173,12 +138,82 @@ public: } void doByInterval() { - value.valD = instanceIna219(_addr)->getPower_mW(); + value.valD = instanceIna219(_addr)->getPower(); regEvent(value.valD, "Ina219power"); // TODO: найти способ понимания ошибки получения данных } - ~Ina219Power_mW(){}; + ~Ina219Power(){}; }; + +class Ina219Setting : public IoTItem +{ +private: + uint8_t _addr = 0; + int adjClbr = 0; + int resol = 1; + + +public: + Ina219Setting(String parameters) : IoTItem(parameters) + { + String sAddr; + jsonRead(parameters, "addr", sAddr); + jsonRead(parameters, "adjClbr", adjClbr); + jsonRead(parameters, "resol", resol); + + + if (sAddr == "") + scanI2C(); + else + _addr = hexStringToUint8(sAddr); + + ina219SettingArray[_addr] = new Ina219Value; + jsonRead(parameters, "shunt", ina219SettingArray[_addr]->shunt); + jsonRead(parameters, "maxV", ina219SettingArray[_addr]->maxV); + + instanceIna219(_addr)->adjCalibration(adjClbr); + if (resol == 1) + resol = 0b0011; + else + resol += 0b0111; + + instanceIna219(_addr)->setResolution(INA219_VBUS, resol); // Напряжение в 12ти битном режиме + instanceIna219(_addr)->setResolution(INA219_VSHUNT, resol); // Ток в 12ти битном режиме + } + + void onModuleOrder(String &key, String &value) + { + if (key == "getClbr") + { + SerialPrint("i", F("Ina219"), "addr: " + String(_addr) + ", Value Calibration:" + instanceIna219(_addr)->getCalibration()); + } + } + + IoTValue execute(String command, std::vector ¶m) + { + if (command == "sleep") + { + if (param.size() == 1) + { + if (param[0].valD == 0) + instanceIna219(_addr)->sleep(false); + if (param[0].valD == 1) + instanceIna219(_addr)->sleep(true); + return {}; + } + } + /* + else if (command == "getCalibration") + { + SerialPrint("i", F("Ina219"), "addr: " + String(_addr) + ", Value Calibration:" + instanceIna219(_addr)->getCalibration()); + return {}; + }*/ + return {}; + } + + ~Ina219Setting(){}; +}; + void *getAPI_Ina219(String subtype, String param) { if (subtype == F("Ina219curr")) @@ -189,17 +224,20 @@ void *getAPI_Ina219(String subtype, String param) { return new Ina219shuntvoltage(param); } - else if (subtype == F("Ina219power_mW")) + else if (subtype == F("Ina219power")) { - return new Ina219Power_mW(param); + return new Ina219Power(param); } - else if (subtype == F("Ina219busvoltage")) + else if (subtype == F("Ina219voltage")) { - return new Ina219busvoltage(param); + return new Ina219voltage(param); } - else if (subtype == F("Ina219loadvoltage")) + else if (subtype == F("Ina219setting")) { - return new Ina219loadvoltage(param); + return new Ina219Setting(param); + // Ina219Setting *ptr = new Ina219Setting(param); + // ina219SettingArray[ptr->getAddr()] = ptr; + // return ptr; } else { diff --git a/src/modules/sensors/Ina219/modinfo.json b/src/modules/sensors/Ina219/modinfo.json index f29a1e57..c89e95b2 100644 --- a/src/modules/sensors/Ina219/modinfo.json +++ b/src/modules/sensors/Ina219/modinfo.json @@ -6,10 +6,10 @@ "name": "INA219 Tок", "type": "Reading", "subtype": "Ina219curr", - "id": "Ina219current", - "widget": "anydatamAmp", + "id": "ina219_A", + "widget": "anydataAmp", "page": "INA 219", - "descr": "219 Датчик тока", + "descr": "Сила тока", "addr": "0x40", "plus": 0, "multiply": 1, @@ -20,11 +20,11 @@ "global": 0, "name": "INA219 Напряжение", "type": "Reading", - "subtype": "Ina219busvoltage", - "id": "Ina219busvoltage", + "subtype": "Ina219voltage", + "id": "ina219_V", "widget": "anydataVlt", "page": "INA 219", - "descr": "219 Датчик напряжения", + "descr": "Напряжения", "addr": "0x40", "plus": 0, "multiply": 1, @@ -35,26 +35,11 @@ "global": 0, "name": "INA219 Мощность", "type": "Reading", - "subtype": "Ina219power_mW", - "id": "Ina219power", - "widget": "anydatamWt", + "subtype": "Ina219power", + "id": "ina219_W", + "widget": "anydataWt", "page": "INA 219", - "descr": "219 Мощность", - "addr": "0x40", - "plus": 0, - "multiply": 1, - "round": 3, - "int": 10 - }, - { - "global": 0, - "name": "INA219 Напряжение нагрузки", - "type": "Reading", - "subtype": "Ina219loadvoltage", - "id": "Ina219loadvoltage", - "widget": "anydataVlt", - "page": "INA 219", - "descr": "219 Напряжение нагрузки", + "descr": "Мощность", "addr": "0x40", "plus": 0, "multiply": 1, @@ -66,15 +51,31 @@ "name": "INA219 Шунт", "type": "Reading", "subtype": "Ina219shuntvoltage", - "id": "Ina219shuntvoltage", - "widget": "anydatamVlt", + "id": "ina219_Vsh", + "widget": "anydataVlt", "page": "INA 219", - "descr": "219 Напряжение шунта", + "descr": "Напряжение шунта", "addr": "0x40", "plus": 0, "multiply": 1, "round": 3, "int": 10 + }, + { + "global": 0, + "name": "INA219 Настройки", + "type": "Reading", + "subtype": "Ina219setting", + "id": "ina219_set", + "widget": "nil", + "page": "", + "descr": "", + "addr": "0x40", + "shunt": 0.1, + "maxV": 3.2, + "adjClbr": 0, + "resol": 4, + "btn-getClbr":"nil" }], "about": { @@ -90,31 +91,46 @@ }, "subTypes": [ "Ina219curr", - "Ina219busvoltage", - "Ina219power_mW", - "Ina219loadvoltage", - "Ina219shuntvoltage" + "Ina219voltage", + "Ina219power", + "Ina219shuntvoltage", + "Ina219setting" ], "title": "Милливатметр постоянного тока", - "moduleDesc": "Измеряет постоянный ток до 3.2 ампера, напряжение до 26 вольт и мощность на нагрузке. Для расчета Наряжения нагрузки, необходимы Напряжение шунта и Датчик Напряжения", + "moduleDesc": "Измеряет постоянный ток до 3.2 ампера, напряжение до 26 вольт и мощность на нагрузке. Модуль INA219 Настройки - для изменении настроек нужен постоянно в конфигурации, должен стоять перед рдугими модулями с тем же адресом, без него работает на значенях по умолчанию", "propInfo": { "int": "Количество секунд между опросами датчика.", - "addr": "Адрес датчика на шине, обычно 0x40. Если оставить поле пустым, то запуститься сканер I2C и подключение к адресу 0x40" - } + "addr": "Адрес датчика на шине, обычно 0x40. Если оставить поле пустым, то запуститься сканер I2C и подключение к адресу 0x40", + "shunt": "Сопротивление шунта, штатно 0.1Ом. Изменить если его перепаяли", + "maxV": "Максимальный ожидаемый ток, штатно 3.2А, для указаного шунта", + "adjClbr": "Задать смещение (подкрутить) калибровочное значение на указанное значение. -20 = Уменьшить калибровочное значение на 20", + "resol": "Установка режима усреднения для измерения напряжения и тока, рекомендуется для повышения стабильности показаний на шумной нагрузке. Варианты 1(без усреднения),2,4,8,16,32,64,128", + "btn-getClbr": "Кнопка запроса текущей калибровки, выводится в лог" + }, + "funcInfo": [ + { + "name": "sleep", + "descr": "INA219 Настройки. Установка / снятие режима сна датчика INA219", + "params": ["1- вкл сна/ 0-выкл сна"] + } + ] }, "defActive": false, "usedLibs": { "esp32_4mb": [ - "https://github.com/adafruit/Adafruit_INA219.git" + "https://github.com/GyverLibs/GyverINA" ], "esp32s2_4mb": [ - "https://github.com/adafruit/Adafruit_INA219.git" + "https://github.com/GyverLibs/GyverINA" ], "esp8266_4mb": [ - "https://github.com/adafruit/Adafruit_INA219.git" + "https://github.com/GyverLibs/GyverINA" + ], + "esp8266_16mb": [ + "https://github.com/GyverLibs/GyverINA" ] } diff --git a/src/modules/sensors/Ina226/Ina226.cpp b/src/modules/sensors/Ina226/Ina226.cpp new file mode 100644 index 00000000..74b614f6 --- /dev/null +++ b/src/modules/sensors/Ina226/Ina226.cpp @@ -0,0 +1,241 @@ +/****************************************************************** + Used GyverINA Current Sensor + Support for INA219 INA226 + https://github.com/GyverLibs/GyverINA + + adapted for version 4dev @Mit4bmw + ******************************************************************/ + +#include "Global.h" +#include "classes/IoTItem.h" + +#include +#include +#include + + + +// Структура для хранения настроек датчика +struct Ina226Value +{ + float shunt = 0; + float maxV = 0; +}; + +// глобальные списки необходимы для хранения Модуля Настроек. Ключ - адрес +std::map ina226SettingArray; + +// глобальные списки необходимы для хранения объектов используемых разными датчиками из модуля. Ключ - адрес +std::map ina226Array; + +// Функция инициализации библиотечного класса, возвращает Единстрвенный указать на библиотеку +INA226 *instanceIna226(uint8_t ADDR) +{ + /** default I2C address **/ + if (ADDR == 0) + ADDR = 0x40; // 1000000 (A0+A1=GND) + + // учитываем, что библиотека может работать с несколькими линиями на разных пинах, поэтому инициируем библиотеку, если линия ранее не использовалась + if (ina226Array.find(ADDR) == ina226Array.end()) + { + if (ina226SettingArray.find(ADDR) == ina226SettingArray.end()) + ina226Array[ADDR] = new INA226(ina226SettingArray[ADDR]->shunt, ina226SettingArray[ADDR]->maxV, (uint8_t)ADDR); + else + ina226Array[ADDR] = new INA226(0.1f, 0.8f, (uint8_t)ADDR); // Стандартные значения для модуля INA226 (0.1 Ом, 0.8А, адрес 0x40) + ina226Array[ADDR]->begin(); + // ina226ValueArray[ADDR] = new Ina226Value; + } + return ina226Array[ADDR]; +} + +class Ina226voltage : public IoTItem +{ +private: + uint8_t _addr = 0; + +public: + Ina226voltage(String parameters) : IoTItem(parameters) + { + String sAddr; + jsonRead(parameters, "addr", sAddr); + if (sAddr == "") + scanI2C(); + else + _addr = hexStringToUint8(sAddr); + } + + void doByInterval() + { + value.valD = instanceIna226(_addr)->getVoltage(); + regEvent(value.valD, "Ina226voltage"); + } + + ~Ina226voltage(){}; +}; + +class Ina226shuntvoltage : public IoTItem +{ +private: + uint8_t _addr = 0; + +public: + Ina226shuntvoltage(String parameters) : IoTItem(parameters) + { + String sAddr; + jsonRead(parameters, "addr", sAddr); + if (sAddr == "") + scanI2C(); + else + _addr = hexStringToUint8(sAddr); + } + void doByInterval() + { + value.valD = instanceIna226(_addr)->getShuntVoltage(); + regEvent(value.valD, "Ina226shuntvoltage"); + } + + ~Ina226shuntvoltage(){}; +}; + +class Ina226curr : public IoTItem +{ +private: + uint8_t _addr = 0; + +public: + Ina226curr(String parameters) : IoTItem(parameters) + { + String sAddr; + jsonRead(parameters, "addr", sAddr); + if (sAddr == "") + scanI2C(); + else + _addr = hexStringToUint8(sAddr); + } + void doByInterval() + { + value.valD = instanceIna226(_addr)->getCurrent(); + regEvent(value.valD, "Ina226curr"); + } + + ~Ina226curr(){}; +}; + +class Ina226Power : public IoTItem +{ +private: + uint8_t _addr = 0; + +public: + Ina226Power(String parameters) : IoTItem(parameters) + { + String sAddr; + jsonRead(parameters, "addr", sAddr); + if (sAddr == "") + scanI2C(); + else + _addr = hexStringToUint8(sAddr); + } + void doByInterval() + { + value.valD = instanceIna226(_addr)->getPower(); + regEvent(value.valD, "Ina226power"); // TODO: найти способ понимания ошибки получения данных + } + + ~Ina226Power(){}; +}; + +class Ina226Setting : public IoTItem +{ +private: + uint8_t _addr = 0; + int adjClbr = 0; + int resol = 1; + + +public: + Ina226Setting(String parameters) : IoTItem(parameters) + { + String sAddr; + jsonRead(parameters, "addr", sAddr); + jsonRead(parameters, "adjClbr", adjClbr); + jsonRead(parameters, "resol", resol); + + + if (sAddr == "") + scanI2C(); + else + _addr = hexStringToUint8(sAddr); + + ina226SettingArray[_addr] = new Ina226Value; + jsonRead(parameters, "shunt", ina226SettingArray[_addr]->shunt); + jsonRead(parameters, "maxV", ina226SettingArray[_addr]->maxV); + + instanceIna226(_addr)->adjCalibration(adjClbr); + + instanceIna226(_addr)->setAveraging(resol); // Напряжение в 12ти битном режиме + } + + void onModuleOrder(String &key, String &value) + { + if (key == "getClbr") + { + SerialPrint("i", F("Ina226"), "addr: " + String(_addr) + ", Value Calibration:" + instanceIna226(_addr)->getCalibration()); + } + } + + IoTValue execute(String command, std::vector ¶m) + { + if (command == "sleep") + { + if (param.size() == 1) + { + if (param[0].valD == 0) + instanceIna226(_addr)->sleep(false); + if (param[0].valD == 1) + instanceIna226(_addr)->sleep(true); + return {}; + } + } + /* + else if (command == "getCalibration") + { + SerialPrint("i", F("Ina226"), "addr: " + String(_addr) + ", Value Calibration:" + instanceIna226(_addr)->getCalibration()); + return {}; + }*/ + return {}; + } + + ~Ina226Setting(){}; +}; + +void *getAPI_Ina226(String subtype, String param) +{ + if (subtype == F("Ina226curr")) + { + return new Ina226curr(param); + } + else if (subtype == F("Ina226shuntvoltage")) + { + return new Ina226shuntvoltage(param); + } + else if (subtype == F("Ina226power")) + { + return new Ina226Power(param); + } + else if (subtype == F("Ina226voltage")) + { + return new Ina226voltage(param); + } + else if (subtype == F("Ina226setting")) + { + return new Ina226Setting(param); + // Ina226Setting *ptr = new Ina226Setting(param); + // ina226SettingArray[ptr->getAddr()] = ptr; + // return ptr; + } + else + { + return nullptr; + } +} diff --git a/src/modules/sensors/Ina226/modinfo.json b/src/modules/sensors/Ina226/modinfo.json new file mode 100644 index 00000000..a2f00e1c --- /dev/null +++ b/src/modules/sensors/Ina226/modinfo.json @@ -0,0 +1,139 @@ +{ + "menuSection": "Сенсоры", + + "configItem": [{ + "global": 0, + "name": "INA226 Tок", + "type": "Reading", + "subtype": "Ina226curr", + "id": "ina226_A", + "widget": "anydataAmp", + "page": "INA 226", + "descr": "Сила тока", + "addr": "0x40", + "plus": 0, + "multiply": 1, + "round": 3, + "int": 10 + }, + { + "global": 0, + "name": "INA226 Напряжение", + "type": "Reading", + "subtype": "Ina226voltage", + "id": "ina226_V", + "widget": "anydataVlt", + "page": "INA 226", + "descr": "Напряжения", + "addr": "0x40", + "plus": 0, + "multiply": 1, + "round": 3, + "int": 10 + }, + { + "global": 0, + "name": "INA226 Мощность", + "type": "Reading", + "subtype": "Ina226power", + "id": "ina226_W", + "widget": "anydataWt", + "page": "INA 226", + "descr": "Мощность", + "addr": "0x40", + "plus": 0, + "multiply": 1, + "round": 3, + "int": 10 + }, + { + "global": 0, + "name": "INA226 Шунт", + "type": "Reading", + "subtype": "Ina226shuntvoltage", + "id": "ina226_Vsh", + "widget": "anydataVlt", + "page": "INA 226", + "descr": "Напряжение шунта", + "addr": "0x40", + "plus": 0, + "multiply": 1, + "round": 3, + "int": 10 + }, + { + "global": 0, + "name": "INA226 Настройки", + "type": "Reading", + "subtype": "Ina226setting", + "id": "ina226_set", + "widget": "nil", + "page": "", + "descr": "", + "addr": "0x40", + "shunt": 0.1, + "maxV": 3.2, + "adjClbr": 0, + "resol": 4, + "btn-getClbr":"nil" + }], + + "about": { + "authorName": "Serghei Crasnicov", + "authorContact": "https://t.me/Serghei63", + "authorGit": "https://github.com/Serghei63", + "specialThanks": "v2.0 - Mitchel @Mit4bmw", + "moduleName": "Ina226", + "moduleVersion": "2.0", + "usedRam": { + "esp32_4mb": 15, + "esp8266_4mb": 15 + }, + "subTypes": [ + "Ina226curr", + "Ina226voltage", + "Ina226power", + "Ina226shuntvoltage", + "Ina226setting" + ], + "title": "Милливатметр постоянного тока", + "moduleDesc": "Стандартные значения для модуля INA226 (Сопротивление шунта - 0.1 Ом, Максимальный ожидаемый ток - 0.8 А, Адрес на шине I2c - 0x40). Модуль INA226 Настройки - для изменении настроек нужен постоянно в конфигурации, должен стоять перед рдугими модулями с тем же адресом, без него работает на значенях по умолчанию", + "propInfo": { + "int": "Количество секунд между опросами датчика.", + "addr": "Адрес датчика на шине, обычно 0x40. Если оставить поле пустым, то запуститься сканер I2C и подключение к адресу 0x40", + "shunt": "Сопротивление шунта, штатно 0.1Ом. Изменить если его перепаяли", + "maxV": "Максимальный ожидаемый ток, штатно 0.8А, для указаного шунта", + "adjClbr": "Задать смещение (подкрутить) калибровочное значение на указанное значение. -20 = Уменьшить калибровочное значение на 20", + "resol": "Установка режима усреднения (колическва замеров) для измерения напряжения и тока, рекомендуется для повышения стабильности показаний на шумной нагрузке. Пропорционально увеличивает время оцифровки. Варианты 0(без усреднения), от 1 до 7 - соответстввует 4,16,64,128,256,512,1024", + "btn-getClbr": "Кнопка запроса текущей калибровки, выводится в лог" + }, + "funcInfo": [ + { + "name": "sleep", + "descr": "INA226 Настройки. Установка / снятие режима сна датчика INA226", + "params": ["1- вкл сна/ 0-выкл сна"] + } + ] + }, + + "defActive": false, + + "usedLibs": { + "esp32_4mb": [ + "https://github.com/GyverLibs/GyverINA" + ], + "esp32s2_4mb": [ + "https://github.com/GyverLibs/GyverINA" + ], + + "esp8266_4mb": [ + "https://github.com/GyverLibs/GyverINA" + ], + "esp8266_16mb": [ + "https://github.com/GyverLibs/GyverINA" + ] + } + + } + + \ No newline at end of file diff --git a/src/modules/virtual/GoogleSheet/GoogleSheet.cpp b/src/modules/virtual/GoogleSheet/GoogleSheet.cpp index d192e10f..173cfe13 100644 --- a/src/modules/virtual/GoogleSheet/GoogleSheet.cpp +++ b/src/modules/virtual/GoogleSheet/GoogleSheet.cpp @@ -2,8 +2,6 @@ #include "Global.h" #include "classes/IoTItem.h" -String URL = F("https://script.google.com/macros/s/"); - class GoogleSheet : public IoTItem { private: @@ -14,7 +12,10 @@ private: // bool init = false; int interval = 1; // long interval; + String URL = ("http://iotmanager.org/projects/google.php?/macros/s/"); // F("https://script.google.com/macros/s/"); String urlFinal; + HTTPClient http; + WiFiClient client; public: GoogleSheet(String parameters) : IoTItem(parameters) @@ -101,30 +102,29 @@ public: if (!send) return; // Не отправляем просто накапливаем данные - /* if (!init) - { - init = true; - urlFinal = urlFinal + "&init=1"; - } - */ - HTTPClient http; + /* if (!init) + { + init = true; + urlFinal = urlFinal + "&init=1"; + } + */ +// HTTPClient http; #if defined ESP8266 - WiFiClientSecure client; - client.setInsecure(); + // WiFiClient client; + // client.setInsecure(); if (!http.begin(client, urlFinal)) - { #elif defined ESP32 - WiFiClient client; + // WiFiClient client; if (!http.begin(urlFinal)) - { #endif + { SerialPrint("I", F("GoogleSheet"), F("connection failed")); } - http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); // HTTPC_STRICT_FOLLOW_REDIRECTS HTTPC_FORCE_FOLLOW_REDIRECTS + // http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); // HTTPC_STRICT_FOLLOW_REDIRECTS HTTPC_FORCE_FOLLOW_REDIRECTS http.addHeader(F("Content-Type"), F("application/x-www-form-urlencoded")); int httpCode = http.GET(); - // String payload = http.getString(); + String payload = http.getString(); SerialPrint("<-", F("GoogleSheet"), "URL: " + urlFinal); SerialPrint("->", F("GoogleSheet"), "server: " + (String)httpCode); /*"URL: " + urlFinal + */ @@ -133,7 +133,7 @@ public: SerialPrint("->", F("GoogleSheet"), "msg from server: " + (String)payload.c_str()); } */ - http.end(); + // http.end(); // Обнуляем данные в запросе, так как все отправили urlFinal = URL + scid + F("/exec?") + F("sheet=") + shname; }; @@ -153,7 +153,7 @@ public: return nullptr; }; - ~GoogleSheet(){}; + ~GoogleSheet() { http.end(); }; }; void *getAPI_GoogleSheet(String subtype, String param) diff --git a/src/modules/virtual/GoogleSheet/modinfo.json b/src/modules/virtual/GoogleSheet/modinfo.json index a81e3a6c..8a8f47ee 100644 --- a/src/modules/virtual/GoogleSheet/modinfo.json +++ b/src/modules/virtual/GoogleSheet/modinfo.json @@ -12,7 +12,7 @@ "descr": "", "int": 5, "logid": "", - "scid": "Script_ID", + "scid": "", "shname": "Logger" } ], @@ -21,7 +21,7 @@ "authorContact": "https://t.me/Mit4bmw", "authorGit": "https://github.com/Mit4el", "exampleURL": "https://iotmanager.org/wiki", - "specialThanks": "", + "specialThanks": "@AVAKS", "moduleName": "GoogleSheet", "moduleVersion": "1.0", "usedRam": { @@ -40,7 +40,7 @@ "funcInfo": [ { "name": "logGoogle", - "descr": "Использовать не чаще раз в минуту! Логирование элементов по их идентификатору в GoogleSheet, указывать через запятую, от одного до N (проверено на 16шт)", + "descr": "Использовать не чаще раз в минуту! Логирование элементов в GoogleSheet, ID элементов указывать через запятую, от одного до N (проверено на 16шт). В данной функции поиск элементов идет по их значению, если несколько элементов с одинаковым значение, может быть не правильно указан его id в Таблице.", "params": [ "id Идентификатор 1-го элеменета", "id Идентификатор N-го элеменета" @@ -59,6 +59,7 @@ "defActive": false, "usedLibs": { "esp32_4mb": [], - "esp32s2_4mb": [] + "esp32s2_4mb": [], + "esp8266_4mb": [] } } \ No newline at end of file diff --git a/tools/prebuildscript.py b/tools/prebuildscript.py new file mode 100644 index 00000000..7eb4a4b1 --- /dev/null +++ b/tools/prebuildscript.py @@ -0,0 +1,28 @@ + +import os +import configparser + +def before_build(): # source, target, env + print("Current Build targets", BUILD_TARGETS) + # Это всё потому что не работает "buildprog". При сборке прошивки Targets пустой, на всякий случай исключим все остальные + if (BUILD_TARGETS == ['upload'] or + BUILD_TARGETS == ['buildfs'] or + BUILD_TARGETS == ['uploadfs'] or + BUILD_TARGETS == ['uploadfsota'] or + BUILD_TARGETS == ['size']): + return + + print("Clear BUILD_TIME, delete main.o !") + config = configparser.ConfigParser() # создаём объекта парсера INI + config.read("platformio.ini") + deviceName = config["platformio"]["default_envs"] + # удаляем объектный файл где используется время сборки, для обновления + try: + os.remove("./.pio/build/"+deviceName+"/src/Main.cpp.o") + except OSError as e: + # If it fails, inform the user. + print("Error: %s - %s." % (e.filename, e.strerror)) + +#env.AddPreAction("buildprog", before_build) # $BUILD_DIR/src/main.cpp.o + +before_build() \ No newline at end of file