diff --git a/include/utils/StringUtils.h b/include/utils/StringUtils.h index 9fac0aa5..6d3afa15 100644 --- a/include/utils/StringUtils.h +++ b/include/utils/StringUtils.h @@ -12,6 +12,8 @@ uint8_t hexStringToUint8(const String& hex); uint16_t hexStringToUint16(const String& hex); +uint32_t hexStringToUint32(const String& hex); + String selectToMarkerLast(String str, const String& found); String selectToMarker(String str, const String& found); diff --git a/run.py b/run.py new file mode 100644 index 00000000..95808a19 --- /dev/null +++ b/run.py @@ -0,0 +1,109 @@ +# Скрипт для простой прошивки ESP с учетом профиля из myProfile.json и поиска нужной кнопочки в интерфейсе PlatformIO +# Если ничего не указано в параметрах, то выполняется последовательно набор команд: +# 1. run PrepareProject.py +# 2. platformio run -t clean +# 3. platformio run -t uploadfs -е default_envs +# 4. platformio run -t upload -е default_envs +# 5. platformio run -t monitor +# где default_envs - это параметр default_envs из myProfile.json +# +# Если указан параметр -p или --profile <ИмяФайла>, то выполняется первая команда PrepareProject.py -p <ИмяФайла> +# Если указан парамтер -l или --lite, то пропускаются команды 1, 2 и 5 с предварительной компиляцией +# Если указан параметр -d или --debug, то выполняется только команда 4 с предварительной компиляцией + +import os +import subprocess +import sys +import json + +def get_platformio_path(): + """ + Возвращает путь к PlatformIO в зависимости от операционной системы. + """ + if os.name == 'nt': # Windows + return os.path.join(os.environ['USERPROFILE'], '.platformio', 'penv', 'Scripts', 'pio.exe') + else: # Linux/MacOS + return os.path.join(os.environ['HOME'], '.platformio', 'penv', 'bin', 'pio') + +def load_default_envs(profile_path="myProfile.json"): + """ + Загружает значение default_envs из файла myProfile.json. + """ + if not os.path.isfile(profile_path): + print(f"Файл профиля {profile_path} не найден.") + sys.exit(1) + + try: + with open(profile_path, 'r', encoding='utf-8') as file: + profile_data = json.load(file) + return profile_data["projectProp"]["platformio"]["default_envs"] + except KeyError: + print("Не удалось найти ключ 'default_envs' в myProfile.json.") + sys.exit(1) + except json.JSONDecodeError: + print(f"Ошибка при чтении файла {profile_path}: некорректный JSON.") + sys.exit(1) + +def run_command(command): + """ + Выполняет указанную команду в subprocess. + """ + try: + print(f"Выполнение команды: {' '.join(command)}") + subprocess.run(command, check=True) + except subprocess.CalledProcessError as e: + print(f"Ошибка при выполнении команды: {e}") + sys.exit(e.returncode) + +def run_platformio(): + """ + Основная логика выполнения команд в зависимости от параметров. + """ + pio_path = get_platformio_path() + + # Проверяем, существует ли PlatformIO + if not os.path.isfile(pio_path): + print(f"PlatformIO не найден по пути: {pio_path}") + sys.exit(1) + # print(f"PlatformIO найден по пути: {pio_path}") + + # Читаем аргументы командной строки + args = sys.argv[1:] + lite_mode = '-l' in args or '--lite' in args + debug_mode = '-d' in args or '--debug' in args + profile_index = next((i for i, arg in enumerate(args) if arg in ('-p', '--profile')), None) + profile_file = args[profile_index + 1] if profile_index is not None and len(args) > profile_index + 1 else "myProfile.json" + + # Загружаем default_envs из myProfile.json + default_envs = load_default_envs(profile_path=profile_file) + + print(f"Используем default_envs: {default_envs}") + print(f"Режим Lite: {lite_mode}, Режим отладки: {debug_mode}") + print(f"Профиль: {profile_file}") + + # Выполнение команд в зависимости от параметров + if not lite_mode and not debug_mode: + # Полный набор команд + run_command(['python', 'PrepareProject.py', '-p', profile_file]) + + # Добавляем сообщение о необходимости дождаться завершения обновления конфигурации + input(f"\x1b[1;31;42m Подождите завершения обновления конфигурации PlatformIO, затем нажмите Ввод для продолжения...\x1b[0m") + + run_command([pio_path, 'run', '-t', 'clean']) + run_command([pio_path, 'run', '-t', 'uploadfs', '--environment', default_envs]) + run_command([pio_path, 'run', '-t', 'upload', '--environment', default_envs]) + run_command([pio_path, 'run', '-t', 'monitor']) + elif lite_mode: + # Упрощенный режим (пропускаем команды 1, 2 и 5) + run_command([pio_path, 'run', '-t', 'buildfs', '--environment', default_envs]) + run_command([pio_path, 'run', '-t', 'uploadfs', '--environment', default_envs]) + run_command([pio_path, 'run', '--environment', default_envs]) + run_command([pio_path, 'run', '-t', 'upload', '--environment', default_envs]) + elif debug_mode: + # Режим отладки (только команда 4) + run_command([pio_path, 'run', '--environment', default_envs]) + run_command([pio_path, 'run', '-t', 'upload', '--environment', default_envs]) + +if __name__ == "__main__": + run_platformio() + diff --git a/src/modules/display/LedFX/LedFX.cpp b/src/modules/display/LedFX/LedFX.cpp new file mode 100644 index 00000000..8515d389 --- /dev/null +++ b/src/modules/display/LedFX/LedFX.cpp @@ -0,0 +1,332 @@ +#include "Global.h" +#include "classes/IoTItem.h" +#include "ESPConfiguration.h" +#include + + + +WS2812FX *_glob_strip = nullptr; // глобальный указатель на WS2812FX для использования в функциях для кастомных эффектов +std::vector vuMeterBands; // массив указателей на элементы IoTValue, которые будут использоваться для передачи данных в эффект VU Meter + +uint16_t vuMeter2(void) { +// функция взята из WS2812FX.cpp для демонстрации возможности создания своего алгоритма эффекта +// в данном случае - VU Meter имеет тот же смысл отображения уровня сигнала, что и в WS2812FX с сохранением алгоритма вывода данных из нескольких источников +// но вместо использования внешнего источника данных для встроенного эффекта, мы используем данные из других элементов конфигурации IoTM +// Если данные не поступают (IoTValue.valS == "1"), то используется генерация случайных чисел для демонстрации работы эффекта + + if (_glob_strip == nullptr) return 0; // Проверяем, инициализирована ли библиотека WS2812FX + + uint16_t numBands = vuMeterBands.size(); // Получаем количество полос VU Meter из массива указателей + if (numBands == 0) return 0; // Если нет полос, выходим из функции + + WS2812FX::Segment* seg = _glob_strip->getSegment(); + uint16_t seglen = seg->stop - seg->start + 1; + uint16_t bandSize = seglen / numBands; + + if (vuMeterBands[0]->valS == "R") + for (uint8_t i=0; i < numBands; i++) { + int randomData = vuMeterBands[i]->valD + _glob_strip->random8(32) - _glob_strip->random8(32); + vuMeterBands[i]->valD = (randomData < 0 || randomData > 255) ? 128 : randomData; + } + + for(uint8_t i=0; ivalD)); + uint8_t scaledBand = (vuMeterBands[i]->valD * bandSize) / 256; + for(uint16_t j=0; jstart + (i * bandSize) + j; + if(j <= scaledBand) { + if(j < bandSize - 4) _glob_strip->setPixelColor(index, GREEN); + else if(j < bandSize - 2) _glob_strip->setPixelColor(index, YELLOW); + else _glob_strip->setPixelColor(index, RED); + } else { + _glob_strip->setPixelColor(index, BLACK); + } + } + } + _glob_strip->setCycle(); + + return seg->speed; +} + + +class LedFX : public IoTItem +{ +private: + WS2812FX *_strip; + + int _data_pin = 2; + int _numLeds = 1; + int _brightness = 100; + int _speed = 15000; + int _effectsMode = 0; + int _valueMode = 0; + int _color = 0xFF0000; // default color red + + uint8_t _BrightnessFadeOutStep = 0; + uint8_t _BrightnessFadeOutMin = 1; + uint8_t _BrightnessFadeInStep = 0; + uint8_t _BrightnessFadeInMax = 50; + +public: + LedFX(String parameters) : IoTItem(parameters) { + jsonRead(parameters, F("data_pin"), _data_pin); + jsonRead(parameters, F("speed"), _speed); + jsonRead(parameters, F("numLeds"), _numLeds); + jsonRead(parameters, F("brightness"), _brightness); + + String tmpStr; + jsonRead(parameters, F("color"), tmpStr); + _color = hexStringToUint32(tmpStr); + + jsonRead(parameters, F("effectsMode"), _effectsMode); + jsonRead(parameters, F("valueMode"), _valueMode); + + + //_strip = new WS2812FX(_numLeds, _data_pin, NEO_BRG + NEO_KHZ400); // SM16703 + _strip = new WS2812FX(_numLeds, _data_pin, NEO_GRB + NEO_KHZ800); // WS2812B + + if (_strip != nullptr) { + _glob_strip = _strip; // Сохраняем указатель в глобальной переменной + + _strip->init(); + _strip->setBrightness(_brightness); + _strip->setSpeed(_speed); + _strip->setMode(_effectsMode); + _strip->setColor(_color); + if (_effectsMode >= 0) _strip->start(); + } + } + + void fadeOutNonBlocking() { + + } + + void loop() { + if (!_strip) return; + + static unsigned long lastUpdate = 0; // Время последнего обновления + unsigned long now = millis(); + if (now - lastUpdate >= 70) { // Проверяем, прошло ли достаточно времени + lastUpdate = now; + + if (_BrightnessFadeOutStep > 0) { + int currentBrightness = _strip->getBrightness(); // Получаем текущую яркость + currentBrightness -= _BrightnessFadeOutStep; + if (currentBrightness < _BrightnessFadeOutMin) { + currentBrightness = _BrightnessFadeOutMin; // Убедимся, что яркость не уйдет в отрицательные значения + _BrightnessFadeOutStep = 0; // Останавливаем затухание + } + _strip->setBrightness(currentBrightness); + _strip->show(); + } + + if (_BrightnessFadeInStep > 0) { + int currentBrightness = _strip->getBrightness(); // Получаем текущую яркость + currentBrightness += _BrightnessFadeInStep; + if (currentBrightness > _BrightnessFadeInMax) { + currentBrightness = _BrightnessFadeInMax; // Убедимся, что яркость не уйдет за пределы + _BrightnessFadeInStep = 0; // Останавливаем затухание + } + _strip->setBrightness(currentBrightness); + _strip->show(); + } + } + + _strip->service(); + IoTItem::loop(); + } + + void doByInterval() { + + } + + IoTValue execute(String command, std::vector ¶m) { + if (!_strip) return {}; + if (command == "fadeOut") { + if (param.size() == 2) { + _BrightnessFadeOutMin = param[0].valD; + _BrightnessFadeOutStep = param[1].valD; + SerialPrint("E", "Strip LedFX", "BrightnessFadeOut"); + } + + } else if (command == "fadeIn") { + if (param.size() == 2) { + _BrightnessFadeInMax = param[0].valD; + _BrightnessFadeInStep = param[1].valD; + SerialPrint("E", "Strip LedFX", "BrightnessFadeIn"); + } + + } else if (command == "setColor") { + if (param.size() == 1) { + _color = hexStringToUint32(param[0].valS); + _strip->setColor(_color); + _strip->show(); + SerialPrint("E", "Strip LedFX", "setColor:" + param[0].valS); + } + + } else if (command == "setEffect") { + if (param.size() == 1) { + if (param[0].valD < 0 | param[0].valD > 79) + _effectsMode = random(0, 79); + else + _effectsMode = param[0].valD; + _strip->setMode(_effectsMode); + _strip->show(); + _strip->start(); + SerialPrint("E", "Strip LedFX", "setEffect:" + param[0].valS); + } + + } else if (command == "setSpeed") { + if (param.size() == 1) { + _speed = param[0].valD; + _strip->setSpeed(_speed); + _strip->show(); + SerialPrint("E", "Strip LedFX", "setSpeed:" + param[0].valS); + } + + } else if (command == "setBrightness") { + if (param.size() == 1) { + _brightness = param[0].valD; + _strip->setBrightness(_brightness); + _strip->show(); + SerialPrint("E", "Strip LedFX", "setBrightness:" + param[0].valS); + } + + } else if (command == "stop") { + _strip->stop(); + SerialPrint("E", "Strip LedFX", "stop"); + + } else if (command == "start") { + _strip->start(); + SerialPrint("E", "Strip LedFX", "start"); + + } else if (command == "pause") { + _strip->pause(); + SerialPrint("E", "Strip LedFX", "pause"); + + } else if (command == "resume") { + _strip->resume(); + SerialPrint("E", "Strip LedFX", "resume"); + + } else if (command == "setSegment") { + if (param.size() == 6) { + _strip->setSegment(param[0].valD, param[1].valD, param[2].valD, param[3].valD, hexStringToUint32(param[4].valS), param[5].valD); + _strip->show(); + _strip->start(); + SerialPrint("E", "Strip LedFX", "setSegment:" + param[0].valS + " start:" + param[1].valS + " stop:" + param[2].valS + " mode:" + param[3].valS, " color:" + param[4].valS + " speed:" + param[5].valS); + } + + } else if(command == "noShowOne"){ + if (param.size() == 1) { + _strip->setPixelColor(param[0].valD, _strip->Color(0, 0, 0)); + _strip->show(); + SerialPrint("E", "Strip LedFX", "noShowOne"); + } + + } else if (command == "showLed"){ + if (param.size() == 2) { + uint32_t color = hexStringToUint32(param[1].valS); + _strip->setPixelColor(param[0].valD, color); + _strip->show(); + _strip->start(); + SerialPrint("E", "Strip LedFX", "showLed:" + param[0].valS + " color:" + param[1].valS); + } + + } else if (command == "vuMeter") { + if (param.size() == 2) { + int bandCnt = param[0].valD; + if (param[1].valS == "") { + for (int i=0; i < vuMeterBands.size(); i++) { + delete vuMeterBands[i]; + } + vuMeterBands.clear(); + + for (uint8_t i=0; i < bandCnt; i++) { + IoTValue *band = new IoTValue(); // создаем новый элемент IoTValue для полос VU Meter + band->valD = 0; + band->valS = "R"; + vuMeterBands.push_back(band); // добавляем указатель в массив + } + } else { + // Очищаем массив vuMeterBands перед заполнением + vuMeterBands.clear(); + + String id; + String idsStr = param[1].valS; + // Разделяем строку idsStr на идентификаторы, используя запятую как разделитель + while (idsStr.length() > 0) { + // Извлекаем идентификатор до первой запятой + id = selectToMarker(idsStr, ","); + + // Ищем элемент IoTItem по идентификатору + IoTItem* item = findIoTItem(id); + if (item != nullptr) { + // Добавляем указатель на поле value найденного элемента в vuMeterBands + vuMeterBands.push_back(&(item->value)); + SerialPrint("E", "LedFX", "Добавлен элемент в vuMeterBands: " + id); + } else { + SerialPrint("E", "LedFX", "Элемент не найден: " + id); + } + + int8_t oldSize = idsStr.length(); + // Удаляем обработанный идентификатор из строки + idsStr = deleteBeforeDelimiter(idsStr, ","); + if (idsStr.length() == oldSize) { + // Если длина строки не изменилась, значит, больше нет запятых и это был последний идентификатор + break; + } + } + + } + _strip->setCustomMode(vuMeter2); + _strip->setMode(FX_MODE_CUSTOM); + _strip->start(); + SerialPrint("E", "Strip LedFX", "vuMeter bands:" + param[0].valS + " IDs to show:" + param[1].valS); + } + } + + return {}; + } + + void setValue(const IoTValue& Value, bool genEvent = true) { + if (!_strip) return; + + if (_valueMode == 0) { + _strip->setMode(Value.valD); + _effectsMode = Value.valD; + } else if (_valueMode == 1) { + _strip->setBrightness(Value.valD); + _brightness = Value.valD; + } else if (_valueMode == 2) { + _color = hexStringToUint32(Value.valS); + _strip->setColor(_color); + } else if (_valueMode == 3) { + _strip->setSpeed(Value.valD); + _speed = Value.valD; + } + + value = Value; + regEvent(value.valD, "LedFX", false, genEvent); + } + + ~LedFX() { + if (_strip != nullptr) { + delete _strip; + _strip = nullptr; + _glob_strip = nullptr; // Обнуляем глобальный указатель + } + }; +}; + +void *getAPI_LedFX(String subtype, String param) +{ + if (subtype == F("LedFX")) { + return new LedFX(param); + } else { + return nullptr; + } +} + + + + diff --git a/src/modules/display/LedFX/modinfo.json b/src/modules/display/LedFX/modinfo.json new file mode 100644 index 00000000..7b09f028 --- /dev/null +++ b/src/modules/display/LedFX/modinfo.json @@ -0,0 +1,163 @@ +{ + "menuSection": "screens", + "configItem": [ + { + "global": 0, + "name": "LedFX", + "type": "Reading", + "subtype": "LedFX", + "id": "fl", + "widget": "inputTxt", + "page": "Кнопки", + "descr": "Лента", + "int": 15, + "needSave": 0, + + "data_pin": "2", + "numLeds": "3", + "brightness": "50", + "speed": "3000", + "color": "0xFF0000", + "effectsMode": 0, + "valueMode": 0 + } + ], + "about": { + "authorName": "Ilya Belyakov", + "authorContact": "https://t.me/Biveraxe", + "authorGit": "https://github.com/biveraxe", + "exampleURL": "https://iotmanager.org/wiki", + "specialThanks": "Yuriy Kuneev (https://t.me/Kuneev07)", + "moduleName": "LedFX", + "moduleVersion": "1.0.1", + "moduleDesc": "Позволяет управлять адресными светодиодными лентами WS2812B и аналогичными.", + "propInfo": { + "int": "Период времени в секундах обновления.", + "data_pin": "Пин к которому подключена лента.", + "speed": "Скорость обновления ленты.", + "numLeds": "Количество пикселей в ленте.", + "needSave": "Запись значения элемента в энергонезависимую память", + "brightness": "Яркость ленты можно менять из сценария.", + "color": "Цвет ленты в формате 0xRRGGBB, например, 0xFF0000 - красный, 0x00FF00 - зеленый, 0x0000FF - синий.", + "effectsMode": "Режим эффектов ленты. 0-79. 0 - Статичный цвет.", + "valueMode": "Режим применения значения элемета. 0 - установка режима эффектов, 1 - регулирование яркости, 2 - изменение цвета, 3 - изменение скорости." + }, + "title": "Адресная светодиодная лента", + "funcInfo": [ + { + "name": "noShowOne", + "descr": "Выключить один светодиод на ленте", + "params": [ + "номер пикселя" + ] + }, + { + "name": "showLed", + "descr": "Зажечь один диод", + "params": [ + "номер пикселя", + "цвет в формате 0xRRGGBB" + ] + }, + { + "name": "setBrightness", + "descr": "Устанавливает общую яркость ленты от 0 до 255", + "params": [ + "яркость от 0 до 255" + ] + }, + { + "name": "vuMeter", + "descr": "Включает режим VU Meter. Важно что бы элемент ленты был ниже в списке чем элемент с датчиком, ИД которого нужно будет мониторить.", + "params": [ + "Количество каналов для отображения на ленте", + "Список ID датчиков через запятую (если указать пустую строку, то каналы будут заполняться случайными числами от 0 до 255)" + ] + }, + { + "name": "setColor", + "descr": "Устанавливает цвет ленты в формате 0xRRGGBB, например, 0xFF0000 - красный, 0x00FF00 - зеленый, 0x0000FF - синий.", + "params": [ + "цвет в формате 0xRRGGBB" + ] + }, + { + "name": "setEffect", + "descr": "Устанавливает эффект ленты. 0-79. 0 - Статичный цвет.", + "params": [ + "номер эффекта от 0 до 79" + ] + }, + { + "name": "setSpeed", + "descr": "Устанавливает скорость эффекта от 0 до 255", + "params": [ + "скорость от 0 до 255" + ] + }, + { + "name": "fadeOut", + "descr": "Плавное затухание яркости", + "params": [ + "Целевое значение яркости, до которого будет затухать", + "Шаг затухания" + ] + }, + { + "name": "fadeIn", + "descr": "Плавное нарастание яркости", + "params": [ + "Целевое значение яркости, до которого будет нарастать", + "Шаг нарастания" + ] + }, + { + "name": "stop", + "descr": "Останавливает эффект", + "params": [] + + }, + { + "name": "start", + "descr": "Запускает эффект", + "params": [] + + }, + { + "name": "pause", + "descr": "Пауза эффекта", + "params": [] + + }, + { + "name": "resume", + "descr": "Возобновляет эффект", + "params": [] + + }, + { + "name": "setSegment", + "descr": "Устанавливает сегмент ленты", + "params": [ + "номер сегмента от 0 до 7", + "глобальный номер первого пикселя в сегменте", + "глобальный номер последнего пикселя в сегменте", + "номер эффекта от 0 до 79", + "цвет в формате 0xRRGGBB, например, 0xFF0000 - красный, 0x00FF00 - зеленый, 0x0000FF - синий.", + "скорость" + ] + } + ] + }, + "defActive": false, + "usedLibs": { + "esp32*": [ + "aadafruit/Adafruit NeoPixel @ ^1.12.5", + "kitesurfer1404/WS2812FX @ ^1.4.5" + ], + "esp82*": [ + "adafruit/Adafruit NeoPixel @ ^1.12.5", + "kitesurfer1404/WS2812FX @ ^1.4.5" + ] + } +} \ No newline at end of file diff --git a/src/modules/display/LedFX/Пример на 7 диодов.json b/src/modules/display/LedFX/Пример на 7 диодов.json new file mode 100644 index 00000000..c034bb0c --- /dev/null +++ b/src/modules/display/LedFX/Пример на 7 диодов.json @@ -0,0 +1,125 @@ +{ + "mark": "iotm", + "config": [ + { + "global": 0, + "type": "Reading", + "subtype": "AnalogAdc", + "id": "t1", + "widget": "anydataRed", + "page": "Сенсоры", + "descr": "Аналог", + "map": "1,1024,1,255", + "plus": 0, + "multiply": 1, + "round": 1, + "pin": 0, + "int": "1", + "avgSteps": 1 + }, + { + "global": 0, + "type": "Reading", + "subtype": "Variable", + "id": "b1", + "needSave": 0, + "widget": "rangeServo", + "page": "Сенсоры", + "descr": "Бар 1", + "int": "0", + "val": "0.0", + "map": "1024,1024,1,255", + "plus": 0, + "multiply": 1, + "round": 0 + }, + { + "global": 0, + "type": "Reading", + "subtype": "Variable", + "id": "b2", + "needSave": 0, + "widget": "rangeServo", + "page": "Сенсоры", + "descr": "Бар 2", + "int": "0", + "val": "0.0", + "map": "1024,1024,1,255", + "plus": 0, + "multiply": 1, + "round": 0 + }, + { + "global": 0, + "type": "Reading", + "subtype": "LedFX", + "id": "fl20", + "widget": "inputTxt", + "page": "Кнопки", + "descr": "Лента", + "int": 15, + "needSave": 0, + "data_pin": "2", + "numLeds": "7", + "brightness": "50", + "speed": "100", + "color": "0xFF0000", + "effectsMode": "11", + "valueMode": 0, + "show": false + }, + { + "global": 0, + "type": "Reading", + "subtype": "VButton", + "id": "pause", + "needSave": 0, + "widget": "toggle", + "page": "Кнопки", + "descr": "Пауза", + "int": "0", + "val": "0" + }, + { + "global": 0, + "type": "Reading", + "subtype": "VButton", + "id": "bars", + "needSave": 0, + "widget": "toggle", + "page": "Кнопки", + "descr": "Бары", + "int": "0", + "val": "0" + }, + { + "global": 0, + "type": "Reading", + "subtype": "VButton", + "id": "any", + "needSave": 0, + "widget": "toggle", + "page": "Кнопки", + "descr": "Анимация", + "int": "0", + "val": "0" + }, + { + "global": 0, + "type": "Reading", + "subtype": "VButton", + "id": "fade", + "needSave": 0, + "widget": "toggle", + "page": "Кнопки", + "descr": "Скрыть", + "int": "0", + "val": "0" + } + ] +} + +scenario=>if bars then fl20.vuMeter(7, "t1") else fl20.stop() +if any then fl20.setEffect(100) else fl20.stop() +if pause then fl20.pause() else fl20.resume() +if fade then fl20.fadeOut(1, 3) else fl20.fadeIn(60, 3) \ No newline at end of file diff --git a/src/modules/sensors/AhtXX/AhtXX.cpp b/src/modules/sensors/AhtXX/AhtXX.cpp index a49e8fe1..7bac81c1 100644 --- a/src/modules/sensors/AhtXX/AhtXX.cpp +++ b/src/modules/sensors/AhtXX/AhtXX.cpp @@ -88,7 +88,7 @@ void* getAPI_AhtXX(String subtype, String param) { if (ahts.find(addr) == ahts.end()) { int shtType; - jsonRead(param, "type", shtType); + jsonRead(param, "shtType", shtType); ahts[addr] = new AHTxx(hexStringToUint8(addr), (AHTXX_I2C_SENSOR)shtType); diff --git a/src/utils/StringUtils.cpp b/src/utils/StringUtils.cpp index bfb0ec1d..d6c8c3f7 100644 --- a/src/utils/StringUtils.cpp +++ b/src/utils/StringUtils.cpp @@ -103,6 +103,7 @@ uint8_t hexStringToUint8(const String& hex) { if (tmp >= 0x00 && tmp <= 0xFF) { return tmp; } + return 0; } uint16_t hexStringToUint16(const String& hex) { @@ -110,6 +111,15 @@ uint16_t hexStringToUint16(const String& hex) { if (tmp >= 0x0000 && tmp <= 0xFFFF) { return tmp; } + return 0; +} + +uint32_t hexStringToUint32(const String& hex) { + uint32_t tmp = strtol(hex.c_str(), NULL, 0); + if (tmp >= 0x0000 && tmp <= 0xFFFFFF) { + return tmp; + } + return 0; } size_t itemsCount2(String str, const String& separator) {