diff --git a/examples/color-light/color-light.cpp b/examples/color-light/color-light.cpp index 89967a2..465e789 100644 --- a/examples/color-light/color-light.cpp +++ b/examples/color-light/color-light.cpp @@ -45,6 +45,7 @@ Adafruit_NeoPixel pixels(num, pin, NEO_RGB + NEO_KHZ800); #endif bool changed = false; +unsigned long lastRefreshTs = 0; void statusLedCallback(bool isLedOn) { if (isLedOn) { @@ -56,8 +57,6 @@ void statusLedCallback(bool isLedOn) { } void setup() { - statusLED.begin(); - homeGenie = HomeGenie::getInstance(); if (!Config::isDeviceConfigured()) { @@ -76,6 +75,14 @@ void setup() { } #endif changed = true; + if (millis() - lastRefreshTs > 50) { // force 20fps max + statusLED.show(); +#ifdef LED_ARRAY_COUNT + pixels.show(); +#endif + lastRefreshTs = millis(); + changed = false; + } }); homeGenie->addAPIHandler(colorLight); @@ -86,6 +93,11 @@ void setup() { cl->onSetColor([i](float r, float g, float b) { pixels.setPixelColor(i, r, g, b); changed = true; + if (millis() - lastRefreshTs > 50) { // force 20fps max + pixels.show(); + lastRefreshTs = millis(); + changed = false; + } }); homeGenie->addAPIHandler(cl); } @@ -97,21 +109,19 @@ void setup() { } + statusLED.begin(); homeGenie->begin(); } -unsigned long ts = 0; - void loop() { homeGenie->loop(); - - if (changed) { //&& millis()-ts > 50) { // force 20fps max + if (changed) { // trailing fx changed = false; statusLED.show(); #ifdef LED_ARRAY_COUNT pixels.show(); #endif - ts = millis(); + lastRefreshTs = millis(); } } diff --git a/lib/ESP32_BleSerial/src/BleSerial.cpp b/lib/ESP32_BleSerial/src/BleSerial.cpp index 9c8e78d..e087ea5 100644 --- a/lib/ESP32_BleSerial/src/BleSerial.cpp +++ b/lib/ESP32_BleSerial/src/BleSerial.cpp @@ -1,21 +1,19 @@ #include "BleSerial.h" using namespace std; -bool BleSerial::connected() +bool BleSerial::connected() const { return Server->getConnectedCount() > 0; } void BleSerial::onConnect(BLEServer *pServer) { - bleConnected = true; if (enableLed) digitalWrite(ledPin, HIGH); } void BleSerial::onDisconnect(BLEServer *pServer) { - bleConnected = false; if (enableLed) digitalWrite(ledPin, LOW); Server->startAdvertising(); @@ -125,7 +123,6 @@ void BleSerial::flush() TxCharacteristic->setValue(this->transmitBuffer, this->transmitBufferLength); this->transmitBufferLength = 0; } - this->lastFlushTime = millis(); TxCharacteristic->notify(true); } @@ -139,7 +136,6 @@ void BleSerial::begin(const char *name, bool enable_led, int led_pin) pinMode(ledPin, OUTPUT); } - ConnectedDeviceCount = 0; BLEDevice::init(name); Server = BLEDevice::createServer(); @@ -193,7 +189,3 @@ void BleSerial::SetupSerialService() RxCharacteristic->setCallbacks(this); SerialService->start(); } - -BleSerial::BleSerial() -{ -} diff --git a/lib/ESP32_BleSerial/src/BleSerial.h b/lib/ESP32_BleSerial/src/BleSerial.h index 1626d1f..1974db7 100644 --- a/lib/ESP32_BleSerial/src/BleSerial.h +++ b/lib/ESP32_BleSerial/src/BleSerial.h @@ -2,8 +2,6 @@ #include #include -//#include -//#include #include #include "ByteRingBuffer.h" @@ -15,23 +13,25 @@ class BleSerial : public BLECharacteristicCallbacks, public BLEServerCallbacks, public Stream { public: - BleSerial(); + BleSerial() = default; + BleSerial(BleSerial const &other) = delete; // disable copy constructor + void operator=(BleSerial const &other) = delete; // disable assign constructor void begin(const char *name, bool enable_led = false, int led_pin = 13); - void end(); - void onWrite(BLECharacteristic *pCharacteristic); - int available(); - int read(); - size_t readBytes(uint8_t *buffer, size_t bufferSize); - int peek(); - size_t write(uint8_t byte); - void flush(); - size_t write(const uint8_t *buffer, size_t bufferSize); + static void end(); + void onWrite(BLECharacteristic *pCharacteristic) override; + int available() override; + int read() override; + size_t readBytes(uint8_t *buffer, size_t bufferSize) override; + int peek() override; + size_t write(uint8_t byte) override; + void flush() override; + size_t write(const uint8_t *buffer, size_t bufferSize) override; size_t print(const char *value); - void onConnect(BLEServer *pServer); - void onDisconnect(BLEServer *pServer); + void onConnect(BLEServer *pServer) override; + void onDisconnect(BLEServer *pServer) override; - bool connected(); + bool connected() const; BLEServer *Server; @@ -49,25 +49,19 @@ class BleSerial : public BLECharacteristicCallbacks, public BLEServerCallbacks, int ledPin = 13; protected: size_t transmitBufferLength; - bool bleConnected; private: - BleSerial(BleSerial const &other) = delete; // disable copy constructor - void operator=(BleSerial const &other) = delete; // disable assign constructor ByteRingBuffer receiveBuffer; size_t numAvailableLines; - unsigned long long lastFlushTime; uint8_t transmitBuffer[BLE_BUFFER_SIZE]; - int ConnectedDeviceCount; void SetupSerialService(); uint16_t peerMTU; uint16_t maxTransferSize = BLE_BUFFER_SIZE; - bool checkMTU(); /* Bluetooth LE GATT UUIDs for the Nordic UART profile Change UUID here if required diff --git a/lib/NTPClient-master/NTPClient.cpp b/lib/NTPClient-master/NTPClient.cpp index 022b378..27ff94d 100644 --- a/lib/NTPClient-master/NTPClient.cpp +++ b/lib/NTPClient-master/NTPClient.cpp @@ -92,24 +92,30 @@ bool NTPClient::forceUpdate() { this->sendNTPPacket(); // Wait till data is there or timeout... - byte timeout = 0; + unsigned int startCheckMs = millis(); int cb = 0; do { - delay ( 10 ); + cb = this->_udp->parsePacket(); - if(cb > 0) { this->_udp->read(this->_packetBuffer, NTP_PACKET_SIZE); if(!this->isValid(this->_packetBuffer)) cb = 0; } - - if (timeout > 100) return false; // timeout after 1000 ms - timeout++; + if (cb == 0) { + if (millis() - startCheckMs > 1000) { + // timeout after 1000 ms + return false; + } + unsigned int delayStartMs = millis(); + while (millis() - delayStartMs < 50) { + yield(); + } + } } while (cb == 0); - this->_lastUpdate = millis() - (10 * (timeout + 1)); // Account for delay in reading the time + this->_lastUpdate = millis(); unsigned long highWord = word(this->_packetBuffer[40], this->_packetBuffer[41]); unsigned long lowWord = word(this->_packetBuffer[42], this->_packetBuffer[43]); diff --git a/lib/duktape-2.7.0/src/duk_config.h b/lib/duktape-2.7.0/src/duk_config.h index 1710372..13213ef 100644 --- a/lib/duktape-2.7.0/src/duk_config.h +++ b/lib/duktape-2.7.0/src/duk_config.h @@ -3085,7 +3085,7 @@ typedef struct duk_hthread duk_context; #define DUK_USE_VALSTACK_LIMIT 1000000L #define DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT 2 #define DUK_USE_VALSTACK_SHRINK_SLACK_SHIFT 4 -#undef DUK_USE_VALSTACK_UNSAFE +//#define DUK_USE_VALSTACK_UNSAFE //#define DUK_USE_VERBOSE_ERRORS //#define DUK_USE_VERBOSE_EXECUTOR_ERRORS //#define DUK_USE_VOLUNTARY_GC diff --git a/platformio.ini b/platformio.ini index 798eed6..9d943f8 100644 --- a/platformio.ini +++ b/platformio.ini @@ -20,7 +20,7 @@ framework = arduino board = esp32dev board_build.filesystem = littlefs board_build.flash_size = 4MB -board_build.partitions = ./src/partitions_ota.csv +board_build.partitions = ./src/partitions.csv lib_deps = ArduinoJson@7.0.4 thijse/ArduinoLog@1.1.1 @@ -29,7 +29,8 @@ lib_deps = hideakitai/MsgPack@0.4.2 adafruit/TINYXML@1.0.3 ESP32Time@2.0.4 - lovyan03/LovyanGFX@^1.1.12 + lovyan03/LovyanGFX@1.1.12 + dvarrel/ESPping@1.0.4 [env:default] @@ -53,7 +54,7 @@ build_flags = ${env.build_flags} -D MINI_ESP32 -D CONFIG_ServiceButtonPin=16 -D [env:sonoff] platform = espressif32@6.6.0 build_flags = ${env.build_flags} -D DISABLE_UI -D CONFIG_ServiceButtonPin=0 -D CONFIG_StatusLedPin=13 -D CONFIG_GPIO_OUT={14,27} -D CONFIG_GPIO_IN={32,33} - +board_build.partitions = no_ota.csv #------------------[ Examples ]------------------ @@ -133,10 +134,6 @@ lib_ignore = platform = espressif32@6.6.0 board = esp32-c3-devkitc-02 #board = esp32-c3-devkitm-1 -; change microcontroller -#board_build.mcu = esp32c3 -; change MCU frequency -#board_build.f_cpu = 160000000L 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 build_src_filter = + - + lib_deps = ${env.lib_deps} @@ -157,10 +154,6 @@ lib_deps = ${env.lib_deps} platform = espressif32@6.6.0 board = esp32-c3-devkitc-02 #board = esp32-c3-devkitm-1 -; change microcontroller -#board_build.mcu = esp32c3 -; change MCU frequency -#board_build.f_cpu = 160000000L build_flags = ${env.build_flags} -I examples -I src -D ESP32_C3 -D DISABLE_UI -D CONFIG_StatusLedPin=-1 -D ARDUINO_USB_MODE=1 -D ARDUINO_USB_CDC_ON_BOOT=1 build_src_filter = + - + + lib_deps = ${env.lib_deps} @@ -170,10 +163,6 @@ lib_deps = ${env.lib_deps} platform = espressif32@6.6.0 board = esp32-c3-devkitc-02 #board = esp32-c3-devkitm-1 -; change microcontroller -#board_build.mcu = esp32c3 -; change MCU frequency -#board_build.f_cpu = 160000000L build_flags = ${env.build_flags} -I examples -I src -D ESP32_C3 -D DISABLE_UI -D CONFIG_StatusLedPin=-1 -D LED_ARRAY_COUNT=25 -D LED_ARRAY_PIN=8 -D ARDUINO_USB_MODE=1 -D ARDUINO_USB_CDC_ON_BOOT=1 build_src_filter = + - + lib_deps = ${env.lib_deps} @@ -183,10 +172,6 @@ lib_deps = ${env.lib_deps} platform = espressif32@6.6.0 board = esp32-c3-devkitc-02 #board = esp32-c3-devkitm-1 -; change microcontroller -#board_build.mcu = esp32c3 -; change MCU frequency -#board_build.f_cpu = 160000000L build_flags = ${env.build_flags} -I examples -I src -D ESP32_C3 -D DISABLE_UI -D CONFIG_StatusLedPin=-1 -D LED_ARRAY_COUNT=64 -D LED_ARRAY_PIN=5 -D ARDUINO_USB_MODE=1 -D ARDUINO_USB_CDC_ON_BOOT=1 build_src_filter = + - + lib_deps = ${env.lib_deps} @@ -196,10 +181,6 @@ lib_deps = ${env.lib_deps} platform = espressif32@6.6.0 board = esp32-c3-devkitc-02 #board = esp32-c3-devkitm-1 -; change microcontroller -#board_build.mcu = esp32c3 -; change MCU frequency -#board_build.f_cpu = 160000000L build_flags = ${env.build_flags} -I examples -I src -D ESP32_C3 -D DISABLE_UI -D CONFIG_StatusLedPin=-1 -D LED_ARRAY_COUNT=90 -D LED_ARRAY_PIN=5 -D ARDUINO_USB_MODE=1 -D ARDUINO_USB_CDC_ON_BOOT=1 build_src_filter = + - + lib_deps = ${env.lib_deps} @@ -218,10 +199,6 @@ lib_deps = ${env.lib_deps} platform = espressif32@6.6.0 board = esp32-c3-devkitc-02 #board = esp32-c3-devkitm-1 -; change microcontroller -#board_build.mcu = esp32c3 -; change MCU frequency -#board_build.f_cpu = 160000000L build_flags = ${env.build_flags} -I examples -I src -D ESP32_C3 -D DISABLE_UI -D CONFIG_StatusLedPin=-1 -D ARDUINO_USB_MODE=1 -D ARDUINO_USB_CDC_ON_BOOT=1 build_src_filter = + - + lib_deps = ${env.lib_deps} @@ -239,9 +216,5 @@ build_src_filter = + - + platform = espressif32@6.6.0 board = esp32-c3-devkitc-02 #board = esp32-c3-devkitm-1 -; change microcontroller -#board_build.mcu = esp32c3 -; change MCU frequency -#board_build.f_cpu = 160000000L build_flags = ${env.build_flags} -I examples -I src -D ESP32_C3 -D ARDUINO_USB_MODE=1 -D ARDUINO_USB_CDC_ON_BOOT=1 build_src_filter = + - + diff --git a/src/Config.h b/src/Config.h index 57df274..07cef58 100644 --- a/src/Config.h +++ b/src/Config.h @@ -33,7 +33,7 @@ #include "defs.h" #include -#ifdef CONFIG_CREATE_AUTOMATION_TASK +#ifdef CONFIG_AUTOMATION_SPAWN_FREERTOS_TASK #include #endif #ifdef ESP32 diff --git a/src/HomeGenie.cpp b/src/HomeGenie.cpp index f4a5ceb..563e78b 100644 --- a/src/HomeGenie.cpp +++ b/src/HomeGenie.cpp @@ -85,7 +85,7 @@ namespace Service { // set scheduler callback Automation::Scheduler::setListener(this); -#ifdef CONFIG_CREATE_AUTOMATION_TASK +#ifdef CONFIG_AUTOMATION_SPAWN_FREERTOS_TASK /* xTaskCreate( reinterpret_cast(Scheduler::loop), @@ -216,6 +216,7 @@ namespace Service { handled = handled || handler->handleRequest(request, responseCallback); } //if (handled) break; + yield(); } return handled; } diff --git a/src/automation/ProgramEngine.cpp b/src/automation/ProgramEngine.cpp index 40b38a2..3cd2de7 100644 --- a/src/automation/ProgramEngine.cpp +++ b/src/automation/ProgramEngine.cpp @@ -41,7 +41,7 @@ namespace Automation { std::function ProgramEngine::apiRequest = nullptr; ProgramEngine::ProgramEngine() { -#ifndef CONFIG_CREATE_AUTOMATION_TASK +#ifndef CONFIG_AUTOMATION_SPAWN_FREERTOS_TASK setLoopInterval(100); #endif }; @@ -50,7 +50,7 @@ namespace Automation { ProgramEngine::apiRequest = std::move(ar); } -#ifdef CONFIG_CREATE_AUTOMATION_TASK +#ifdef CONFIG_AUTOMATION_SPAWN_FREERTOS_TASK [[noreturn]] void ProgramEngine::worker() { for(;;) { auto jobs = &ProgramEngine::scheduleList; diff --git a/src/automation/ProgramEngine.h b/src/automation/ProgramEngine.h index b52eb8c..faf1867 100644 --- a/src/automation/ProgramEngine.h +++ b/src/automation/ProgramEngine.h @@ -43,7 +43,7 @@ namespace Automation { using namespace Net; class ProgramEngine -#ifndef CONFIG_CREATE_AUTOMATION_TASK +#ifndef CONFIG_AUTOMATION_SPAWN_FREERTOS_TASK : Task #endif { @@ -51,7 +51,7 @@ namespace Automation { ProgramEngine(); static void begin(std::function); -#ifdef CONFIG_CREATE_AUTOMATION_TASK +#ifdef CONFIG_AUTOMATION_SPAWN_FREERTOS_TASK [[noreturn]] static void worker(); #else void loop() override; diff --git a/src/automation/ScheduledScript.cpp b/src/automation/ScheduledScript.cpp index 1cf6dd3..ca057e6 100644 --- a/src/automation/ScheduledScript.cpp +++ b/src/automation/ScheduledScript.cpp @@ -48,82 +48,47 @@ namespace Automation { duk_context *ctx = duk_create_heap_default(); - duk_push_c_lightfunc(ctx, helper_log, 2, 2, 0); + duk_push_c_lightfunc(ctx, helper_log, DUK_VARARGS, 0, 0); duk_put_global_string(ctx, "__log"); duk_push_c_lightfunc(ctx, pause, 1, 1, 0); duk_put_global_string(ctx, "__pause"); - duk_push_c_lightfunc(ctx, boundModules_on, 0, 0, 0); - duk_put_global_string(ctx, "__boundModules_on"); + duk_push_c_lightfunc(ctx, schedule_on_previous, 1, 1, 0); + duk_put_global_string(ctx, "__onPrevious"); - duk_push_c_lightfunc(ctx, boundModules_off, 0, 0, 0); - duk_put_global_string(ctx, "__boundModules_off"); + duk_push_c_lightfunc(ctx, schedule_on_next, 1, 1, 0); + duk_put_global_string(ctx, "__onNext"); - duk_push_c_lightfunc(ctx, boundModules_toggle, 0, 0, 0); - duk_put_global_string(ctx, "__boundModules_toggle"); + duk_push_c_lightfunc(ctx, netHelper_call, 0, 0, 0); + duk_put_global_string(ctx, "__netHelper_call"); - duk_push_c_lightfunc(ctx, boundModules_level_set, 1, 1, 0); - duk_put_global_string(ctx, "__boundModules_level_set"); + duk_push_c_lightfunc(ctx, netHelper_ping, 1, 1, 0); + duk_put_global_string(ctx, "__netHelper_ping"); - duk_push_c_lightfunc(ctx, boundModules_colorHsb_set, 1, 1, 0); - duk_put_global_string(ctx, "__boundModules_colorHsb_set"); + duk_push_c_lightfunc(ctx, boundModules_command, 2, 2, 0); + duk_put_global_string(ctx, "__boundModules_command"); + duk_push_c_lightfunc(ctx, boundModules_property_avg, 1, 1, 0); + duk_put_global_string(ctx, "__boundModules_property_avg"); + + duk_push_c_lightfunc(ctx, boundModules_property_get, 1, 1, 0); + duk_put_global_string(ctx, "__boundModules_property_get"); duk_push_pointer(ctx, schedule); duk_put_global_string(ctx, DUK_HIDDEN_SYMBOL("schedule")); - - String scriptCode = "const $$ = {" - " boundModules: {" - " on: function() {" - " __boundModules_on();" - " }," - " off: function() {" - " __boundModules_off();" - " }," - " toggle: function() {" - " __boundModules_toggle();" - " }," - " set level(v) {" - " __boundModules_level_set(v);" - " }," - " get level() {" - " return '';" // TODO: implement getter - " }," - " set colorHsb(hsb) {" - " __boundModules_colorHsb_set(hsb);" - " }," - " get colorHsb() {" - " return '';" // TODO: implement getter - " }" - " }," - " onPrevious: function() {" - " return false;" // TODO: 2B implemented - " }," - " onNext: function() {" - " return false;" // TODO: 2B implemented - " }," - " data: function(k, v) {" - " __log(k, v);" // TODO: 2B implemented - " }," - " pause: function(seconds) {" - " __pause(seconds);" - " }" - "};" + - schedule->script + - "\n;"; - + const String scriptCode = baseCode + schedule->script; duk_peval_string(ctx, scriptCode.c_str()); - duk_pop(ctx); // pop eval result + //duk_pop(ctx); // pop eval result duk_destroy_heap(ctx); } duk_ret_t ScheduledScript::pause(duk_context *ctx) { double pauseMs = (1000.0F * duk_to_number(ctx, 0)); -#ifdef CONFIG_CREATE_AUTOMATION_TASK +#ifdef CONFIG_AUTOMATION_SPAWN_FREERTOS_TASK vTaskDelay(portTICK_PERIOD_MS * pauseMs); #else unsigned long start = millis(); @@ -134,45 +99,74 @@ namespace Automation { return 0; } - duk_ret_t ScheduledScript::boundModules_level_get(duk_context *ctx) { - const char* res = getProperty(ctx, IOEventPaths::Status_Level); - duk_push_string(ctx, res); + duk_ret_t ScheduledScript::schedule_on_previous(duk_context *ctx) { + duk_get_global_string(ctx, DUK_HIDDEN_SYMBOL("schedule")); + auto schedule = (Schedule*)duk_get_pointer(ctx, -1); + time_t ts = time(0) - 60; // check one minute before now + bool result = schedule->occurs(ts); + duk_push_boolean(ctx, result); return 1; } - duk_ret_t ScheduledScript::boundModules_level_set(duk_context *ctx) { - String level = duk_to_string(ctx, 0); - auto command = String(ControlApi::Control_Level) + String("/") + String(level); - apiCommand(ctx, command.c_str()); - return 0; + duk_ret_t ScheduledScript::schedule_on_next(duk_context *ctx) { + duk_get_global_string(ctx, DUK_HIDDEN_SYMBOL("schedule")); + auto schedule = (Schedule*)duk_get_pointer(ctx, -1); + time_t ts = time(0) + 60; // check one minute after now + bool result = schedule->occurs(ts); + duk_push_boolean(ctx, result); + return 1; + } + + duk_ret_t ScheduledScript::boundModules_property_avg(duk_context *ctx) { + String propertyName = duk_to_string(ctx, 0); + float res = getAvgPropertyValue(ctx, propertyName.c_str()); + duk_push_number(ctx, res); + return 1; } - duk_ret_t ScheduledScript::boundModules_colorHsb_get(duk_context *ctx) { - const char* res = getProperty(ctx, IOEventPaths::Status_ColorHsb); + duk_ret_t ScheduledScript::boundModules_property_get(duk_context *ctx) { + String propertyName = duk_to_string(ctx, 0); + const char* res = getProperty(ctx, propertyName.c_str()); duk_push_string(ctx, res); return 1; } - duk_ret_t ScheduledScript::boundModules_colorHsb_set(duk_context *ctx) { - String hsb = duk_to_string(ctx, 0); - auto command = String(ControlApi::Control_ColorHsb) + String("/") + String(hsb); - apiCommand(ctx, command.c_str()); + duk_ret_t ScheduledScript::boundModules_command(duk_context *ctx) { + String command = duk_to_string(ctx, 0); + String options = duk_to_string(ctx, 1); + apiCommand(ctx, command.c_str(), options.c_str()); return 0; } - duk_ret_t ScheduledScript::boundModules_on(duk_context *ctx) { - apiCommand(ctx, ControlApi::Control_On); - return 0; + duk_ret_t ScheduledScript::netHelper_call(duk_context *ctx) { + String url = duk_to_string(ctx, 0); + String response = Helpers::NetHelper::httpGet(url); + duk_push_string(ctx, response.c_str()); + return 1; } - duk_ret_t ScheduledScript::boundModules_off(duk_context *ctx) { - apiCommand(ctx, ControlApi::Control_Off); - return 0; + duk_ret_t ScheduledScript::netHelper_ping(duk_context *ctx) { + String host = duk_to_string(ctx, 0); + bool result = Helpers::NetHelper::ping(host); + duk_push_boolean(ctx, result); + return 1; } - duk_ret_t ScheduledScript::boundModules_toggle(duk_context *ctx) { - apiCommand(ctx, ControlApi::Control_Toggle); - return 0; + float ScheduledScript::getAvgPropertyValue(duk_context *ctx, const char* propertyPath) { + duk_get_global_string(ctx, DUK_HIDDEN_SYMBOL("schedule")); + int vc = 0; float avg = 0; + auto schedule = (Schedule*)duk_get_pointer(ctx, -1); + for (auto mr: schedule->boundModules) { + auto module = HomeGenie::getInstance()->getModule(&mr->domain, &mr->address); + if (module != nullptr) { + auto property = module->getProperty(propertyPath); + if (property != nullptr && property->value != nullptr) { + avg += property->value.toFloat(); + vc++; + } + } + } + return avg / (float)vc; } const char* ScheduledScript::getProperty(duk_context *ctx, const char* propertyPath) { @@ -181,7 +175,7 @@ namespace Automation { for (auto mr: schedule->boundModules) { auto module = HomeGenie::getInstance()->getModule(&mr->domain, &mr->address); if (module != nullptr) { - auto property = module->getProperty(IOEventPaths::Status_ColorHsb); + auto property = module->getProperty(propertyPath); if (property != nullptr && property->value != nullptr) { return property->value.c_str(); } @@ -190,11 +184,11 @@ namespace Automation { return ""; } - void ScheduledScript::apiCommand(duk_context *ctx, const char* command) { + void ScheduledScript::apiCommand(duk_context *ctx, const char* command, const char* options) { duk_get_global_string(ctx, DUK_HIDDEN_SYMBOL("schedule")); auto schedule = (Schedule*)duk_get_pointer(ctx, -1); for (auto mr: schedule->boundModules) { - String apiCommand = String("/api/") + mr->domain + String("/") + mr->address + String("/") + String(command); + String apiCommand = String("/api/") + mr->domain + String("/") + mr->address + String("/") + String(command) + String("/") + String(options); // TODO: add support for generic HTTP commands @@ -207,14 +201,10 @@ namespace Automation { String res = ""; int n = duk_get_top(ctx); // #args for (int i = 0; i < n; i++) { - res += String(":") + duk_to_string(ctx, i); + res += duk_to_string(ctx, i); } - - //duk_get_global_string(ctx, DUK_HIDDEN_SYMBOL("schedule")); - //auto s = (Schedule*)duk_get_pointer(ctx, -1); - - duk_push_string(ctx, res.c_str()); - return 1; + Serial.println(res); + return 0; } } diff --git a/src/automation/ScheduledScript.h b/src/automation/ScheduledScript.h index 063abac..1e78b0a 100644 --- a/src/automation/ScheduledScript.h +++ b/src/automation/ScheduledScript.h @@ -59,6 +59,7 @@ Flash: [========= ] 92.1% (used 1810372 bytes from 1966080 bytes) * */ +#include "automation/helpers/NetHelper.h" #include "automation/ProgramEngine.h" namespace Automation { @@ -73,24 +74,109 @@ namespace Automation { void setSchedule(Schedule* s) { schedule = s; } - ScheduledScript(Schedule*); + explicit ScheduledScript(Schedule*); void run(); private: Schedule* schedule; static duk_ret_t helper_log(duk_context *ctx); static duk_ret_t pause(duk_context *ctx); - static duk_ret_t boundModules_level_get(duk_context *ctx); - static duk_ret_t boundModules_level_set(duk_context *ctx); - static duk_ret_t boundModules_colorHsb_get(duk_context *ctx); - static duk_ret_t boundModules_colorHsb_set(duk_context *ctx); - static duk_ret_t boundModules_on(duk_context *ctx); - static duk_ret_t boundModules_off(duk_context *ctx); - static duk_ret_t boundModules_toggle(duk_context *ctx); + + static duk_ret_t schedule_on_previous(duk_context *ctx); + static duk_ret_t schedule_on_next(duk_context *ctx); + + static duk_ret_t boundModules_command(duk_context *ctx); + static duk_ret_t boundModules_property_get(duk_context *ctx); + static duk_ret_t boundModules_property_avg(duk_context *ctx); + + static duk_ret_t netHelper_call(duk_context *ctx); + static duk_ret_t netHelper_ping(duk_context *ctx); + static const char* getProperty(duk_context *ctx, const char* propertyPath); - static void apiCommand(duk_context *ctx, const char* command); + static float getAvgPropertyValue(duk_context *ctx, const char* propertyPath); + + static void apiCommand(duk_context *ctx, const char* command, const char* options); + + const char* baseCode PROGMEM = "const $$ = {\n" + " get net() {\n" + " _url = '';\n" + " return {\n" + " webService: function(url) {\n" + " _url = url;\n" + " return this;\n" + " },\n" + " call: function() {\n" + " return __netHelper_call(_url);\n" + " },\n" + " ping: function(host) {\n" + " return __netHelper_ping(host);\n" + " }\n" + " }\n" + " },\n" + " get boundModules() {\n" + " return {\n" + " command: function(cmd, opts) {\n" + " __boundModules_command(cmd, opts);\n" + " return this;\n" + " },\n" + " on: function() {\n" + " __boundModules_command('Control.On', '');\n" + " return this;\n" + " },\n" + " off: function() {\n" + " __boundModules_command('Control.Off', '');\n" + " return this;\n" + " },\n" + " toggle: function() {\n" + " __boundModules_command('Control.Toggle', '');\n" + " return this;\n" + " },\n" + " set level(level) {\n" + " __boundModules_command('Control.Level', level);\n" + " return this;\n" + " },\n" + " get level() {\n" + " return __boundModules_property_avg('Status.Level');\n" + " },\n" + " set colorHsb(hsb) {\n" + " __boundModules_command('Control.ColorHsb', hsb);\n" + " return this;\n" + " },\n" + " get colorHsb() {\n" + " return __boundModules_property_get('Status.ColorHsb');\n" + " },\n" + " get isOn() {\n" + " return parseFloat(__boundModules_property_avg('Status.Level')) > 0;\n" + " },\n" + " get isOff() {\n" + " return parseFloat(__boundModules_property_avg('Status.Level')) === 0;\n" + " },\n" + " get temperature() {\n" + " return parseFloat(__boundModules_property_avg('Sensor.Temperature'));\n" + " },\n" + " get luminance() {\n" + " return parseFloat(__boundModules_property_avg('Sensor.Luminance'));\n" + " },\n" + " get humidity() {\n" + " return parseFloat(__boundModules_property_avg('Sensor.Humidity'));\n" + " }\n" + " }\n" + " },\n" + " onPrevious: function() {\n" + " return __onPrevious();\n" + " },\n" + " onNext: function() {\n" + " return __onNext();\n" + " },\n" + " data: function(k, v) {\n" + " __log(k, v);\n" // TODO: 2B implemented + " },\n" + " pause: function(seconds) {\n" + " __pause(seconds);\n" + " return this;\n" + " }\n" + "};\n"; }; - }; diff --git a/src/automation/helpers/NetHelper.cpp b/src/automation/helpers/NetHelper.cpp new file mode 100644 index 0000000..feca593 --- /dev/null +++ b/src/automation/helpers/NetHelper.cpp @@ -0,0 +1,57 @@ +/* + * HomeGenie-Mini (c) 2018-2024 G-Labs + * + * + * This file is part of HomeGenie-Mini (HGM). + * + * HomeGenie-Mini is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * HomeGenie-Mini is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with HomeGenie-Mini. If not, see . + * + * + * Authors: + * - Generoso Martello + * + * + * Releases: + * - 2019-01-13 Initial release + * + */ + +#include "NetHelper.h" + +namespace Automation { namespace Helpers { + HTTPClient NetHelper::http; + + String NetHelper::httpGet(String &url) { + String response; + http.begin(url.c_str()); + //http.addHeader("Content-Type", "application/x-www-form-urlencoded"); + int httpCode = http.GET(); + if (httpCode > 0) { + // Server response + if (httpCode == HTTP_CODE_OK) { + response = http.getString(); + } else { + // Server reported error code + //Serial.printf("[HTTP] GET... code: %d\n", httpCode); + } + } else { + //Serial.printf("[HTTP] GET... failed, error: %s\n", HTTPClient::errorToString(httpCode).c_str()); + } + return response; + } + + bool NetHelper::ping(String &host) { + return Ping.ping(host.c_str()); + } +}} diff --git a/src/automation/helpers/NetHelper.h b/src/automation/helpers/NetHelper.h new file mode 100644 index 0000000..c887cc1 --- /dev/null +++ b/src/automation/helpers/NetHelper.h @@ -0,0 +1,55 @@ +/* + * HomeGenie-Mini (c) 2018-2024 G-Labs + * + * + * This file is part of HomeGenie-Mini (HGM). + * + * HomeGenie-Mini is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * HomeGenie-Mini is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with HomeGenie-Mini. If not, see . + * + * + * Authors: + * - Generoso Martello + * + * + * Releases: + * - 2019-01-13 Initial release + * + */ + +#ifndef HOMEGENIE_MINI_NETHELPER_H +#define HOMEGENIE_MINI_NETHELPER_H + +#ifdef ESP8266 +#include +#else +#include +#endif +#include + +#include "Config.h" + +namespace Automation { namespace Helpers { + + class NetHelper{ + public: + static String httpGet(String& url); + static bool ping(String& host); + + private: + static HTTPClient http; + }; + +}} + +#endif //HOMEGENIE_MINI_NETHELPER_H diff --git a/src/defs.h b/src/defs.h index e35d4e9..5427819 100644 --- a/src/defs.h +++ b/src/defs.h @@ -39,7 +39,10 @@ #define DEBUGLOG_DEFAULT_LOG_LEVEL_ERROR -#define CONFIG_CREATE_AUTOMATION_TASK +// disabling FreeRTOS task saves about ~10K or RAM +//#define CONFIG_AUTOMATION_SPAWN_FREERTOS_TASK + +// disabling SSE and MQTT saves only ~2K of RAM //#define DISABLE_SSE //#define DISABLE_MQTT @@ -54,7 +57,7 @@ #endif #ifdef ESP8266 - #undef CONFIG_CREATE_AUTOMATION_TASK + #undef CONFIG_AUTOMATION_SPAWN_FREERTOS_TASK #define DISABLE_UI #define DISABLE_BLUETOOTH_LE #define DISABLE_BLUETOOTH_CLASSIC diff --git a/src/net/NetManager.cpp b/src/net/NetManager.cpp index 07c86dc..b24b4a7 100644 --- a/src/net/NetManager.cpp +++ b/src/net/NetManager.cpp @@ -142,8 +142,10 @@ namespace Net { void NetManager::loop() { Logger::verbose("%s loop() >> BEGIN", NETMANAGER_LOG_PREFIX); - for (int i = 0; i < 8; i++) + for (int i = 0; i < 5; i++) { // higher priority task webSocket->loop(); + yield(); + } Logger::verbose("%s loop() << END", NETMANAGER_LOG_PREFIX); } diff --git a/src/partitions.csv b/src/partitions.csv index aee5d55..f9e5083 100644 --- a/src/partitions.csv +++ b/src/partitions.csv @@ -1,3 +1,4 @@ # Name, Type, SubType, Offset, Size, Flags -nvs, data, nvs, 36K, 20K, -factory, app, factory, 64K, 4000K, \ No newline at end of file +nvs, data, nvs, 36K, 28K, +factory, app, factory, 64K, 3912K, +spiffs, data, spiffs, 3976K, 120K, diff --git a/src/service/EventRouter.cpp b/src/service/EventRouter.cpp index db1f37f..7f7c26e 100644 --- a/src/service/EventRouter.cpp +++ b/src/service/EventRouter.cpp @@ -88,6 +88,8 @@ namespace Service { } // TODO: route event to the console as well + + yield(); } } @@ -102,6 +104,7 @@ namespace Service { updated = true; break; } + yield(); } if (!updated) { eventsQueue.add(m); diff --git a/src/service/api/devices/ColorLight.h b/src/service/api/devices/ColorLight.h index e42aa1b..d22446d 100644 --- a/src/service/api/devices/ColorLight.h +++ b/src/service/api/devices/ColorLight.h @@ -66,20 +66,20 @@ namespace Service { namespace API { namespace devices { return ov + ((v - ov) * getProgress()); } float getRed() { - auto orgb = Utility::hsv2rgb(hfix(oh), os, ov); - auto crgb = Utility::hsv2rgb(hfix(h), s, v); + auto orgb = Utility::hsv2rgb(hueFix(oh), os, ov); + auto crgb = Utility::hsv2rgb(hueFix(h), s, v); float r = orgb.r + ((crgb.r - orgb.r) * getProgress()); return r; } float getGreen() { - auto orgb = Utility::hsv2rgb(hfix(oh), os, ov); - auto crgb = Utility::hsv2rgb(hfix(h), s, v); + auto orgb = Utility::hsv2rgb(hueFix(oh), os, ov); + auto crgb = Utility::hsv2rgb(hueFix(h), s, v); float g = orgb.g + ((crgb.g - orgb.g) * getProgress()); return g; } float getBlue() { - auto orgb = Utility::hsv2rgb(hfix(oh), os, ov); - auto crgb = Utility::hsv2rgb(hfix(h), s, v); + auto orgb = Utility::hsv2rgb(hueFix(oh), os, ov); + auto crgb = Utility::hsv2rgb(hueFix(h), s, v); float b = orgb.b + ((crgb.b - orgb.b) * getProgress()); return b; } @@ -89,7 +89,7 @@ namespace Service { namespace API { namespace devices { float v; float oh, os, ov; unsigned long startTime; - float hfix(float h) { + static float hueFix(float h) { return 1.325f - h; } @@ -108,8 +108,6 @@ namespace Service { namespace API { namespace devices { private: LightColor color; std::function setColorCallback = nullptr; - - void setColor(float h, float s, float v, float duration); }; }}} diff --git a/src/ui/activities/control/SwitchControlActivity.h b/src/ui/activities/control/SwitchControlActivity.h index c7923d1..402cfa1 100644 --- a/src/ui/activities/control/SwitchControlActivity.h +++ b/src/ui/activities/control/SwitchControlActivity.h @@ -201,6 +201,7 @@ namespace UI { namespace Activities { namespace Control { invalidate(); } + // TODO: implement with Automation::Helpers::NetHelper::httpGet bool sendCommand(const char* command, const char* options = "") { String url = moduleBaseUrl; if (!url.endsWith("/")) {