diff --git a/interface/package.json b/interface/package.json index 8c4de3df6..bb5058464 100644 --- a/interface/package.json +++ b/interface/package.json @@ -42,7 +42,7 @@ }, "devDependencies": { "@babel/core": "^7.25.2", - "@eslint/js": "^9.9.1", + "@eslint/js": "^9.10.0", "@preact/compat": "^17.1.2", "@preact/preset-vite": "^2.9.0", "@trivago/prettier-plugin-sort-imports": "^4.3.0", @@ -53,7 +53,7 @@ "@types/react-dom": "^18.3.0", "@types/react-router-dom": "^5.3.3", "concurrently": "^8.2.2", - "eslint": "^9.9.1", + "eslint": "^9.10.0", "eslint-config-prettier": "^9.1.0", "formidable": "^3.5.1", "prettier": "^3.3.3", diff --git a/interface/yarn.lock b/interface/yarn.lock index 8d0cca047..7a2992365 100644 --- a/interface/yarn.lock +++ b/interface/yarn.lock @@ -750,10 +750,10 @@ __metadata: languageName: node linkType: hard -"@eslint/js@npm:9.9.1, @eslint/js@npm:^9.9.1": - version: 9.9.1 - resolution: "@eslint/js@npm:9.9.1" - checksum: 10c0/a3a91de2ce78469f7c4eee78c1eba77360706e1d0fa0ace2e19102079bcf237b851217c85ea501dc92c4c3719d60d9df966977abc8554d4c38e3638c1f53dcb2 +"@eslint/js@npm:9.10.0, @eslint/js@npm:^9.10.0": + version: 9.10.0 + resolution: "@eslint/js@npm:9.10.0" + checksum: 10c0/2ac45a002dc1ccf25be46ea61001ada8d77248d1313ab4e53f3735e5ae00738a757874e41f62ad6fbd49df7dffeece66e5f53ff0d7b78a99ce4c68e8fea66753 languageName: node linkType: hard @@ -764,6 +764,15 @@ __metadata: languageName: node linkType: hard +"@eslint/plugin-kit@npm:^0.1.0": + version: 0.1.0 + resolution: "@eslint/plugin-kit@npm:0.1.0" + dependencies: + levn: "npm:^0.4.1" + checksum: 10c0/fae97cd4efc1c32501c286abba1b5409848ce8c989e1ca6a5bb057a304a2cd721e6e957f6bc35ce95cfd0871e822ed42df3c759fecdad72c30e70802e26f83c7 + languageName: node + linkType: hard + "@humanwhocodes/module-importer@npm:^1.0.1": version: 1.0.1 resolution: "@humanwhocodes/module-importer@npm:1.0.1" @@ -1710,7 +1719,7 @@ __metadata: "@babel/core": "npm:^7.25.2" "@emotion/react": "npm:^11.13.3" "@emotion/styled": "npm:^11.13.0" - "@eslint/js": "npm:^9.9.1" + "@eslint/js": "npm:^9.10.0" "@mui/icons-material": "npm:^6.0.2" "@mui/material": "npm:^6.0.2" "@preact/compat": "npm:^17.1.2" @@ -1726,7 +1735,7 @@ __metadata: alova: "npm:3.0.16" async-validator: "npm:^4.2.5" concurrently: "npm:^8.2.2" - eslint: "npm:^9.9.1" + eslint: "npm:^9.10.0" eslint-config-prettier: "npm:^9.1.0" formidable: "npm:^3.5.1" jwt-decode: "npm:^4.0.0" @@ -3224,15 +3233,16 @@ __metadata: languageName: node linkType: hard -"eslint@npm:^9.9.1": - version: 9.9.1 - resolution: "eslint@npm:9.9.1" +"eslint@npm:^9.10.0": + version: 9.10.0 + resolution: "eslint@npm:9.10.0" dependencies: "@eslint-community/eslint-utils": "npm:^4.2.0" "@eslint-community/regexpp": "npm:^4.11.0" "@eslint/config-array": "npm:^0.18.0" "@eslint/eslintrc": "npm:^3.1.0" - "@eslint/js": "npm:9.9.1" + "@eslint/js": "npm:9.10.0" + "@eslint/plugin-kit": "npm:^0.1.0" "@humanwhocodes/module-importer": "npm:^1.0.1" "@humanwhocodes/retry": "npm:^0.3.0" "@nodelib/fs.walk": "npm:^1.2.8" @@ -3255,7 +3265,6 @@ __metadata: is-glob: "npm:^4.0.0" is-path-inside: "npm:^3.0.3" json-stable-stringify-without-jsonify: "npm:^1.0.1" - levn: "npm:^0.4.1" lodash.merge: "npm:^4.6.2" minimatch: "npm:^3.1.2" natural-compare: "npm:^1.4.0" @@ -3269,7 +3278,7 @@ __metadata: optional: true bin: eslint: bin/eslint.js - checksum: 10c0/5e71efda7c0a14ee95436d5cdfed04ee61dfb1d89d7a32b50a424de2e680af82849628ea6581950c2e0726491f786a3cfd0032ce013c1c5093786e475cfdfb33 + checksum: 10c0/7357f3995b15043eea83c8c0ab16c385ce3f28925c1b11cfcd6b2ede8faab3d91ede84a68173dd5f6e3e176e177984e6218de58b7b8388e53e2881f1ec07c836 languageName: node linkType: hard diff --git a/platformio.ini b/platformio.ini index 0a745d9a9..70de8b6ea 100644 --- a/platformio.ini +++ b/platformio.ini @@ -171,6 +171,7 @@ board_upload.flash_size = 4MB board_build.partitions = esp32_partition_4M.csv board_build.extra_flags = '-DEMSESP_DEFAULT_BOARD_PROFILE="S2MINI"' +; https://github.com/platformio/platform-espressif32/blob/master/boards/lolin_s3.json [env:s3_16M_P] extends = espressi32_base board = lolin_s3 diff --git a/scripts/upload_cli.py b/scripts/upload_cli.py index 8a6a5836e..d407983a2 100644 --- a/scripts/upload_cli.py +++ b/scripts/upload_cli.py @@ -1,13 +1,14 @@ # Modified from https://github.com/ayushsharma82/ElegantOTA # -# Requires Python (sudo apt install python3-pip) -# `python3 -m venv venv` to create the virtual environment -# `source ./venv/bin/activate` to enter it -# `pip install -r requirements.txt` to install the libraries +# Requires Python (sudo apt install python3-pip) and then create a virtual environment: +# cd scripts +# python3 -m venv venv +# source ./venv/bin/activate +# pip install -r requirements.txt # # Run using for example: -# python3 upload_cli.py -i 10.10.10.173 -f ../build/firmware/EMS-ESP-3_7_0-dev_8-ESP32_4M.bin +# python3 upload_cli.py -i 10.10.10.175 -f ../build/firmware/EMS-ESP-3_7_0-dev_34-ESP32S3-16MB+.bin import argparse import requests @@ -104,7 +105,22 @@ def upload(file, ip, username, password): if response.status_code != 200: print_fail("Upload failed (code " + response.status.code + ").") else: - print_success("Upload successful.") + print_success("Upload successful. Rebooting device.") + restart_headers = { + 'Host': host_ip, + 'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/118.0', + 'Accept': '*/*', + 'Accept-Language': 'de,en-US;q=0.7,en;q=0.3', + 'Accept-Encoding': 'gzip, deflate', + 'Referer': f'{emsesp_url}', + 'Content-Type': 'application/json', + 'Connection': 'keep-alive', + 'Authorization': 'Bearer ' + f'{access_token}' + } + restart_url = f"{emsesp_url}/api/system/restart" + response = requests.get(restart_url, headers=restart_headers) + if response.status_code != 200: + print_fail("Restart failed (code " + str(response.status_code) + ")") print() diff --git a/src/console.cpp b/src/console.cpp index 917f144c5..67b7ade63 100644 --- a/src/console.cpp +++ b/src/console.cpp @@ -79,13 +79,7 @@ static void setup_commands(std::shared_ptr & commands) { commands->add_command(ShellContext::MAIN, CommandFlags::USER, string_vector{F_(show), F_(system)}, - [=](Shell & shell, const std::vector & arguments) { - shell.println(); - shell.printfln("%s%sEMS-ESP version %s%s", COLOR_BRIGHT_GREEN, COLOR_BOLD_ON, EMSESP_APP_VERSION, COLOR_RESET); - shell.println(); - to_app(shell).system_.show_system(shell); - shell.println(); - }); + [=](Shell & shell, const std::vector & arguments) { to_app(shell).system_.show_system(shell); }); commands->add_command(ShellContext::MAIN, CommandFlags::ADMIN, diff --git a/src/emsesp.cpp b/src/emsesp.cpp index 2fd0cc095..bcb020c94 100644 --- a/src/emsesp.cpp +++ b/src/emsesp.cpp @@ -1614,7 +1614,7 @@ void EMSESP::start() { device_library_ = { #include "device_library.h" }; - LOG_INFO("Loaded EMS device library (%d)", device_library_.size()); + LOG_INFO("Loaded EMS device library (%d entries)", device_library_.size()); system_.reload_settings(); // ... and store some of the settings locally diff --git a/src/modbus.cpp b/src/modbus.cpp index dbdd9814b..e949e8009 100644 --- a/src/modbus.cpp +++ b/src/modbus.cpp @@ -512,7 +512,7 @@ int Modbus::getRegisterCount(const DeviceValue & dv) { num_registers = 1; else if (num_values <= (1L << 16)) num_registers = 2; - else if (num_values <= (1L << 32)) // TODO: fix, this will always be true for compilers with 32 bit longs + else if (num_values <= (1L << 32)) num_registers = 4; else LOG_ERROR("num_registers is too big to be encoded with modbus registers"); diff --git a/src/system.cpp b/src/system.cpp index ef9de4e5e..8983b4317 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -300,7 +300,7 @@ void System::system_restart(const char * partitionname) { if (partition && strcmp(partition->label, partitionname) == 0) { esp_ota_set_boot_partition(partition); } else - // try and find the parition by name + // try and find the partition by name if (strcmp(esp_ota_get_running_partition()->label, partitionname) != 0) { partition = esp_ota_get_next_update_partition(nullptr); if (!partition) { @@ -525,8 +525,8 @@ void System::button_OnDblClick(PButton & b) { // button long press void System::button_OnLongPress(PButton & b) { - LOG_NOTICE("Button pressed - long press - restart other partition"); - EMSESP::system_.system_restart("boot"); + LOG_NOTICE("Button pressed - long press - restart from factory/boot partition"); + EMSESP::system_.system_restart("boot"); // this is default when first installed. it may contain the bootloader code. } // button indefinite press - do nothing for now @@ -987,13 +987,18 @@ void System::show_users(uuid::console::Shell & shell) { shell.println(); } +// shell command 'show system' void System::show_system(uuid::console::Shell & shell) { refreshHeapMem(); // refresh free heap and max alloc heap + shell.println(); shell.println("System:"); shell.printfln(" Version: %s", EMSESP_APP_VERSION); - shell.printfln(" Platform: %s", EMSESP_PLATFORM); - shell.printfln(" NVS device information: %s", getBBQKeesGatewayDetails().c_str()); + shell.printfln(" Platform: %s (%s)", EMSESP_PLATFORM, ESP.getChipModel()); + shell.printfln(" Model: %s", getBBQKeesGatewayDetails().c_str()); +#ifndef EMSESP_STANDALONE + shell.printfln(" Partition Boot/Running: %s/%s", esp_ota_get_boot_partition()->label, esp_ota_get_running_partition()->label); +#endif shell.printfln(" Language: %s", locale().c_str()); shell.printfln(" Board profile: %s", board_profile().c_str()); shell.printfln(" Uptime: %s", uuid::log::format_timestamp_ms(uuid::get_uptime_ms(), 3).c_str()); @@ -1010,8 +1015,11 @@ void System::show_system(uuid::console::Shell & shell) { shell.printfln(" App used/free: %lu KB / %lu KB", appUsed(), appFree()); uint32_t FSused = LittleFS.usedBytes() / 1024; shell.printfln(" FS used/free: %lu KB / %lu KB", FSused, FStotal() - FSused); - shell.println(); + if (PSram()) { + shell.printfln(" PSRAM size/free: %lu KB / %lu KB", PSram(), ESP.getFreePsram() / 1024); + } + shell.println(); shell.println("Network:"); // show ethernet mac address if we have an eth controller present @@ -1113,6 +1121,8 @@ void System::show_system(uuid::console::Shell & shell) { shell.printfln(" Queued: %d", syslog_.queued()); } + shell.println(); + #endif } @@ -1414,17 +1424,25 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output node["uptime"] = uuid::log::format_timestamp_ms(uuid::get_uptime_ms(), 3); node["uptimeSec"] = uuid::get_uptime_sec(); #ifndef EMSESP_STANDALONE - node["platform"] = EMSESP_PLATFORM; - node["arduino"] = ARDUINO_VERSION; - node["sdk"] = ESP.getSdkVersion(); - node["freeMem"] = getHeapMem(); - node["maxAlloc"] = getMaxAllocMem(); - node["freeCaps"] = heap_caps_get_free_size(MALLOC_CAP_8BIT) / 1024; // includes heap and psram - node["usedApp"] = EMSESP::system_.appUsed(); // kilobytes - node["freeApp"] = EMSESP::system_.appFree(); // kilobytes - node["partition"] = esp_ota_get_running_partition()->label; + node["platform"] = EMSESP_PLATFORM; + node["cpuType"] = ESP.getChipModel(); + node["arduino"] = ARDUINO_VERSION; + node["sdk"] = ESP.getSdkVersion(); + node["freeMem"] = getHeapMem(); + node["maxAlloc"] = getMaxAllocMem(); + node["freeCaps"] = heap_caps_get_free_size(MALLOC_CAP_8BIT) / 1024; // includes heap and psram + node["usedApp"] = EMSESP::system_.appUsed(); // kilobytes + node["freeApp"] = EMSESP::system_.appFree(); // kilobytes + node["partitionBootRunning"] = std::string(esp_ota_get_boot_partition()->label) + "/" + + esp_ota_get_running_partition()->label; // will sycle app0/app0 - app1/app1 after OTA. boot/factory is on first install. #endif node["resetReason"] = EMSESP::system_.reset_reason(0) + " / " + EMSESP::system_.reset_reason(1); + node["psram"] = (EMSESP::system_.PSram() > 0); // boolean + if (EMSESP::system_.PSram()) { + node["psramSize"] = EMSESP::system_.PSram(); + node["freePsram"] = ESP.getFreePsram() / 1024; + } + node["model"] = EMSESP::system_.getBBQKeesGatewayDetails(); // Network Status node = output["network"].to(); @@ -1635,7 +1653,8 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output #else node["webLogBuffer"] = EMSESP::webLogService.num_log_messages(); #endif - node["modbusEnabled"] = settings.modbus_enabled; + node["modbusEnabled"] = settings.modbus_enabled; + node["forceHeatingOff"] = settings.boiler_heatingoff; }); // Devices - show EMS devices if we have any diff --git a/src/web/WebStatusService.cpp b/src/web/WebStatusService.cpp index ea3307cd5..c9939a7da 100644 --- a/src/web/WebStatusService.cpp +++ b/src/web/WebStatusService.cpp @@ -79,7 +79,7 @@ void WebStatusService::systemStatus(AsyncWebServerRequest * request) { } // /rest/hardwareStatus -// This is also used for polling +// This is also used for polling during the RestartMonitor to see if EMS-ESP is alive void WebStatusService::hardwareStatus(AsyncWebServerRequest * request) { EMSESP::system_.refreshHeapMem(); // refresh free heap and max alloc heap @@ -109,7 +109,7 @@ void WebStatusService::hardwareStatus(AsyncWebServerRequest * request) { root["free_heap"] = EMSESP::system_.getHeapMem(); root["arduino_version"] = ARDUINO_VERSION; root["sdk_version"] = ESP.getSdkVersion(); - root["partition"] = esp_ota_get_running_partition()->label; + root["partition"] = esp_ota_get_running_partition()->label; // active partition root["flash_chip_size"] = ESP.getFlashChipSize() / 1024; root["flash_chip_speed"] = ESP.getFlashChipSpeed(); root["app_used"] = EMSESP::system_.appUsed();