diff --git a/include/classes/IoTItem.h b/include/classes/IoTItem.h index ff899a20..772a3052 100644 --- a/include/classes/IoTItem.h +++ b/include/classes/IoTItem.h @@ -87,6 +87,7 @@ class IoTItem { int _map3 = 0; int _map4 = 0; int _round = 1; // 1, 10, 100, 1000, 10000 + int _numDigits = 1; // количество целых значений, не значимые позиции заменяются нулем в строковом формате bool _global = false; // характеристика айтема, что ему нужно слать и принимать события из внешнего мира }; diff --git a/include/utils/StringUtils.h b/include/utils/StringUtils.h index 816d8353..ea403cfb 100644 --- a/include/utils/StringUtils.h +++ b/include/utils/StringUtils.h @@ -45,3 +45,7 @@ String uint64ToString(uint64_t input, uint8_t base = 10); void cleanString(String& str); unsigned char ChartoHex(char ch); + +std::vector splitStr(const String& str, const String& delimiter); + +bool strInVector(const String& str, const std::vector& vec); diff --git a/src/classes/IoTItem.cpp b/src/classes/IoTItem.cpp index 73918f46..28557848 100644 --- a/src/classes/IoTItem.cpp +++ b/src/classes/IoTItem.cpp @@ -15,6 +15,7 @@ IoTItem::IoTItem(const String& parameters) { if (!jsonRead(parameters, F("multiply"), _multiply, false)) _multiply = 1; if (!jsonRead(parameters, F("plus"), _plus, false)) _plus = 0; if (!jsonRead(parameters, F("round"), _round, false)) _round = -1; + if (!jsonRead(parameters, F("numDigits"), _numDigits, false)) _numDigits = 1; if (!jsonRead(parameters, F("global"), _global, false)) _global = false; @@ -119,9 +120,9 @@ String IoTItem::getRoundValue() { if (_round >= 0 && _round <= 6) { int sot = _round ? pow(10, (int)_round) : 1; value.valD = round(value.valD * sot) / sot; - + //todo: оптимизировать. Вынести расчет строки формата округления, чтоб использовать постоянно готовую char buf[15]; - sprintf(buf, ("%1." + (String)_round + "f").c_str(), value.valD); + sprintf(buf, ("%0" + (String)(_numDigits + _round) + "." + (String)_round + "f").c_str(), value.valD); value.valS = (String)buf; return value.valS; } else { diff --git a/src/modules/display/Lcd2004/Lcd2004.cpp b/src/modules/display/Lcd2004/Lcd2004.cpp index 0caf4ebe..5ddd92b5 100644 --- a/src/modules/display/Lcd2004/Lcd2004.cpp +++ b/src/modules/display/Lcd2004/Lcd2004.cpp @@ -1,22 +1,14 @@ #include "Global.h" #include "classes/IoTItem.h" - -//#include "LiquidCrystal_I2C.h" #include -#include - -void scanI2C(); - -//LiquidCrystal_I2C *LCDI2C; RobotClass_LiquidCrystal_I2C *LCDI2C; class Lcd2004 : public IoTItem { private: unsigned int _x; unsigned int _y; - String _id2show; - String _descr; + String _id2show, _prefix = "", _postfix = ""; int _prevStrSize; String _addr; @@ -37,42 +29,52 @@ class Lcd2004 : public IoTItem { int w = selectFromMarkerToMarker(size, ",", 0).toInt(); //количество столбцов int h = selectFromMarkerToMarker(size, ",", 1).toInt(); //количество строк if (LCDI2C == nullptr) { //инициализации экрана еще не было - //LCDI2C = new LiquidCrystal_I2C(hexStringToUint8(_addr), w, h); LCDI2C = new RobotClass_LiquidCrystal_I2C(hexStringToUint8(_addr), w, h, CP_UTF8); if (LCDI2C != nullptr) { LCDI2C->init(); + LCDI2C->clear(); + LCDI2C->backlight(); } } - - LCDI2C->clear(); - LCDI2C->backlight(); jsonRead(parameters, "coord", xy); _x = selectFromMarkerToMarker(xy, ",", 0).toInt(); _y = selectFromMarkerToMarker(xy, ",", 1).toInt(); - jsonRead(parameters, "descr", _descr); jsonRead(parameters, "id2show", _id2show); + jsonRead(parameters, "prefix", _prefix); + jsonRead(parameters, "postfix", _postfix); } - void doByInterval() { - if (LCDI2C != nullptr) { - printBlankStr(_prevStrSize); - - String tmpStr = getItemValue(_id2show); - if (_descr != "none") tmpStr = _descr + " " + tmpStr; - LCDI2C->setCursor(_x, _y); - LCDI2C->print(tmpStr); - - //LCDI2C->print("Helloy,Manager 404 !"); - //Serial.printf("ffff %s\n", _id2show); - _prevStrSize = tmpStr.length(); - } else { - scanI2C(); + void drawItem(IoTItem* item) { + String tmpStr = _prefix; + tmpStr += item->getValue(); + tmpStr += _postfix; + + printBlankStr(_prevStrSize); + LCDI2C->setCursor(_x, _y); + LCDI2C->print(tmpStr); + _prevStrSize = tmpStr.length(); + } + + void setValue(const IoTValue& Value, bool genEvent = true) { + if (LCDI2C == nullptr) return; + + value = Value; + drawItem(this); + IoTItem::setValue(Value, genEvent); + } + + void onRegEvent(IoTItem* eventItem) { + if (LCDI2C == nullptr) { scanI2C(); return;} + if (!eventItem || _id2show == "") return; + + if (_id2show == eventItem->getID()) { + setValue(eventItem->value, false); } } - IoTValue execute(String command, std::vector ¶m) { // будет возможным использовать, когда сценарии запустятся + IoTValue execute(String command, std::vector ¶m) { if (command == "noBacklight") LCDI2C->noBacklight(); else if (command == "backlight") @@ -99,9 +101,13 @@ class Lcd2004 : public IoTItem { if (param.size()) { _y = param[0].valD; } - } else if (command == "descr") { + } else if (command == "prefix") { if (param.size()) { - _descr = param[0].valS; + _prefix = param[0].valS; + } + } else if (command == "postfix") { + if (param.size()) { + _postfix = param[0].valS; } } else if (command == "id2show") { if (param.size()) { diff --git a/src/modules/display/Lcd2004/modinfo.json b/src/modules/display/Lcd2004/modinfo.json index 024750b8..0cc656ef 100644 --- a/src/modules/display/Lcd2004/modinfo.json +++ b/src/modules/display/Lcd2004/modinfo.json @@ -7,30 +7,32 @@ "type": "Reading", "subtype": "Lcd2004", "id": "Lcd", - "widget": "", - "page": "", - "descr": "T", + "widget": "inputTxt", + "page": "Экраны", + "descr": "LCD Экран", - "int": 15, "addr": "0x27", "size": "20,4", "coord": "0,0", - "id2show": "id датчика" + "id2show": "", + "prefix": "", + "postfix": "" }, { "name": "LCD экран 1602", "type": "Reading", "subtype": "Lcd2004", "id": "Lcd", - "widget": "", - "page": "", - "descr": "T", + "widget": "inputTxt", + "page": "Экраны", + "descr": "LCD Экран", - "int": 15, "addr": "0x27", "size": "16,2", "coord": "0,0", - "id2show": "id датчика" + "id2show": "", + "prefix": "", + "postfix": "" }], "about": { @@ -46,11 +48,12 @@ }, "moduleDesc": "Позволяет выводить на символьные экраны по указанным позициям значения других элементов конфигурации.", "propInfo": { - "int": "Период времени в секундах обновления информации на экране по конкретному элементу.", - "addr": "Адрес устройства на шине, обычно 0x27.", + "addr": "Адрес устройства на шине, обычно 0x27. Установите пустую строку для включения режима сканирования адресов на шине (результат в консоли).", "size": "Размерность матрицы экрана.", "coord": "Координата позиции для вывода данных элемента конфигурации.", - "id2show": "id элемента конфигурации." + "id2show": "id элемента конфигурации для отображения на экране. Если пустое значение, то данные берутся из собственной переменной.", + "prefix": "Символы до значения.", + "postfix": "Символы после значения." }, "funcInfo": [ { @@ -89,10 +92,15 @@ "params": ["Номер столбца первого символа"] }, { - "name": "descr", + "name": "prefix", "descr": "Задает приставку слева от значения", "params": ["Строка"] }, + { + "name": "postfix", + "descr": "Задает приставку справа от значения", + "params": ["Строка"] + }, { "name": "id2show", "descr": "Задает ИД элемента, значение которого хотим отображать на экране", diff --git a/src/modules/display/TM16XX/TM16XX.cpp b/src/modules/display/TM16XX/TM16XX.cpp new file mode 100644 index 00000000..7a8a1b3d --- /dev/null +++ b/src/modules/display/TM16XX/TM16XX.cpp @@ -0,0 +1,86 @@ +#include "Global.h" +#include "classes/IoTItem.h" + +#include +#include +#include + + + +class TM16XX : public IoTItem { + private: + TM16xxDisplay *_display = nullptr; + TM16xx *_module = nullptr; + std::vector _ids2show; + + public: + TM16XX(String parameters) : IoTItem(parameters) { + //jsonRead(parameters, "id2show", _id2show); + + int DIO, CLK, STB, chip, numDigits, intensity; + bool onoff; + String id2show; + jsonRead(parameters, "DIO", DIO); + jsonRead(parameters, "CLK", CLK); + jsonRead(parameters, "STB", STB); + jsonRead(parameters, "chip", chip); + jsonRead(parameters, "numDigits", numDigits); + jsonRead(parameters, "intensity", intensity); + jsonRead(parameters, "on", onoff); + + jsonRead(parameters, "id2show", id2show); + if (id2show != "") _ids2show = splitStr(id2show, ","); + + if (chip == 1637) { + _module = new TM1637(DIO, CLK, numDigits); + } else if (chip == 1638) { + _module = new TM1638(DIO, CLK, STB, numDigits); + } + _module->setupDisplay(onoff, intensity); + _display = new TM16xxDisplay(_module, numDigits); + } + + void doByInterval() { + + } + + void setValue(const IoTValue& Value, bool genEvent = true) { + if (_display == nullptr) return; + + value = Value; + _display->println(getValue()); + IoTItem::setValue(Value, genEvent); + } + + void onRegEvent(IoTItem* eventItem) { + if (_display == nullptr) return; + if (!eventItem || _ids2show.size() == 0) return; + + if (strInVector(eventItem->getID(), _ids2show)) { + if (_ids2show.size() == 1) { + _display->println(eventItem->getValue()); + } else { + _display->println(); + for (int i = 0; i < _ids2show.size(); i++) { + IoTItem* item = findIoTItem(_ids2show[i]); + if (item) { + _display->print(item->getValue()); + } + } + } + } + } + + ~TM16XX() { + delete _display; + delete _module; + }; +}; + +void *getAPI_TM16XX(String subtype, String param) { + if (subtype == F("TM16XX")) { + return new TM16XX(param); + } else { + return nullptr; + } +} diff --git a/src/modules/display/TM16XX/modinfo.json b/src/modules/display/TM16XX/modinfo.json new file mode 100644 index 00000000..9c6461ed --- /dev/null +++ b/src/modules/display/TM16XX/modinfo.json @@ -0,0 +1,133 @@ +{ + "menuSection": "Экраны", + + "configItem": [{ + "global": 0, + "name": "7 сегментный дисплей TM16XX", + "type": "Writing", + "subtype": "TM16XX", + "id": "tm", + "widget": "inputTxt", + "page": "Экраны", + "descr": "Экран", + "round": 0, + + "chip": 1637, + "numDigits": 4, + "DIO": "13", + "CLK": "14", + "STB": "12", + "intensity": "5", + "on": "1", + "id2show": "" + }], + + "about": { + "authorName": "Ilya Belyakov", + "authorContact": "https://t.me/Biveraxe", + "authorGit": "https://github.com/biveraxe", + "specialThanks": "", + "moduleName": "TM16XX", + "moduleVersion": "1.0", + "usedRam": { + "esp32_4mb": 15, + "esp8266_4mb": 15 + }, + "moduleDesc": "Позволяет выводить на 7 сегментный экран серии TM16XX (TM1637, TM1638). Может быть расширен до поддержки TM1616, TM1620, TM1628, TM1630, TM1637, TM1638, TM1640, TM1650, TM1652 и TM1668", + "propInfo": { + "int": "Период времени в секундах обновления информации на экране по конкретному элементу.", + "chip": "Номер чипа TM1637 или TM1638", + "numDigits": "Число цифр на дисплее", + "DIO": "Номер пина данных", + "CLK": "Номер пина часового сигнала", + "intensity": "Яркость 0-7", + "on": "Вкл/выкл при старте 1/0", + "STB": "Номер пина стекового сигнала - не используется на определенных моделях", + "id2show": "id элемента конфигурации для отображения. Если пустая строка, то дисплей использует свою переменную. Если указать несколько значений через запятую, то все данные будут последовательно выводиться в строку." + }, + "funcInfo": [ + { + "name": "noBacklight", + "descr": "Выключить подсветку", + "params": [] + }, + { + "name": "backlight", + "descr": "Включить подсветку", + "params": [] + }, + { + "name": "noDisplay", + "descr": "Спрятать все данные", + "params": [] + }, + { + "name": "display", + "descr": "Показать данные на экране", + "params": [] + }, + { + "name": "toggle", + "descr": "Переключает видимость значений на экране", + "params": [] + }, + { + "name": "x", + "descr": "Устанавливает первую координату", + "params": ["Номер строки первого символа"] + }, + { + "name": "y", + "descr": "Устанавливает вторую координату", + "params": ["Номер столбца первого символа"] + }, + { + "name": "descr", + "descr": "Задает приставку слева от значения", + "params": ["Строка"] + }, + { + "name": "id2show", + "descr": "Задает ИД элемента, значение которого хотим отображать на экране", + "params": ["Имя элемента конфигурации"] + } + ] + }, + + "defActive": true, + + "usedLibs": { + "esp32_4mb": [ + "https://github.com/maxint-rd/TM16xx", + "adafruit/Adafruit GFX Library @ ^1.11.5" + ], + "esp8266_4mb": [ + "https://github.com/maxint-rd/TM16xx", + "adafruit/Adafruit GFX Library @ ^1.11.5" + ], + "esp8266_1mb": [ + "https://github.com/maxint-rd/TM16xx", + "adafruit/Adafruit GFX Library @ ^1.11.5" + ], + "esp8266_1mb_ota": [ + "https://github.com/maxint-rd/TM16xx", + "adafruit/Adafruit GFX Library @ ^1.11.5" + ], + "esp8285_1mb": [ + "https://github.com/maxint-rd/TM16xx", + "adafruit/Adafruit GFX Library @ ^1.11.5" + ], + "esp8285_1mb_ota": [ + "https://github.com/maxint-rd/TM16xx", + "adafruit/Adafruit GFX Library @ ^1.11.5" + ], + "esp8266_2mb": [ + "https://github.com/maxint-rd/TM16xx", + "adafruit/Adafruit GFX Library @ ^1.11.5" + ], + "esp8266_2mb_ota": [ + "https://github.com/maxint-rd/TM16xx", + "adafruit/Adafruit GFX Library @ ^1.11.5" + ] + } +} \ No newline at end of file diff --git a/src/modules/sensors/RTC/RTC.cpp b/src/modules/sensors/RTC/RTC.cpp index 727303f0..b9994c5c 100644 --- a/src/modules/sensors/RTC/RTC.cpp +++ b/src/modules/sensors/RTC/RTC.cpp @@ -39,18 +39,18 @@ class RTC : public IoTItem { return this; } - ulong getRtcUnixTime() { - return _watch->gettimeUnix(); + unsigned long getRtcUnixTime() { + return _watch->gettimeUnix() - jsonReadInt(settingsFlashJson, F("timezone")) * 60 * 60; } void onModuleOrder(String &key, String &value) { if (key == "setUTime") { char *stopstring; - ulong ut = strtoul(value.c_str(), &stopstring, 10); + unsigned long ut = strtoul(value.c_str(), &stopstring, 10); _watch->settimeUnix(ut); SerialPrint("i", F("RTC"), "Устанавливаем время: " + value); } else if (key == "setSysTime") { - _watch->settimeUnix(unixTime); + _watch->settimeUnix(unixTime + jsonReadInt(settingsFlashJson, F("timezone")) * 60 * 60); SerialPrint("i", F("RTC"), F("Запоминаем системное время")); } } diff --git a/src/utils/StringUtils.cpp b/src/utils/StringUtils.cpp index 4234a68f..f33db48c 100644 --- a/src/utils/StringUtils.cpp +++ b/src/utils/StringUtils.cpp @@ -204,4 +204,23 @@ void cleanString(String& str) { for (size_t i = 0; i < str.length(); i++) { if (allowedChars.indexOf(str.charAt(i)) == -1) str.setCharAt(i, ' '); } +} + +std::vector splitStr(const String& str, const String& delimiter) { + std::vector result; + size_t newPos, pos = 0; + while ((newPos = str.indexOf(delimiter, pos)) != -1) { + result.push_back(str.substring(pos, newPos)); + pos = newPos + delimiter.length(); + } + result.push_back(str.substring(pos)); + return result; +} + + +bool strInVector(const String& str, const std::vector& vec) { + for (size_t i = 0; i < vec.size(); i++) { + if (vec[i] == str) return true; + } + return false; } \ No newline at end of file