diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index cf19e4b..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,89 +0,0 @@ -# !!! WARNING !!! AUTO-GENERATED FILE, PLEASE DO NOT MODIFY IT AND USE -# https://docs.platformio.org/page/projectconf/section_env_build.html#build-flags -# -# If you need to override existing CMake configuration or add extra, -# please create `CMakeListsUser.txt` in the root of project. -# The `CMakeListsUser.txt` will not be overwritten by PlatformIO. - -cmake_minimum_required(VERSION 3.2) -project("homegenie-mini") - -include(CMakeListsPrivate.txt) - -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/CMakeListsUser.txt) -include(CMakeListsUser.txt) -endif() - -add_custom_target( - PLATFORMIO_BUILD ALL - COMMAND ${PLATFORMIO_CMD} -f -c clion run "$<$>:-e${CMAKE_BUILD_TYPE}>" - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -) - -add_custom_target( - PLATFORMIO_BUILD_VERBOSE ALL - COMMAND ${PLATFORMIO_CMD} -f -c clion run --verbose "$<$>:-e${CMAKE_BUILD_TYPE}>" - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -) - -add_custom_target( - PLATFORMIO_UPLOAD ALL - COMMAND ${PLATFORMIO_CMD} -f -c clion run --target upload "$<$>:-e${CMAKE_BUILD_TYPE}>" - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -) - -add_custom_target( - PLATFORMIO_CLEAN ALL - COMMAND ${PLATFORMIO_CMD} -f -c clion run --target clean "$<$>:-e${CMAKE_BUILD_TYPE}>" - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -) - -add_custom_target( - PLATFORMIO_MONITOR ALL - COMMAND ${PLATFORMIO_CMD} -f -c clion device monitor "$<$>:-e${CMAKE_BUILD_TYPE}>" - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -) - -add_custom_target( - PLATFORMIO_TEST ALL - COMMAND ${PLATFORMIO_CMD} -f -c clion test "$<$>:-e${CMAKE_BUILD_TYPE}>" - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -) - -add_custom_target( - PLATFORMIO_PROGRAM ALL - COMMAND ${PLATFORMIO_CMD} -f -c clion run --target program "$<$>:-e${CMAKE_BUILD_TYPE}>" - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -) - -add_custom_target( - PLATFORMIO_UPLOADFS ALL - COMMAND ${PLATFORMIO_CMD} -f -c clion run --target uploadfs "$<$>:-e${CMAKE_BUILD_TYPE}>" - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -) - -add_custom_target( - PLATFORMIO_BUILD_DEBUG ALL - COMMAND ${PLATFORMIO_CMD} -f -c clion run --target debug "$<$>:-e${CMAKE_BUILD_TYPE}>" - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -) - -add_custom_target( - PLATFORMIO_UPDATE_ALL ALL - COMMAND ${PLATFORMIO_CMD} -f -c clion update - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -) - -add_custom_target( - PLATFORMIO_REBUILD_PROJECT_INDEX ALL - COMMAND ${PLATFORMIO_CMD} -f -c clion init --ide clion - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -) - -add_custom_target( - PLATFORMIO_DEVICE_LIST ALL - COMMAND ${PLATFORMIO_CMD} -f -c clion device list - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -) - -#add_executable(Z_DUMMY_TARGET ${SRC_LIST}) diff --git a/CMakeListsPrivate.txt b/CMakeListsPrivate.txt deleted file mode 100644 index e069f21..0000000 --- a/CMakeListsPrivate.txt +++ /dev/null @@ -1,64 +0,0 @@ -set(ENV{PATH} "$ENV{HOME}/.nvm/versions/node/v8.1.0/bin:$ENV{HOME}/.platformio/penv/bin") -set(PLATFORMIO_CMD "$ENV{HOME}/.platformio/penv/bin/platformio") - -SET(CMAKE_C_COMPILER "$ENV{HOME}/.platformio/packages/toolchain-xtensa/bin/xtensa-lx106-elf-gcc") -SET(CMAKE_CXX_COMPILER "$ENV{HOME}/.platformio/packages/toolchain-xtensa/bin/xtensa-lx106-elf-g++") -SET(CMAKE_CXX_FLAGS_DISTRIBUTION "-fno-rtti -fno-exceptions -std=c++11 -Os -mlongcalls -mtext-section-literals -falign-functions=4 -U__STRICT_ANSI__ -ffunction-sections -fdata-sections -Wall") -SET(CMAKE_C_FLAGS_DISTRIBUTION "-std=gnu99 -Wpointer-arith -Wno-implicit-function-declaration -Wl,-EL -fno-inline-functions -nostdlib -Os -mlongcalls -mtext-section-literals -falign-functions=4 -U__STRICT_ANSI__ -ffunction-sections -fdata-sections -Wall") -set(CMAKE_CXX_STANDARD 11) - -add_definitions(-D'PLATFORMIO=30603') -add_definitions(-D'ESP8266') -add_definitions(-D'ARDUINO_ARCH_ESP8266') -add_definitions(-D'ESP8266_WEMOS_D1MINI') -add_definitions(-D'F_CPU=80000000L') -add_definitions(-D'__ets__') -add_definitions(-D'ICACHE_FLASH') -add_definitions(-D'ARDUINO=10805') -add_definitions(-D'ARDUINO_BOARD=\"PLATFORMIO_D1_MINI\"') -add_definitions(-D'LWIP_OPEN_SRC') -add_definitions(-D'TCP_MSS=536') -add_definitions(-D'VTABLES_IN_FLASH') - -include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/tools/sdk/include") -include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/tools/sdk/libc/xtensa-lx106-elf/include") -include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/cores/esp8266") -include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/tools/sdk/lwip2/include") -include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/variants/d1_mini") -include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/ArduinoOTA") -include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/DNSServer/src") -include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/EEPROM") -include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266AVRISP/src") -include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266HTTPClient/src") -include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266HTTPUpdateServer/src") -include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266LLMNR") -include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266NetBIOS") -include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266SSDP") -include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266WebServer/src") -include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266WiFi/src") -include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266WiFiMesh/src") -include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266httpUpdate/src") -include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266mDNS") -include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/Ethernet/src") -include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/GDBStub/src") -include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/Hash/src") -include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/SD/src") -include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/SPI") -include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/SPISlave/src") -include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/Servo/src") -include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/SoftwareSerial") -include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/TFT_Touch_Shield_V2") -include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/Ticker") -include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/Wire") -include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/esp8266/src") -include_directories("$ENV{HOME}/.platformio/packages/toolchain-xtensa/xtensa-lx106-elf/include") -include_directories("$ENV{HOME}/.platformio/packages/toolchain-xtensa/xtensa-lx106-elf/include/c++/4.8.2") -include_directories("$ENV{HOME}/.platformio/packages/toolchain-xtensa/xtensa-lx106-elf/include/c++/4.8.2/xtensa-lx106-elf") -include_directories("$ENV{HOME}/.platformio/packages/toolchain-xtensa/lib/gcc/xtensa-lx106-elf/4.8.2/include") -include_directories("$ENV{HOME}/.platformio/packages/toolchain-xtensa/lib/gcc/xtensa-lx106-elf/4.8.2/include-fixed") -include_directories("$ENV{HOME}/.platformio/packages/tool-unity") - -include_directories("./include") -include_directories("./src") - -FILE(GLOB_RECURSE SRC_LIST "./src/*.*" "./lib/*.*" "./.piolibdeps/*.*") diff --git a/examples/color-light/color-light.cpp b/examples/color-light/color-light.cpp index c4ebede..065fe21 100644 --- a/examples/color-light/color-light.cpp +++ b/examples/color-light/color-light.cpp @@ -32,7 +32,7 @@ void setup() { // Get the default system module auto miniModule = homeGenie->getDefaultModule(); - miniModule->name = "Smart light"; + miniModule->name = "LED Controller"; // Add to the default module some configuration properties. // Properties starting with `Widget.OptionField.` are special @@ -48,14 +48,6 @@ void setup() { miniModule->properties.add( new ModuleParameter("Widget.OptionField.LED.power", "number:LED.power:5:100:25:led_power")); - // Dropdown list control to select the light animation effect - miniModule->properties.add( - new ModuleParameter("Widget.OptionField.FX.Rainbow", - "select:FX.Style:light_style:solid|rainbow|rainbow_2|white_stripes|white_stripes_2|kaleidoscope")); - // Dropdown list control to enable the strobe effect - miniModule->properties.add( - new ModuleParameter("Widget.OptionField.FX.Strobe", - "select:FX.Strobe:strobe_effect:off|slow|medium|fast")); // The following are the actual properties where // UI controls implemented by `Widget.Options` @@ -64,13 +56,10 @@ void setup() { miniModule->properties.add(mpLedCount); mpMaxPower = new ModuleParameter("LED.power", "25"); miniModule->properties.add(mpMaxPower); - mpFxStyle = new ModuleParameter("FX.Style", lightStyleNames[0]); - miniModule->properties.add(mpFxStyle); - mpFxStrobe = new ModuleParameter("FX.Strobe", "off"); - miniModule->properties.add(mpFxStrobe); // Get status LED config - int statusLedPin = Config::getSetting("stld-pin", "-1").toInt(); + auto pin = Config::getSetting("stld-pin"); + int statusLedPin = pin.isEmpty() ? -1 : pin.toInt(); if (statusLedPin >= 0) { int statusLedType = Config::getSetting("stld-typ", "82").toInt(); int statusLedSpeed = Config::getSetting("stld-spd", "0").toInt(); @@ -105,12 +94,12 @@ void setup() { maxPower = Config::getSetting("leds-pwr").toInt(); if (maxPower <= 0) maxPower = DEFAULT_MAX_POWER; createPixels(); - + // default values mpLedCount->value = String(ledsCount); mpMaxPower->value = String(maxPower); // Setup main LEDs control module - mainModule = new ColorLight(IO::IOEventDomains::HomeAutomation_HomeGenie, "C1", "Main"); + mainModule = new ColorLight(IO::IOEventDomains::HomeAutomation_HomeGenie, "C1", "Color Light"); mainModule->module->properties.add( new ModuleParameter("Widget.Preference.AudioLight", "true")); mainModule->onSetColor([](LightColor color) { @@ -119,8 +108,26 @@ void setup() { }); homeGenie->addAPIHandler(mainModule); + auto module = mainModule->module; + module->name = "Smart Light"; + + // Add to the ColorLight module some configuration properties: + // - dropdown list control to select the light animation effect + module->properties.add( + new ModuleParameter("Widget.OptionField.FX.Rainbow", + "select:FX.Style:light_style:solid|rainbow|rainbow_2|white_stripes|white_stripes_2|kaleidoscope")); + // - dropdown list control to enable the strobe effect + module->properties.add( + new ModuleParameter("Widget.OptionField.FX.Strobe", + "select:FX.Strobe:strobe_effect:off|slow|medium|fast")); + + mpFxStyle = new ModuleParameter("FX.Style", lightStyleNames[0]); + module->properties.add(mpFxStyle); + mpFxStrobe = new ModuleParameter("FX.Strobe", "off"); + module->properties.add(mpFxStrobe); + // Setup control buttons - setupControlButtons(miniModule); + setupControlButtons(module); // Initialize FX buffer fx_init(ledsCount, currentColor); @@ -133,6 +140,8 @@ void setup() { } + // Name shown in SMNP/UPnP advertising + Config::system.friendlyName = "LED Controller"; homeGenie->begin(); refresh(); diff --git a/examples/ir-transceiver/ir-transceiver.cpp b/examples/ir-transceiver/ir-transceiver.cpp index b608569..8dfb3ba 100644 --- a/examples/ir-transceiver/ir-transceiver.cpp +++ b/examples/ir-transceiver/ir-transceiver.cpp @@ -86,6 +86,7 @@ void setup() { homeGenie->addAPIHandler(colorLight); #endif + Config::system.friendlyName = "Firefly IR"; homeGenie->begin(); } diff --git a/examples/rf-transceiver/rf-transceiver.cpp b/examples/rf-transceiver/rf-transceiver.cpp index e5a7072..3a571f8 100644 --- a/examples/rf-transceiver/rf-transceiver.cpp +++ b/examples/rf-transceiver/rf-transceiver.cpp @@ -57,6 +57,7 @@ void setup() { receiver->setModule(rfModule); homeGenie->addIOHandler(receiver); + Config::system.friendlyName = "Firefly RF"; homeGenie->begin(); } diff --git a/examples/smart-sensor/CommonSensors.h b/examples/smart-sensor/CommonSensors.h index 6dcac54..0364f7e 100644 --- a/examples/smart-sensor/CommonSensors.h +++ b/examples/smart-sensor/CommonSensors.h @@ -43,11 +43,11 @@ void includeCommonSensors(HomeGenie* homeGenie, Module* miniModule) { if (Config::getSetting("sdht-typ").equals("22")) { auto dhtSensor = new DHTxx(22, dhtSensorPint); dhtSensor->setModule(miniModule); - homeGenie->addIOHandler(dhtSensor); + homeGenie->addIOHandler((IIOEventSender*)dhtSensor); } else if (Config::getSetting("sdht-typ").equals("11")) { auto dhtSensor = new DHTxx(11, dhtSensorPint); dhtSensor->setModule(miniModule); - homeGenie->addIOHandler(dhtSensor); + homeGenie->addIOHandler((IIOEventSender*)dhtSensor); } } diff --git a/examples/smart-sensor/smart-sensor.cpp b/examples/smart-sensor/smart-sensor.cpp index 049c56b..9ffc3bb 100644 --- a/examples/smart-sensor/smart-sensor.cpp +++ b/examples/smart-sensor/smart-sensor.cpp @@ -44,6 +44,7 @@ void setup() { includeCommonSensors(homeGenie, miniModule); + Config::system.friendlyName = "Smart Sensor"; homeGenie->begin(); } diff --git a/examples/x10-transceiver/x10-transceiver.cpp b/examples/x10-transceiver/x10-transceiver.cpp index 5281127..ee1daf9 100644 --- a/examples/x10-transceiver/x10-transceiver.cpp +++ b/examples/x10-transceiver/x10-transceiver.cpp @@ -57,6 +57,7 @@ void setup() { x10Receiver->setModule(rfModule); homeGenie->addIOHandler(x10Receiver); + Config::system.friendlyName = "Firefly X10"; homeGenie->begin(); } diff --git a/lib/ESP32_BleSerial/src/BleSerial.cpp b/lib/ESP32_BleSerial/src/BleSerial.cpp index ba6fd49..985dfc7 100644 --- a/lib/ESP32_BleSerial/src/BleSerial.cpp +++ b/lib/ESP32_BleSerial/src/BleSerial.cpp @@ -168,7 +168,7 @@ void BleSerial::onWrite(BLECharacteristic *pCharacteristic) { if (pCharacteristic->getUUID().toString() == BLE_RX_UUID) { - std::string value = pCharacteristic->getValue(); + std::string value = pCharacteristic->getValue().c_str(); for (int i = 0; i < value.length(); i++) receiveBuffer.add(value[i]); diff --git a/lib/LinkedList/.gitattributes b/lib/LinkedList/.gitattributes new file mode 100644 index 0000000..412eeda --- /dev/null +++ b/lib/LinkedList/.gitattributes @@ -0,0 +1,22 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Custom for Visual Studio +*.cs diff=csharp +*.sln merge=union +*.csproj merge=union +*.vbproj merge=union +*.fsproj merge=union +*.dbproj merge=union + +# Standard to msysgit +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain diff --git a/lib/LinkedList/.gitignore b/lib/LinkedList/.gitignore new file mode 100644 index 0000000..b9d6bd9 --- /dev/null +++ b/lib/LinkedList/.gitignore @@ -0,0 +1,215 @@ +################# +## Eclipse +################# + +*.pydevproject +.project +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.classpath +.settings/ +.loadpath + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# CDT-specific +.cproject + +# PDT-specific +.buildpath + + +################# +## Visual Studio +################# + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +build/ +[Bb]in/ +[Oo]bj/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.Publish.xml +*.pubxml + +# NuGet Packages Directory +## TODO: If you have NuGet Package Restore enabled, uncomment the next line +#packages/ + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.[Pp]ublish.xml +*.pfx +*.publishsettings + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +############# +## Windows detritus +############# + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac crap +.DS_Store + + +############# +## Python +############# + +*.py[co] + +# Packages +*.egg +*.egg-info +dist/ +build/ +eggs/ +parts/ +var/ +sdist/ +develop-eggs/ +.installed.cfg + +# Installer logs +pip-log.txt + +# Unit test / coverage reports +.coverage +.tox + +#Translations +*.mo + +#Mr Developer +.mr.developer.cfg diff --git a/lib/LinkedList/.piopm b/lib/LinkedList/.piopm new file mode 100644 index 0000000..579b499 --- /dev/null +++ b/lib/LinkedList/.piopm @@ -0,0 +1 @@ +{"type": "library", "name": "LinkedList", "version": "1.5.0", "spec": {"owner": "vortigont", "id": 12906, "name": "LinkedList", "requirements": null, "uri": null}} \ No newline at end of file diff --git a/lib/LinkedList/CHANGELOG.md b/lib/LinkedList/CHANGELOG.md new file mode 100644 index 0000000..82b87a3 --- /dev/null +++ b/lib/LinkedList/CHANGELOG.md @@ -0,0 +1,14 @@ +## Changelog + +## v1.5.0 - 2023.01.27 + + provide LinkedList deep-copy via assign operator + + some tests cleanup + + test cases cover `exist()` method + * optimized `clear()` method to use non-copy `unlink()` + * refactoring for `remove()`, `shift()`, `pop()` methods + + added `unlink()` method to delete nodes without data object copy/return + * fixed bug when cached node index was updated wrong on `add()` + * change type of `size` and `index` to unsigned + + pass data objects by const ref to avoid useless obj copy + + \ No newline at end of file diff --git a/lib/LinkedList/CMakeLists.txt b/lib/LinkedList/CMakeLists.txt new file mode 100644 index 0000000..e12f73a --- /dev/null +++ b/lib/LinkedList/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 3.5) + +if(ESP_PLATFORM) + idf_component_register( + SRCS "LList.h" + INCLUDE_DIRS "." + ) +endif() + +project(LinkedList VERSION 1.4.0) \ No newline at end of file diff --git a/lib/LinkedList/LICENSE.txt b/lib/LinkedList/LICENSE.txt new file mode 100644 index 0000000..5c02604 --- /dev/null +++ b/lib/LinkedList/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Ivan Seidel + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/lib/LinkedList/LList.h b/lib/LinkedList/LList.h new file mode 100644 index 0000000..0ed5eff --- /dev/null +++ b/lib/LinkedList/LList.h @@ -0,0 +1,28 @@ +/* + LinkedList.h - V1.1 - Generic LinkedList implementation + Works better with FIFO, because LIFO will need to + search the entire List to find the last one; + + For instructions, go to https://github.com/ivanseidel/LinkedList + + Created by Ivan Seidel Gomes, March, 2013. + Released into the public domain. +*/ + +/* + This is a namespace wrapper to avoid collision with ESP Async WebServer's LinkedList class + include it instead of and use Class types - LList, LNode +*/ + +#ifndef LList_h +#define LList_h +#include + +namespace LL{ +#include +} + + +template using LNode = LL::ListNode; +template using LList = LL::LinkedList; +#endif \ No newline at end of file diff --git a/lib/LinkedList/LinkedList.h b/lib/LinkedList/LinkedList.h new file mode 100644 index 0000000..34ab881 --- /dev/null +++ b/lib/LinkedList/LinkedList.h @@ -0,0 +1,558 @@ +/* + LinkedList.h - V1.1 - Generic LinkedList implementation + Works better with FIFO, because LIFO will need to + search the entire List to find the last one; + + For instructions, go to https://github.com/ivanseidel/LinkedList + + Created by Ivan Seidel Gomes, March, 2013. + Released into the public domain. +*/ + +#pragma once + +#include +#include + +template +struct ListNode +{ + T data; + ListNode *next; + + explicit ListNode(ListNode* _next = nullptr) : next(_next) {} + explicit ListNode(const T& _v, ListNode* _next = nullptr) : data(_v), next(_next) {} +}; + +template +class LinkedList{ + +protected: + unsigned _size = 0; + ListNode *root = nullptr; + ListNode *last = nullptr; + + // Helps "get" method, by saving last position + mutable ListNode *lastNodeGot = nullptr; + mutable unsigned lastIndexGot=0; // cached node index + + ListNode* getNode(unsigned index) const; + + ListNode* findEndOfSortedString(ListNode *p, int (*cmp)(T &, T &)); + + /** + * @brief delete last node in a list + * @return true if success + */ + void _pop(); + + /** + * @brief delete first node in a list + * @return true if success + */ + void _shift(); + +public: + LinkedList(){}; + LinkedList(unsigned sizeIndex, T _t); //initiate list size and default value + LinkedList(const LinkedList &rhs) : LinkedList(){ *this = rhs; }; // clone constructor + virtual ~LinkedList(); + + /* + Returns current size of LinkedList + */ + virtual unsigned size() const; + /* + Adds a T object in the specified index; + Unlink and link the LinkedList correcly; + Increment _size + */ + virtual bool add(unsigned index, const T&); + /* + Adds a T object in the end of the LinkedList; + Increment _size; + */ + virtual bool add(const T&); + /* + Adds a T object in the start of the LinkedList; + Increment _size; + */ + virtual bool unshift(const T&); + /* + Set the object at index, with T; + */ + virtual bool set(unsigned index, const T&); + + /* + Remove node at index; + If index is not reachable, returns false; + else, deletes node + Returns a copy of T object from removed node + */ + virtual T remove(unsigned index); + + /* + Unlink and delete node at index; + NOTE: this will not destroy dyn alloced objects + like pointer to obj created with 'new' + use 'delete(remove())' instead or use smart pointers + */ + void unlink(unsigned index); + + /* + Remove last object; + Returns a copy of T object from removed node + */ + virtual T pop(); + + /** + * @brief Remove first object + * Returns a copy of T object from removed node + */ + virtual T shift(); + + /* + Get the index'th element on the list; + Return Element if accessible, + else, return false; + */ + virtual T get(unsigned index) const; + + /* + Get first element of the list; + Return Element if accessible, + else, return false; + */ + virtual T head() const; + + /* + Get last element of the list; + Return Element if accessible, + else, return false; + */ + virtual T tail() const; + + /* + Return true if element with specified index exist + note: this works faster than (uncached) get(index) + */ + virtual bool exist(unsigned index) const; + + /** + * @brief clear linked list + * effectively unlinks all nodes from a chain + * NOTE: this will destruct linked nodes not considering stored objects + * i.e. it's OK to clear nodes containing trivial objects like int, float, etc... + * if node contains pointers to dynamically allocated objects created + * with 'new' operator it will result in a mem leak! + */ + virtual void clear(); + + /* + Sort the list, given a comparison function + */ + virtual void sort(int (*cmp)(T &, T &)); + + + inline T& operator[](unsigned i) { return getNode(i)->data; } + inline const T& operator[](const unsigned i) const { return getNode(i)->data; } + + // deep-copy via assign operator + virtual LinkedList & operator =(const LinkedList &rhs); + + /* + ConstIterator class + provides immutable forward iterator for the list + */ + struct ConstIterator { + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; + using value_type = T; + using pointer = const T*; + using reference = const T&; + + ConstIterator(ListNode *ptr = nullptr) : m_ptr(ptr) { if (m_ptr != nullptr) m_next_ptr = ptr->next; } + + const reference operator*() const { return m_ptr->data; } + const pointer operator->() const { return &m_ptr->data; } + + // Prefix increment + ConstIterator& operator++() { m_ptr = m_next_ptr; m_next_ptr = m_next_ptr ? m_next_ptr->next : nullptr; return *this; } + + // Postfix increment + ConstIterator operator++(int) { ConstIterator tmp = *this; m_ptr = m_next_ptr; m_next_ptr = m_next_ptr ? m_next_ptr->next : nullptr; return tmp; } + + bool operator== (const ConstIterator& a) const { return m_ptr == a.m_ptr; }; + bool operator!= (const ConstIterator& a) const { return m_ptr != a.m_ptr; }; + //friend bool operator== (const ConstIterator& a, const ConstIterator& b) { return a.m_ptr == b.m_ptr; }; + //friend bool operator!= (const ConstIterator& a, const ConstIterator& b) { return a.m_ptr != b.m_ptr; }; + + friend LinkedList; + + protected: + ListNode *m_ptr; + ListNode *m_next_ptr = nullptr; + }; + + /* + Iterator class + inherits from ConstIterator, provides mutable forward iterator for the list + */ + struct Iterator : public ConstIterator { + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; + using value_type = T; + using pointer = T*; + using reference = T&; + + Iterator(ListNode *ptr = nullptr) : ConstIterator(ptr) {} + Iterator(){} + + reference operator*() { return this->m_ptr->data; } + pointer operator->() { return &this->m_ptr->data; } + }; + + // iterator methods + ConstIterator cbegin() const { return ConstIterator(root); } + ConstIterator cend() const { return ConstIterator(nullptr); } // same as last->next for non-empty list + Iterator begin() { return Iterator(root); } + Iterator end() { return Iterator(nullptr); } // same as last->next for non-empty list + +}; + +// D-tor +template +LinkedList::~LinkedList(){ clear(); } + +/* + Actualy "logic" coding +*/ +template +ListNode* LinkedList::getNode(unsigned index) const { + if (!_size || index >=_size) + return nullptr; + + if (!index) + return root; + + if (index == _size-1) + return last; + + unsigned _pos = 0; + ListNode* current = root; + + // Check if the node trying to get is + // ahead or equal to the last one got + if(lastIndexGot <= index){ + _pos = lastIndexGot; + current = lastNodeGot; + } + + while(_pos < index && current){ + current = current->next; + _pos++; + } + + // Check if the object index got is the same as the required + if(_pos == index){ + lastIndexGot = index; + lastNodeGot = current; + return current; + } + + return nullptr; +} + +template +unsigned LinkedList::size() const { + return _size; +} + +template +LinkedList::LinkedList(unsigned sizeIndex, T _t){ + for (unsigned i = 0; i < sizeIndex; i++){ + add(_t); + } +} + +template +bool LinkedList::add(unsigned index, const T& _t){ + if(index >= _size) + return add(_t); + + if(!index) + return unshift(_t); + + lastIndexGot = index; + ListNode *_prev = getNode(--index); + + _prev->next = new ListNode(_t, _prev->next); + lastNodeGot = _prev->next; + + _size++; + + return true; +} + +template +bool LinkedList::add(const T& _t){ + + if(root){ + // Already have elements inserted + last->next = new ListNode(_t); + last = last->next; + } else { + // First element being inserted + root = new ListNode(_t); + last = root; + } + + lastIndexGot = _size; + lastNodeGot = last; + ++_size; + + return true; +} + +template +bool LinkedList::unshift(const T& _t){ + + if(!_size) + return add(_t); + + root = new ListNode(_t, root); + + _size++; + + lastIndexGot = 0; + lastNodeGot = root; + + return true; +} + +template +bool LinkedList::set(unsigned index, const T& _t){ + // Check if index position is in bounds + if(index >= _size) + return false; + + getNode(index)->data = _t; + return true; +} + +template +void LinkedList::_pop(){ + if(!_size) + return; + + if (_size == 1){ + // Only one element left on the list + delete(root); + root = last = lastNodeGot = nullptr; + lastIndexGot = _size = 0; + return; + } + + ListNode *tmp = getNode(_size - 2); + delete(tmp->next); + tmp->next = nullptr; + last = lastNodeGot = tmp; + lastIndexGot = --_size; + --lastIndexGot; +} + +template +T LinkedList::pop(){ + if(!_size) + return T(); + + if(_size > 1){ + ListNode *tmp = getNode(_size - 2); + T ret(tmp->next->data); + _pop(); + return ret; + } + + T ret(root->data); + _pop(); + return ret; +} + +template +void LinkedList::_shift(){ + if(!_size) + return; + + if (_size == 1){ + // Only one element left on the list + delete(root); + root = last = lastNodeGot = nullptr; + lastIndexGot = _size = 0; + return; + } + + // drop first node + ListNode *_next = root->next; + delete(root); + root = lastNodeGot = _next; + lastIndexGot = 0; + --_size; +} + +template +T LinkedList::shift(){ + if(!_size) + return T(); + + T data(root->data); + _shift(); + return data; +} + +template +T LinkedList::remove(unsigned index){ + if (index >= _size) + return T(); + + if(!index) + return shift(); + + if (index == _size-1) + return pop(); + + T ret(getNode(index)->data); + unlink(index); + return ret; +} + +template +void LinkedList::unlink(unsigned index){ + if (!_size || index >= _size) + return; + + if(!index) + return _shift(); + + if (index == _size-1) + return _pop(); + + ListNode *prev = getNode(--index); + ListNode *toDelete = prev->next; + prev->next = prev->next->next; + delete(toDelete); + _size--; + lastIndexGot = index; + lastNodeGot = prev; +} + +template +T LinkedList::get(unsigned index) const { + ListNode *tmp = getNode(index); + + return (tmp ? tmp->data : T()); +} + +template +void LinkedList::clear(){ + while(_size) + _shift(); +} + +template +void LinkedList::sort(int (*cmp)(T &, T &)){ + if(_size < 2) return; // trivial case; + + for(;;) { + + ListNode **joinPoint = &root; + + while(*joinPoint) { + ListNode *a = *joinPoint; + ListNode *a_end = findEndOfSortedString(a, cmp); + + if(!a_end->next ) { + if(joinPoint == &root) { + last = a_end; + lastIndexGot = 0; + return; + } + else { + break; + } + } + + ListNode *b = a_end->next; + ListNode *b_end = findEndOfSortedString(b, cmp); + + ListNode *tail = b_end->next; + + a_end->next = NULL; + b_end->next = NULL; + + while(a && b) { + if(cmp(a->data, b->data) <= 0) { + *joinPoint = a; + joinPoint = &a->next; + a = a->next; + } + else { + *joinPoint = b; + joinPoint = &b->next; + b = b->next; + } + } + + if(a) { + *joinPoint = a; + while(a->next) a = a->next; + a->next = tail; + joinPoint = &a->next; + } + else { + *joinPoint = b; + while(b->next) b = b->next; + b->next = tail; + joinPoint = &b->next; + } + } + } +} + +template +ListNode* LinkedList::findEndOfSortedString(ListNode *p, int (*cmp)(T &, T &)) { + while(p->next && cmp(p->data, p->next->data) <= 0) { + p = p->next; + } + + return p; +} + +template +T LinkedList::head() const { + return _size ? root->data : T(); +} + +template +T LinkedList::tail() const { + return _size ? last->data : T(); +} + +template +bool LinkedList::exist(unsigned index) const { + return (index < _size); +} + +template +LinkedList& LinkedList::operator =(const LinkedList& rhs) { + clear(); + LinkedList::ConstIterator i(rhs.root); + while (i != rhs.cend()){ + add(*i); + ++i; + } + + //for (const auto& i : std::as_const(rhs)) // std::as_const req c++17 + // add(*i); + + return *this; +} diff --git a/lib/LinkedList/README.md b/lib/LinkedList/README.md new file mode 100644 index 0000000..477c676 --- /dev/null +++ b/lib/LinkedList/README.md @@ -0,0 +1,221 @@ +# LinkedList + +__| [CHANGELOG](/CHANGELOG.md) |__ + +This is a fork of [ivanseidel](https://github.com/ivanseidel)'s [LinkedList](https://github.com/ivanseidel/LinkedList) lib. +I needed some features for my projects but it looks like [upstream](https://github.com/ivanseidel/LinkedList) is not suported much recently. So I decided to make some improvements and merge fixes on my owm. At least till ivanseidel's [PR](https://github.com/ivanseidel/LinkedList/pulls)'s are pending. + + +### Changes compared to origin + + - more optimization and improvement could be found in [CHANGELOG](CHANGELOG.md) + + - provide LinkedList object deep-copy via assign operator + + - Lib could be build as an ESP-IDF component via provided CMakeLists.txt + + - getters methods are const-aware correct + + - STL-like forward Iterators [added](https://github.com/ivanseidel/LinkedList/pull/55) + + - Cache node [improvement](https://github.com/ivanseidel/LinkedList/pull/56) + + - added `head()`/`tail()`/`exist()` helpers to make user code simple on Node access/checks + + - added [wrapper namespace](https://github.com/ivanseidel/LinkedList/pull/51) to workaround Async Webserver Class name collision + + - updated [library.json](library.json) for [PlatformIO](https://platformio.org/) capability + + - merged [ivanseidel/LinkedList#48](https://github.com/ivanseidel/LinkedList/pull/48) (moved test.cpp into subdir) + + +=============================== + +This library was developed targeting **`Arduino`** applications. However, works just great with any C++. + +Implementing a buffer for objects takes time. If we are not in the mood, we just create an `array[1000]` with enough size. + +The objective of this library is to create a pattern for projects. +If you need to use a List of: `int`, `float`, `objects`, `Lists` or `Wales`. **This is what you are looking for.** + +With a simple but powerful caching algorithm, you can get subsequent objects much faster than usual. Tested without any problems with Lists bigger than 2000 members. + +## Installation + +1. [Download](https://github.com/ivanseidel/LinkedList/archive/master.zip) the Latest release from gitHub. +2. Unzip and modify the Folder name to "LinkedList" (Remove the '-version') +3. Paste the modified folder on your Library folder (On your `Libraries` folder inside Sketchbooks or Arduino software). +4. Reopen the Arduino software. + +**If you are here, because another Library requires this class, just don't waste time reading bellow. Install and ready.** + +## Tests + +`cd extras/test` to this directory and run `g++ -std=c++14 extras/test/tests.cpp -o tests && ./tests` + +------------------------- + +## Getting started + +### The `LinkedList` class + +In case you don't know what a LinkedList is and what it's used for, take a quick look at [Wikipedia::LinkedList](https://en.wikipedia.org/wiki/Linked_list) before continuing. + +#### To declare a LinkedList object +```c++ +// Instantiate a LinkedList that will hold 'integer' +LinkedList myLinkedList = LinkedList(); + +// Or just this +LinkedList myLinkedList; + +// But if you are instantiating a pointer LinkedList... +LinkedList *myLinkedList = new LinkedList(); + +// If you want a LinkedList with any other type such as 'MyClass' +// Make sure you call delete(MyClass) when you remove! +LinkedList *myLinkedList = new LinkedList(); +``` + +#### Getting the size of the linked list +```c++ +// To get the size of a linked list, make use of the size() method +int theSize = myList.size(); + +// Notice that if it's pointer to the linked list, you should use -> instead +int theSize = myList->size(); +``` + +#### Adding elements + +```c++ +// add(obj) method will insert at the END of the list +myList.add(myObject); + +// add(index, obj) method will try to insert the object at the specified index +myList.add(0, myObject); // Add at the beginning +myList.add(3, myObject); // Add at index 3 + +// unshift(obj) method will insert the object at the beginning +myList.unshift(myObject); +``` + +#### Getting elements + +```c++ +// get(index) will return the element at index +// (notice that the start element is 0, not 1) + +// Get the FIRST element +myObject = myList.get(0); +or +myObject = myList.head(); + + +// Get the third element +myObject = myList.get(2); + +// Get the LAST element +myObject = myList.get(myList.size() - 1); +or +myObject = myList.tail(); +``` + +#### Changing elements +```c++ +// set(index, obj) method will change the object at index to obj + +// Change the first element to myObject +myList.set(0, myObject); + +// Change the third element to myObject +myList.set(2, myObject); + +// Change the LAST element of the list +myList.set(myList.size() - 1, myObject); +``` + +#### Deleting elements +*NOTE:* Deleting list nodes won't DELETE/FREE memory from Pointers, if you +are storing Classes/Poiners in a list, manualy delete and free those before removing nodes. +OR better to use `std::shared_pointer` or other smart structures. + +```c++ +// remove(index) will remove and return the element at index + +// Unlink/delete the first object +myList.unlink(0); + +// Get and Delete the third element +myDeletedObject = myList.remove(2); + +// pop() will remove and return the LAST element +myDeletedObject = myList.pop(); + +// shift() will remove and return the FIRST element +myDeletedObject = myList.shift(); + +// clear() will erase the entire list, leaving it with 0 elements +myList.clear(); +``` + +#### Sorting elements +```c++ +// Sort using a comparator function +myList.sort(myComparator); +``` + +------------------------ + +## Library Reference + +### `ListNode` struct + +- `T` `ListNode::data` - The object data + +- `ListNode` `*next` - Pointer to the next Node + +### `LinkedList` class + +**`boolean` methods returns if succeeded** + +- `LinkedList::LinkedList()` - Constructor. + +- `LinkedList::~LinkedList()` - Destructor. Clear Nodes to minimize memory. Does not free pointer memory. + +- `int` `LinkedList::size()` - Returns the current size of the list. + +- `bool` `LinkedList::add(T)` - Add element T at the END of the list. + +- `bool` `LinkedList::add(int index, T)` - Add element T at `index` of the list. + +- `bool` `LinkedList::unshift(T)` - Add element T at the BEGINNING of the list. + +- `bool` `LinkedList::set(int index, T)` - Set the element at `index` to T. + +- `T` `LinkedList::remove(int index)` - Remove element at `index`. Return the removed element. Does not free pointer memory + +- `T` `LinkedList::pop()` - Remove the LAST element. Return the removed element. + +- `T` `LinkedList::shift()` - Remove the FIRST element. Return the removed element. + +- `T` `LinkedList::get(int index)` - Return the element at `index`. + +- `void` `LinkedList::clear()` - Removes all elements. Does not free pointer memory. + +- `void` `LinkedList::sort(int (*cmp)(T &, T &))` - Sorts the linked list according to a comparator funcrion. The comparator should return < 0 if the first argument should be sorted before the second, and > 0 if the first argument should be sorted after the first element. (Same as how `strcmp()` works.) + +- **protected** `int` `LinkedList::_size` - Holds the cached size of the list. + +- **protected** `ListNode` `LinkedList::*root` - Holds the root node of the list. + +- **protected** `ListNode` `LinkedList::*last` - Holds the last node of the list. + +- **protected** `ListNode*` `LinkedList::getNode(int index)` - Returns the `index` node of the list. + +### Version History + +* `1.1 (2013-07-20)`: Cache implemented. Getting subsequent objects is now O(N). Before, O(N^2). +* `1.0 (2013-07-20)`: Original release + +![LinkedList](https://d2weczhvl823v0.cloudfront.net/ivanseidel/LinkedList/trend.png) diff --git a/lib/LinkedList/examples/ClassList/ClassList.pde b/lib/LinkedList/examples/ClassList/ClassList.pde new file mode 100644 index 0000000..9a8ea9d --- /dev/null +++ b/lib/LinkedList/examples/ClassList/ClassList.pde @@ -0,0 +1,81 @@ +/* + LinkedList Example + Link: http://github.com/ivanseidel/LinkedList + + Example Created by + Tom Stewart, github.com/tastewar + + Edited by: + Ivan Seidel, github.com/ivanseidel +*/ + +#include + +// Let's define a new class +class Animal { + public: + char *name; + bool isMammal; +}; + +char catname[]="kitty"; +char dogname[]="doggie"; +char emuname[]="emu"; + +LinkedList myAnimalList = LinkedList(); + +void setup() +{ + + Serial.begin(9600); + Serial.println("Hello!" ); + + // Create a Cat + Animal *cat = new Animal(); + cat->name = catname; + cat->isMammal = true; + + // Create a dog + Animal *dog = new Animal(); + dog->name = dogname; + dog->isMammal = true; + + // Create a emu + Animal *emu = new Animal(); + emu->name = emuname; + emu->isMammal = false; // just an example; no offense to pig lovers + + // Add animals to list + myAnimalList.add(cat); + myAnimalList.add(emu); + myAnimalList.add(dog); +} + +void loop() { + + Serial.print("There are "); + Serial.print(myAnimalList.size()); + Serial.print(" animals in the list. The mammals are: "); + + int current = 0; + Animal *animal; + for(int i = 0; i < myAnimalList.size(); i++){ + + // Get animal from list + animal = myAnimalList.get(i); + + // If its a mammal, then print it's name + if(animal->isMammal){ + + // Avoid printing spacer on the first element + if(current++) + Serial.print(", "); + + // Print animal name + Serial.print(animal->name); + } + } + Serial.println("."); + + while (true); // nothing else to do, loop forever +} \ No newline at end of file diff --git a/lib/LinkedList/examples/LinkedListIterators/LinkedListIterators.ino b/lib/LinkedList/examples/LinkedListIterators/LinkedListIterators.ino new file mode 100644 index 0000000..399da5c --- /dev/null +++ b/lib/LinkedList/examples/LinkedListIterators/LinkedListIterators.ino @@ -0,0 +1,72 @@ +/* + LinkedList Iterators Example + Link: http://github.com/ivanseidel/LinkedList + + Example Created by + Emil Muratov, github.com/vortigont + +*/ +#include +#include + + +/* + An example on how to use STL compatible iterators to traverse LinkedList nodes + +*/ + + +LinkedList myList = LinkedList(); + +void setup() +{ + + Serial.begin(115200); + Serial.println("LinkedList STL compatible Iterators Example"); + + // Add some stuff to the list + int begin = 5, + cnt = 20; + + // fill the list with ascending integers + while (cnt--){ + myList.add(begin++); + } + + // let's print our list + Serial.print("myList: "); + for(const auto i : myList){ // const iterator by value + Serial.printf("%d ", i); + } + Serial.println(); + + // count Sum of all list members + int sum = 0; + for(const auto i : myList){ // const iterator by value + sum+=i; + } + + Serial.printf("myList iterated sum: %d\n", sum); + + // let's double odd elements in a list and zero out evens, + // do this right inplace, without retreive/save list elements + for (auto& i : myList) // mutable iterator by reference + i *= 2*(i%2); + + // let's print our new list + Serial.print("myList: "); + for(const auto& i : myList){ // const iterator by reference + Serial.printf("%d ", i); + } + + Serial.println(); +} + +void loop() { + + while (true){ + delay(100); + }; // nothing else to do, loop forever +} + + diff --git a/lib/LinkedList/examples/SimpleIntegerList/SimpleIntegerList.pde b/lib/LinkedList/examples/SimpleIntegerList/SimpleIntegerList.pde new file mode 100644 index 0000000..1bcbe9c --- /dev/null +++ b/lib/LinkedList/examples/SimpleIntegerList/SimpleIntegerList.pde @@ -0,0 +1,58 @@ +/* + LinkedList Example + Link: http://github.com/ivanseidel/LinkedList + + Example Created by + Tom Stewart, github.com/tastewar + + Edited by: + Ivan Seidel, github.com/ivanseidel +*/ +#include + +LinkedList myList = LinkedList(); + +void setup() +{ + + Serial.begin(9600); + Serial.println("Hello!"); + + // Add some stuff to the list + int k = -240, + l = 123, + m = -2, + n = 222; + myList.add(n); + myList.add(0); + myList.add(l); + myList.add(17); + myList.add(k); + myList.add(m); +} + +void loop() { + + int listSize = myList.size(); + + Serial.print("There are "); + Serial.print(listSize); + Serial.print(" integers in the list. The negative ones are: "); + + // Print Negative numbers + for (int h = 0; h < listSize; h++) { + + // Get value from list + int val = myList.get(h); + + // If the value is negative, print it + if (val < 0) { + Serial.print(" "); + Serial.print(val); + } + } + + while (true); // nothing else to do, loop forever +} + + diff --git a/lib/LinkedList/examples/Sort/Sort.ino b/lib/LinkedList/examples/Sort/Sort.ino new file mode 100644 index 0000000..43df279 --- /dev/null +++ b/lib/LinkedList/examples/Sort/Sort.ino @@ -0,0 +1,93 @@ +/* + LinkedList Example + Link: http://github.com/PaulMurrayCbr/LinkedList + Forked from: http://github.com/ivanseidel/LinkedList + + Example Created by + Paul Murray, github.com/PaulMurrayCbr +*/ + +#include + +char testString[] = "Lorem ipsum dolor sit amet, \ +consectetur adipiscing elit, sed do eiusmod tempor \ +incididunt ut labore et dolore magna aliqua. Ut enim \ +ad minim veniam, quis nostrud exercitation ullamco \ +laboris nisi ut aliquip ex ea commodo consequat. Duis \ +aute irure dolor in reprehenderit in voluptate velit \ +esse cillum dolore eu fugiat nulla pariatur. Excepteur \ +sint occaecat cupidatat non proident, sunt in culpa qui \ +officia deserunt mollit anim id est laborum."; + +LinkedList list; + +void setup() { + Serial.begin(9600); + while (!Serial); + + Serial.print("Beginning sketch in "); + for (int i = 3; i > 0; i--) { + Serial.print(i); + Serial.print(' '); + delay(500); + } + Serial.println("0."); + + Serial.println("Loading some strings into the linked list"); + Serial.println(); + + char *p; + int col = 0; + for (p = strtok(testString, " ,."); p; p = strtok(NULL, " ,.")) { + Serial.print(p); + Serial.print(' '); + col += strlen(p) + 1; + if (col >= 80) { + Serial.println(); + col = 0; + } + list.add(p); + } + + + if (col) { + Serial.println(); + col = 0; + } + + Serial.println(); + Serial.println("Sorting"); + Serial.println(); + + list.sort(compare); + + Serial.println(); + Serial.println("Result"); + Serial.println(); + + while (p = list.shift()) { + Serial.print(p); + Serial.print(' '); + col += strlen(p) + 1; + if (col >= 80) { + Serial.println(); + col = 0; + } + } + if (col) { + Serial.println(); + col = 0; + } + + Serial.println(); + Serial.println("Done!"); +} + +int compare(char *&a, char *&b) { + return strcmp(a, b); +} + +void loop() { + // put your main code here, to run repeatedly: + +} diff --git a/lib/LinkedList/keywords.txt b/lib/LinkedList/keywords.txt new file mode 100644 index 0000000..3ae4968 --- /dev/null +++ b/lib/LinkedList/keywords.txt @@ -0,0 +1,28 @@ +####################################### +# Syntax Coloring +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +LinkedList KEYWORD1 +ListNode KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +size KEYWORD2 +add KEYWORD2 +unshift KEYWORD2 +set KEYWORD2 +remove KEYWORD2 +pop KEYWORD2 +shift KEYWORD2 +get KEYWORD2 +clear KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/lib/LinkedList/library.json b/lib/LinkedList/library.json new file mode 100644 index 0000000..0ce0b18 --- /dev/null +++ b/lib/LinkedList/library.json @@ -0,0 +1,33 @@ +{ + "name": "LinkedList", + "keywords": "llist, linkedlist", + "description": "Forked ivanseidel's LinkedList - A fully implemented LinkedList (int, float, objects, Lists or Wales) made to work with Arduino projects", + "url": "https://github.com/vortigont/LinkedList", + "authors": [ + { + "name": "Ivan Seidel", + "url": "https://github.com/ivanseidel" + }, + { + "name": "Emil Muratov", + "url": "https://github.com/vortigont", + "email": "gpm@hotplug.ru", + "maintainer": true + } + ], + "license": "MIT", + "repository": + { + "type": "git", + "url": "https://github.com/vortigont/LinkedList.git" + }, + "frameworks": "*", + "platforms": "*", + "version": "1.5.0", + "build": { + "srcFilter": [ + "+", + "+" + ] + } +} diff --git a/lib/LinkedList/library.properties b/lib/LinkedList/library.properties new file mode 100644 index 0000000..71bd873 --- /dev/null +++ b/lib/LinkedList/library.properties @@ -0,0 +1,9 @@ +name=LinkedList +version=1.5.0 +author=Ivan Seidel +maintainer=Emil Muratov +sentence=Forked ivanseidel's LinkedList - A fully implemented LinkedList made to work with Arduino projects +paragraph=The objective of this library is to create a pattern for projects. If you need to use a List of: int, float, objects, Lists or Wales. This is what you are looking for. +category=Data Processing +url=https://github.com/vortigont/LinkedList +architectures=* diff --git a/lib/duktape-2.7.0/src/duktape.c b/lib/duktape-2.7.0/src/duktape.c index 573e70c..9673080 100644 --- a/lib/duktape-2.7.0/src/duktape.c +++ b/lib/duktape-2.7.0/src/duktape.c @@ -44764,6 +44764,7 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_hthread *ctx) { state_error: DUK_DCERROR_TYPE_INVALID_STATE(thr); + return 0; } #endif @@ -44881,6 +44882,7 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_yield(duk_hthread *thr) { state_error: DUK_DCERROR_TYPE_INVALID_STATE(thr); + return 0; } #endif diff --git a/library.json b/library.json index 656a0ef..87f2aa3 100644 --- a/library.json +++ b/library.json @@ -1,7 +1,7 @@ { "name": "HomeGenie", - "description": "Library for creating easily smart devices based on ESP32 or ESP8266 chip.", - "keywords": "iot,esp32,esp8266,mqtt,sse,http,websocket,homegenie,smarthome,", + "description": "Library for creating easily smart devices based on ESP32 or ESP8266.", + "keywords": "esp32,esp8266,mqtt,sse,http,websocket,homegenie,smart device", "authors": { "name": "genielabs", "url": "https://github.com/genielabs", @@ -18,4 +18,4 @@ "build": { "libArchive": false } -} \ No newline at end of file +} diff --git a/platformio.ini b/platformio.ini index a120123..f8459e4 100644 --- a/platformio.ini +++ b/platformio.ini @@ -13,7 +13,20 @@ include_dir = ./src data_dir = ./data/web [env] -platform = espressif32@6.8.1 +# Official PlatformIO espressif32 and Arduino 2.x +platform = espressif32@6.9.0 +# +# Official PlatformIO espressif32 and Arduino 3.x +# but only supports ESP32, ESP32-S2, ESP32-C3 and ESP32-S3 +#platform = espressif32@6.9.0 +#platform_packages = +# framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.5 +# framework-arduinoespressif32-libs @ https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.1/esp32-arduino-libs-idf-release_v5.1-33fbade6.zip +# +# UNOFFICIAL Espressif32 and Arduino 3.x +# should support also latest ESP32 boards (not verified) +#platform = https://github.com/pioarduino/platform-espressif32/releases/download/51.03.05/platform-espressif32.zip +# build_src_filter = -<*> + build_flags = -D CRON_USE_LOCAL_TIME -D CRON_DISABLE_YEARS -Os -D BUILD_ENV_NAME=\"$PIOENV\" build_unflags = -fno-exceptions @@ -29,11 +42,10 @@ lib_deps = ArduinoJson@7.0.4 thijse/ArduinoLog@1.1.1 WebSockets@2.4.1 - vortigont/LinkedList@1.5.0 hideakitai/MsgPack@0.4.2 adafruit/TINYXML@1.0.3 ESP32Time@2.0.6 - lovyan03/LovyanGFX@1.1.12 + lovyan03/LovyanGFX@1.1.16 dvarrel/ESPping@1.0.4 jpb10/SolarCalculator@2.0.1 lib_deps_8266 = @@ -91,7 +103,22 @@ lib_ignore = board = esp32-c3-devkitc-02 #board = esp32-c3-devkitm-1 build_flags = ${env.build_flags} -I examples -I src -D ESP32_C3 -D DISABLE_UI -D ARDUINO_USB_MODE=1 -D ARDUINO_USB_CDC_ON_BOOT=1 - -D DEFAULT_CONFIG='{"sys-rb-n":"0","sys-sl-n":"-1","io-typ01":"Dimmer","io-pin01":"4","io-typ02":"Dimmer","io-pin02":"5","sdht-typ":"22","sdht-pin":"7","motn-typ":"switch","motn-pin":"6"}' + -D DEFAULT_CONFIG='{"sys-rb-n":"9","sys-sl-n":"-1","stld-typ":"82","stld-spd":"0","stld-pin":"10","io-typ01":"Dimmer","io-pin01":"4","io-typ02":"Dimmer","io-pin02":"5","sdht-typ":"22","sdht-pin":"7","motn-typ":"switch","motn-pin":"6"}' +build_src_filter = + - + +lib_deps = ${env.lib_deps} + RobTillaart/DHTNew@0.4.19 + OneWire@2.3.8 +lib_ignore = + LovyanGFX + +[env:smart-sensor-s3] +board = esp32-s3-fh4r2 +#board = esp32-s3-devkitc-1 +#board = esp32-s3-devkitm-1 +#board = lolin_s3_mini +build_flags = ${env.build_flags} -I examples -I src -D ESP32_S3 -D DISABLE_UI + -D BOARD_HAS_PSRAM -D ARDUINO_USB_MODE=1 -D ARDUINO_USB_CDC_ON_BOOT=1 + -D DEFAULT_CONFIG='{"sys-rb-n":"0","sys-sl-n":"-1","stld-typ":"82","stld-spd":"0","stld-pin":"21","io-typ01":"Dimmer","io-pin01":"5","io-typ02":"Dimmer","io-pin02":"6","sdht-typ":"22","sdht-pin":"8","motn-typ":"switch","motn-pin":"7"}' build_src_filter = + - + lib_deps = ${env.lib_deps} RobTillaart/DHTNew@0.4.19 @@ -101,7 +128,8 @@ lib_ignore = [env:smart-sensor-s2-mini] board = lolin_s2_mini -build_flags = ${env.build_flags} -I examples -I src -D ESP32_S2 -D DISABLE_UI -D BOARD_HAS_PSRAM +build_flags = ${env.build_flags} -I examples -I src -D ESP32_S2 -D DISABLE_UI + -D BOARD_HAS_PSRAM -D DEFAULT_CONFIG='{"sys-rb-n":"0","sys-sl-n":"15","io-typ01":"Dimmer","io-pin01":"4","io-typ02":"Dimmer","io-pin02":"5","sdht-typ":"22","sdht-pin":"7","motn-typ":"switch","motn-pin":"6"}' build_src_filter = + - + lib_deps = ${env.lib_deps} @@ -262,7 +290,7 @@ board = esp32-c3-devkitc-02 #board = esp32-c3-devkitm-1 build_flags = ${env.build_flags} -I examples -I src -D ESP32_C3 -D DISABLE_UI -D ARDUINO_USB_MODE=1 -D ARDUINO_USB_CDC_ON_BOOT=1 - -D DEFAULT_CONFIG='{"sys-rb-n":"0","sys-sl-n":"-1","leds-typ":"6","leds-cnt":"25","leds-spd":"0","leds-pin":"8"}' + -D DEFAULT_CONFIG='{"sys-rb-n":"9","sys-sl-n":"-1","stld-typ":"82","stld-spd":"0","stld-pin":"10","leds-typ":"82","leds-spd":"0","leds-pin":"5","leds-cnt":"1"}' build_src_filter = + - + lib_deps = ${env.lib_deps} https://github.com/adafruit/Adafruit_NeoPixel#1.12.0 @@ -274,7 +302,7 @@ board = esp32-s3-fh4r2 #board = lolin_s3_mini build_flags = ${env.build_flags} -I examples -I src -D ESP32_S3 -D DISABLE_UI -D BOARD_HAS_PSRAM -D ARDUINO_USB_MODE=1 -D ARDUINO_USB_CDC_ON_BOOT=1 - -D DEFAULT_CONFIG='{"sys-rb-n":"0","sys-sl-n":"-1","leds-typ":"6","leds-cnt":"144","leds-spd":"0","leds-pin":"6"}' + -D DEFAULT_CONFIG='{"sys-rb-n":"0","sys-sl-n":"-1","stld-typ":"82","stld-spd":"0","stld-pin":"21","leds-typ":"82","leds-spd":"0","leds-pin":"6","leds-cnt":"1"}' build_src_filter = + - + lib_deps = ${env.lib_deps} https://github.com/adafruit/Adafruit_NeoPixel#1.12.0 @@ -283,7 +311,7 @@ lib_deps = ${env.lib_deps} board = lolin_s2_mini build_flags = ${env.build_flags} -I examples -I src -D ESP32_S2 -D BOARD_HAS_PSRAM - -D DEFAULT_CONFIG='{"sys-rb-n":"0","sys-sl-n":"15","leds-typ":"6","leds-cnt":"64","leds-spd":"0","leds-pin":"8"}' + -D DEFAULT_CONFIG='{"sys-rb-n":"0","sys-sl-n":"15","leds-typ":"82","leds-spd":"0","leds-pin":"8","leds-cnt":"0"}' build_src_filter = + - + lib_deps = ${env.lib_deps} https://github.com/adafruit/Adafruit_NeoPixel#1.12.0 diff --git a/src/Config.h b/src/Config.h index 33605c3..0030245 100644 --- a/src/Config.h +++ b/src/Config.h @@ -59,6 +59,7 @@ const static char CONFIG_KEY_wifi_ssid[] = {"wifi:ssid"}; const static char CONFIG_KEY_wifi_password[] = {"wifi:password"}; const static char CONFIG_KEY_device_name[] = {"device:name"}; +const static char CONFIG_KEY_device_group[] = {"device:group"}; const static char CONFIG_KEY_system_mode[] = {"system:mode"}; const static char CONFIG_KEY_system_zone_id[] = {"system:zn_id"}; const static char CONFIG_KEY_system_zone_description[] = {"system:zn_dsc"}; @@ -88,11 +89,13 @@ class ZoneConfig { class SystemConfig { public: + String id; String friendlyName; String systemMode; String ssid, pass; SystemConfig() { + id = ""; friendlyName = CONFIG_BUILTIN_MODULE_NAME; systemMode = ""; ssid = ""; diff --git a/src/HomeGenie.cpp b/src/HomeGenie.cpp index d7c6488..749949c 100644 --- a/src/HomeGenie.cpp +++ b/src/HomeGenie.cpp @@ -295,14 +295,7 @@ namespace Service { unsigned int HomeGenie::writeGroupListJSON(ResponseCallback *responseCallback) { bool firstModule = true; - String defaultGroupName = "Dashboard"; - Preferences preferences; - preferences.begin(CONFIG_SYSTEM_NAME, true); - String deviceName = preferences.getString(CONFIG_KEY_device_name, ""); - preferences.end(); - if (deviceName.length() > 0) { - defaultGroupName = deviceName; - } + String defaultGroupName = Config::getSetting(CONFIG_KEY_device_group, "Dashboard"); String out = R"([{"Name": ")" + defaultGroupName + R"(", "Modules": [)"; responseCallback->write(out.c_str()); for (int i = 0; i < handlers.size(); i++) { diff --git a/src/HomeGenie.h b/src/HomeGenie.h index fbc6cc4..0a162e1 100644 --- a/src/HomeGenie.h +++ b/src/HomeGenie.h @@ -151,10 +151,11 @@ namespace Service { volatile int64_t buttonPressStart = 0; volatile bool buttonPressed = false; static void buttonChange() { - bool wasPressed = getInstance()->buttonPressed; - getInstance()->buttonPressed = (digitalRead(Config::ServiceButtonPin) == LOW); - if (!wasPressed && getInstance()->buttonPressed) { - getInstance()->buttonPressStart = millis(); + auto hg = getInstance(); + bool wasPressed = hg->buttonPressed; + hg->buttonPressed = (digitalRead(Config::ServiceButtonPin) == LOW); + if (!wasPressed && hg->buttonPressed) { + hg->buttonPressStart = millis(); } } static void checkServiceButton() { @@ -163,11 +164,12 @@ namespace Service { } buttonChange(); int64_t elapsed = 0; - if (getInstance()->buttonPressed) { + auto hg = getInstance(); + if (hg->buttonPressed) { // released - elapsed = millis() - getInstance()->buttonPressStart; + elapsed = millis() - hg->buttonPressStart; if (elapsed > Config::ConfigureButtonPushInterval) { - getInstance()->getNetManager().getWiFiManager().configure(); + hg->getNetManager().getWiFiManager().configure(); } } } diff --git a/src/automation/ScheduledScript.h b/src/automation/ScheduledScript.h index 51f8ad7..0032a21 100644 --- a/src/automation/ScheduledScript.h +++ b/src/automation/ScheduledScript.h @@ -34,7 +34,7 @@ #ifndef DISABLE_AUTOMATION -#include +#include /* * diff --git a/src/automation/Scheduler.h b/src/automation/Scheduler.h index 55f6ba2..8c7d842 100644 --- a/src/automation/Scheduler.h +++ b/src/automation/Scheduler.h @@ -75,7 +75,7 @@ namespace Automation { bool occurs(time_t ts) { return ExtendedCron::IsScheduling(ts, cronExpression); } - bool wasScheduled(time_t ts) { + bool wasScheduled(time_t ts) const { return ExtendedCron::normalizeStartTime(lastOccurrence) == ExtendedCron::normalizeStartTime(ts); } void setScheduled(time_t ts) { @@ -121,6 +121,9 @@ namespace Automation { static String getJsonList(); private: static LinkedList scheduleList; + // TODO: add LinkedList runtimeEventList; ( RuntimeEvent => {key/value} ) + // - registerRuntimeEvent(const char* key, const char* description, ..) + // - handleRuntimeEvent(const char* key, const char* value, ..) static SchedulerListener* listener; static int lastCheckMinute; }; diff --git a/src/defs.h b/src/defs.h index 6e03229..7cf29b6 100644 --- a/src/defs.h +++ b/src/defs.h @@ -65,7 +65,7 @@ #define FILE_WRITE "w" #define FILE_APPEND "a" #else - #define ESP_WIFI_STATUS WiFiClass::status() + #define ESP_WIFI_STATUS WiFi.status() #endif #ifdef ESP8266 diff --git a/src/net/BluetoothManager.h b/src/net/BluetoothManager.h index 2a4edd1..acd35fe 100644 --- a/src/net/BluetoothManager.h +++ b/src/net/BluetoothManager.h @@ -38,7 +38,7 @@ #include #ifndef DISABLE_BLUETOOTH_LE -#include "lib/ESP32_BleSerial/src/BleSerial.h" +#include #endif #ifndef DISABLE_BLUETOOTH_CLASSIC diff --git a/src/net/HTTPServer.cpp b/src/net/HTTPServer.cpp index 960d51b..6f09d97 100644 --- a/src/net/HTTPServer.cpp +++ b/src/net/HTTPServer.cpp @@ -103,10 +103,12 @@ namespace Net { SSDPDevice.setManufacturer(FPSTR(SSDP_Manufacturer)); SSDPDevice.setManufacturerURL(FPSTR(SSDP_ManufacturerURL)); + Config::system.id = SSDPDevice.getId(); + Logger::info("| ✔ SSDP service"); + //Logger::info("| ✔ SSDP service id: ", Config::system.id.c_str()); + SSDPDevice.setFriendlyName(Config::system.friendlyName); Logger::info("| ✔ UPnP friendly name: %s", Config::system.friendlyName.c_str()); - - Logger::info("| ✔ SSDP service"); } httpServer.handleClient(); @@ -135,11 +137,19 @@ namespace Net { #ifndef DISABLE_SSE // BEGIN RequestHandler interface methods +#if ESP_ARDUINO_VERSION_MAJOR > 2 + bool HTTPServer::canHandle(HTTPMethod method, const String& uri) { +#else bool HTTPServer::canHandle(HTTPMethod method, String uri) { +#endif return false; } +#if ESP_ARDUINO_VERSION_MAJOR > 2 + bool HTTPServer::handle(WebServer& server, HTTPMethod requestMethod, const String& requestUri) { +#else bool HTTPServer::handle(WebServer& server, HTTPMethod requestMethod, String requestUri) { +#endif return false; } // END RequestHandler interface methods diff --git a/src/net/HTTPServer.h b/src/net/HTTPServer.h index 4d63b63..8a4e3b2 100644 --- a/src/net/HTTPServer.h +++ b/src/net/HTTPServer.h @@ -36,6 +36,7 @@ #else #include #endif +#include #include #include @@ -57,8 +58,13 @@ namespace Net { static void addHandler(RequestHandler* handler); #ifndef DISABLE_SSE // RequestHandler interface methods +#if ESP_ARDUINO_VERSION_MAJOR > 2 + bool canHandle(HTTPMethod method, const String& uri) override; + bool handle(WebServer& server, HTTPMethod requestMethod, const String& requestUri) override; +#else bool canHandle(HTTPMethod method, String uri) override; bool handle(WebServer& server, HTTPMethod requestMethod, String requestUri) override; +#endif void sendSSEvent(String domain, String address, String event, String value); #endif private: diff --git a/src/net/NetManager.h b/src/net/NetManager.h index 1b599dc..089ecdd 100644 --- a/src/net/NetManager.h +++ b/src/net/NetManager.h @@ -240,20 +240,29 @@ namespace Net { // BEGIN HTTP RequestHandler interface methods +#if ESP_ARDUINO_VERSION_MAJOR > 2 + bool canHandle(HTTPMethod method, const String& uri) override { +#else bool canHandle(HTTPMethod method, String uri) override { +#endif return uri != nullptr && uri.startsWith("/api/"); } +#if ESP_ARDUINO_VERSION_MAJOR > 2 + bool handle(WebServer &server, HTTPMethod requestMethod, const String& requestUri) override { +#else bool handle(WebServer &server, HTTPMethod requestMethod, String requestUri) override { +#endif // append POST data to requestUri + String uri = requestUri; for (int a = 0; a < server.args(); a++) { if (server.argName(a).length() > 0) { - requestUri += String("/") + server.argName(a); + uri += String("/") + server.argName(a); } - requestUri += String ("/") + server.arg(a); + uri += String ("/") + server.arg(a); } // create response callback auto responseCallback = new WebServerResponseCallback(&server); - if (!netRequestHandler->onNetRequest(&server, requestUri.c_str(), responseCallback)) { + if (!netRequestHandler->onNetRequest(&server, uri.c_str(), responseCallback)) { responseCallback->error("Invalid request."); }; delete responseCallback; diff --git a/src/net/SSDPDevice.cpp b/src/net/SSDPDevice.cpp index 41b4b24..fbbb4eb 100644 --- a/src/net/SSDPDevice.cpp +++ b/src/net/SSDPDevice.cpp @@ -407,6 +407,10 @@ void SSDPDeviceClass::handleClient() { } } +String SSDPDeviceClass::getId() { + return {m_uuid}; +} + void SSDPDeviceClass::setSchemaURL(const char *url) { strlcpy(m_schemaURL, url, sizeof(m_schemaURL)); } diff --git a/src/net/SSDPDevice.h b/src/net/SSDPDevice.h index 900da6a..24e44c1 100644 --- a/src/net/SSDPDevice.h +++ b/src/net/SSDPDevice.h @@ -116,6 +116,8 @@ class SSDPDeviceClass { void handleClient(); + String getId(); + void setDeviceType(const String& deviceType) { setDeviceType(deviceType.c_str()); } void setDeviceType(const char *deviceType); void setName(const String& name) { setName(name.c_str()); } diff --git a/src/net/WiFiManager.cpp b/src/net/WiFiManager.cpp index cae265a..2e92a8e 100644 --- a/src/net/WiFiManager.cpp +++ b/src/net/WiFiManager.cpp @@ -40,7 +40,13 @@ namespace Net { WiFiManager::WiFiManager() { setLoopInterval(1000); +#ifdef ESP8266 WiFi.mode(WIFI_STA); + //WiFi.setOutputPower(20.5); +#else + WiFiClass::mode(WIFI_STA); + //WiFi.setTxPower(WIFI_POWER_19_5dBm); +#endif WiFi.setAutoReconnect(true); #ifdef CONFIGURE_WITH_WPS @@ -86,7 +92,7 @@ namespace Net { if (err == ESP_OK) { WiFi.begin((char *) config.sta.ssid, (char *) config.sta.password); } else { - // TODO: printf("Couldn't get config: %d\n", (int) err); + // TODO: Serial.printf("Couldn't get config: %d\n", (int) err); } #endif } else if (!Config::system.ssid.isEmpty() && !Config::system.pass.isEmpty()) { @@ -133,6 +139,8 @@ namespace Net { IO::Logger::error("| x Not connected to WiFi (state='%d')", status); break; case WL_IDLE_STATUS: + IO::Logger::error("| x WiFi idle (?)"); + connect(); break; } } @@ -167,7 +175,7 @@ namespace Net { #ifdef ESP8266 return WiFi.beginWPSConfig(); #else - int timeout = 200; + int timeout = 400; bool success = wpsStart(); while (esp32_wps_started && timeout-- > 0) { delay(100); diff --git a/src/net/WiFiManager.h b/src/net/WiFiManager.h index 128b71a..92ba219 100644 --- a/src/net/WiFiManager.h +++ b/src/net/WiFiManager.h @@ -99,7 +99,20 @@ namespace Net { */ } -#ifdef ESP32 +#ifdef ESP8266 + // WPS events handling + static void WiFiEvent(WiFiEvent_t event) { + switch(event) { + case WIFI_EVENT_STAMODE_GOT_IP: + case WIFI_EVENT_STAMODE_DISCONNECTED: + case WIFI_EVENT_STAMODE_CONNECTED: + break; + case WIFI_EVENT_STAMODE_AUTHMODE_CHANGE: + setWiFiConfigured(); + break; + } + } +#else // ESP32 static esp_wps_config_t wps_config; static bool esp32_wps_started; static bool wpsStart() { @@ -142,20 +155,7 @@ namespace Net { break; } } -#else - // WPS events handling - static void WiFiEvent(WiFiEvent_t event) { - switch(event) { - case WIFI_EVENT_STAMODE_GOT_IP: - case WIFI_EVENT_STAMODE_DISCONNECTED: - case WIFI_EVENT_STAMODE_CONNECTED: - break; - case WIFI_EVENT_STAMODE_AUTHMODE_CHANGE: - setWiFiConfigured(); - break; - } - } -#endif // ESP32 +#endif #endif // CONFIGURE_WITH_WPS }; diff --git a/src/service/api/APIHandler.h b/src/service/api/APIHandler.h index 3eef7e1..4feb342 100644 --- a/src/service/api/APIHandler.h +++ b/src/service/api/APIHandler.h @@ -45,6 +45,7 @@ namespace Service { namespace API { namespace ApiHandlerResponseStatus { static const char* OK = R"({ "ResponseStatus": "OK", Message: "" })"; + static const char* ERROR = R"({ "ResponseStatus": "ERROR", Message: "" })"; } namespace ApiHandlerResponseText { static const char* OK = R"({ "ResponseText": "OK" })"; diff --git a/src/service/api/APIRequest.h b/src/service/api/APIRequest.h index 6e1bfa6..ed79eff 100644 --- a/src/service/api/APIRequest.h +++ b/src/service/api/APIRequest.h @@ -75,6 +75,7 @@ namespace Service { namespace API { static const char Location_Get[] = {"Location.Get"}; static const char Location_Set[] = {"Location.Set"}; static const char System_Info[] = {"System.Info"}; + static const char System_DataSet[] = {"System.DataSet"}; static const char System_TimeSet[] = {"System.TimeSet"}; } } diff --git a/src/service/api/HomeGenieHandler.cpp b/src/service/api/HomeGenieHandler.cpp index 03f561a..fcd11e6 100644 --- a/src/service/api/HomeGenieHandler.cpp +++ b/src/service/api/HomeGenieHandler.cpp @@ -40,7 +40,6 @@ namespace Service { namespace API { miniModule->type = "Sensor"; miniModule->name = CONFIG_BUILTIN_MODULE_NAME; miniModule->description = "HomeGenie Mini node"; - miniModule->properties.add(new ModuleParameter("Widget.OptionField.System.LocationInfo", "location.info:map-picker")); moduleList.add(miniModule); } @@ -353,6 +352,39 @@ namespace Service { namespace API { return true; } } + } else if (method == ConfigApi::SystemApi::System_DataSet) { + JsonDocument doc; + DeserializationError error = deserializeJson(doc, request->Data); + + if (!error.code()) { + int operationsCount = 0; + if (doc.containsKey("name")) { + String deviceName = doc["name"].as(); + if (deviceName.isEmpty()) { + responseCallback->writeAll(HomeGenieHandlerResponseStatus::ERROR_INVALID_NAME); + return true; + } else { + Config::system.friendlyName = deviceName; + Config::saveSetting(CONFIG_KEY_device_name, deviceName); + } + } + if (doc.containsKey("group")) { + String deviceGroup = doc["group"].as(); + if (deviceGroup.isEmpty()) { + responseCallback->writeAll(HomeGenieHandlerResponseStatus::ERROR_INVALID_NAME); + return true; + } else { + Config::saveSetting(CONFIG_KEY_device_group, deviceGroup); + operationsCount++; + } + } + if (operationsCount > 0) { + responseCallback->writeAll(ApiHandlerResponseText::OK); + } else { + responseCallback->writeAll(ApiHandlerResponseStatus::ERROR); + } + return true; + } #ifndef ESP8266 } else if (method == ConfigApi::SystemApi::System_TimeSet) { @@ -374,6 +406,8 @@ namespace Service { namespace API { obj["Release"]["Name"] = CONFIG_DEVICE_MODEL_NAME; obj["Release"]["Version"] = CONFIG_DEVICE_MODEL_NUMBER; obj["Release"]["ReleaseDate"] = ReleaseBuildDate; + obj["Id"] = Config::system.id; + obj["Name"] = Config::system.friendlyName; #ifdef ESP8266 obj["Release"]["Runtime"] = "esp8266"; obj["Platform"] = "espressif8266"; @@ -388,6 +422,9 @@ namespace Service { namespace API { obj["UtcOffset"] = Config::zone.offset; obj["LocalTime"] = homeGenie->getNetManager().getTimeClient().getFormattedDate(); obj["Configuration"] = doc.add(); + // Default group name + String defaultGroupName = Config::getSetting(CONFIG_KEY_device_group, "Dashboard"); + obj["Configuration"]["Group"] = defaultGroupName; // Location info obj["Configuration"]["Location"] = doc.add(); obj["Configuration"]["Location"]["name"] = Config::zone.name; diff --git a/src/service/api/HomeGenieHandler.h b/src/service/api/HomeGenieHandler.h index f25df6e..e08b436 100644 --- a/src/service/api/HomeGenieHandler.h +++ b/src/service/api/HomeGenieHandler.h @@ -37,6 +37,7 @@ namespace Service { namespace API { using namespace IO::GPIO; namespace HomeGenieHandlerResponseStatus { + static const char* ERROR_INVALID_NAME = R"({ "ResponseStatus": "ERROR", "ResponseMessage": "Invalid name" })"; static const char* ERROR_NO_SCHEDULE_WITH_THE_GIVEN_NAME = R"({ "ResponseStatus": "ERROR", "ResponseMessage": "No schedule with the given name" })"; }