diff --git a/CHANGELOG_LATEST.md b/CHANGELOG_LATEST.md index c77cb22e8..89a912bdd 100644 --- a/CHANGELOG_LATEST.md +++ b/CHANGELOG_LATEST.md @@ -12,7 +12,7 @@ This release is based on the latest Espressif/Arduino core version 3. It brings - Commands Service that can be called via MQTT or API or used in the Scheduler Service - option to disable factory reset [#3150](https://github.com/emsesp/EMS-ESP32/issues/3150) - TLS support with 4MB boards without PSRAM -- added eth_10mbit, which forces 10BASE-T half-duplex & autonegotiation off, halving the PHY’s power draw. It’s off by default as it will cause issues on managed switches with a port forced to 100Mb [#3213](https://github.com/emsesp/EMS-ESP32/pull/3213) +- added eth_10mbit to Network Settings, which forces 10BASE-T half-duplex & autonegotiation off, halving the PHY’s power draw. It’s off by default as it will cause issues on managed switches with a port forced to 100Mb [#3213](https://github.com/emsesp/EMS-ESP32/pull/3213) ## Fixed diff --git a/data/pre_load.json b/data/pre_load.json index 36c23849c..e6fd8d2b5 100644 --- a/data/pre_load.json +++ b/data/pre_load.json @@ -16,7 +16,8 @@ "enableMDNS": true, "enableCORS": false, "CORSOrigin": "*", - "tx_power": 0 + "tx_power": 0, + "eth_10mbit": false }, "AP": { "provision_mode": 2, @@ -129,7 +130,6 @@ "eth_power": 15, "eth_phy_addr": 0, "eth_clock_mode": 1, - "eth_10mbit": false, "modbus_enabled": false, "modbus_port": 502, "modbus_max_clients": 10, diff --git a/interface/package.json b/interface/package.json index e2e473ff9..b728a853b 100644 --- a/interface/package.json +++ b/interface/package.json @@ -42,7 +42,7 @@ "@eslint/js": "^10.0.1", "@preact/preset-vite": "^2.10.6", "@trivago/prettier-plugin-sort-imports": "^6.0.2", - "@types/node": "^26.4.0", + "@types/node": "^26.4.1", "@types/react": "^19.2.18", "@types/react-dom": "^19.2.5", "concurrently": "^10.0.5", diff --git a/interface/pnpm-lock.yaml b/interface/pnpm-lock.yaml index 0fa5026f6..69bf335c2 100644 --- a/interface/pnpm-lock.yaml +++ b/interface/pnpm-lock.yaml @@ -56,13 +56,13 @@ importers: version: 10.0.1(eslint@10.9.1(supports-color@10.2.2)) '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@10.2.2))(preact@10.29.8)(supports-color@10.2.2)(vite@8.2.2(@types/node@26.4.0)(terser@5.51.2)) + version: 2.10.6(@babel/core@7.29.7(supports-color@10.2.2))(preact@10.29.8)(supports-color@10.2.2)(vite@8.2.2(@types/node@26.4.1)(terser@5.51.2)) '@trivago/prettier-plugin-sort-imports': specifier: ^6.0.2 version: 6.0.2(prettier@3.9.6)(supports-color@10.2.2) '@types/node': - specifier: ^26.4.0 - version: 26.4.0 + specifier: ^26.4.1 + version: 26.4.1 '@types/react': specifier: ^19.2.18 version: 19.2.18 @@ -101,10 +101,10 @@ importers: version: 8.69.0(eslint@10.9.1(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3) vite: specifier: ^8.2.2 - version: 8.2.2(@types/node@26.4.0)(terser@5.51.2) + version: 8.2.2(@types/node@26.4.1)(terser@5.51.2) vite-plugin-imagemin: specifier: ^0.6.1 - version: 0.6.1(supports-color@10.2.2)(vite@8.2.2(@types/node@26.4.0)(terser@5.51.2)) + version: 0.6.1(supports-color@10.2.2)(vite@8.2.2(@types/node@26.4.1)(terser@5.51.2)) packages: @@ -668,8 +668,8 @@ packages: resolution: {integrity: sha512-zmPitbQ8+6zNutpwgcQuLcsEpn/Cj54Kbn7L5pX0Os5kdWplB7xPgEh/g+SWOB/qmows2gpuCaPyduq8ZZRnxA==} deprecated: This is a stub types definition. minimatch provides its own type definitions, so you do not need this installed. - '@types/node@26.4.0': - resolution: {integrity: sha512-faiGnoIrLH/V8cibOMEAZ8pMw6oXqSukl29ra4mN8GdaB2ZewzeaLj+INpV5N+Z1eKWzY+IzaIZH2EIR6YZRNQ==} + '@types/node@26.4.1': + resolution: {integrity: sha512-k97ENvZWtvA6yqz5/FS6a7duDgOPEeOQOc2iKS/nY6mX6qJUKtLnWzQS+Xj6tXweyj6ZcTAK2Qecetnvi9nCLA==} '@types/parse-json@4.0.2': resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} @@ -3394,19 +3394,19 @@ snapshots: '@popperjs/core@2.11.8': {} - '@preact/preset-vite@2.10.6(@babel/core@7.29.7(supports-color@10.2.2))(preact@10.29.8)(supports-color@10.2.2)(vite@8.2.2(@types/node@26.4.0)(terser@5.51.2))': + '@preact/preset-vite@2.10.6(@babel/core@7.29.7(supports-color@10.2.2))(preact@10.29.8)(supports-color@10.2.2)(vite@8.2.2(@types/node@26.4.1)(terser@5.51.2))': dependencies: '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/plugin-transform-react-jsx': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) '@babel/plugin-transform-react-jsx-development': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) - '@prefresh/vite': 2.4.12(preact@10.29.8)(supports-color@10.2.2)(vite@8.2.2(@types/node@26.4.0)(terser@5.51.2)) + '@prefresh/vite': 2.4.12(preact@10.29.8)(supports-color@10.2.2)(vite@8.2.2(@types/node@26.4.1)(terser@5.51.2)) '@rollup/pluginutils': 5.4.0 babel-plugin-transform-hook-names: 1.0.2(@babel/core@7.29.7(supports-color@10.2.2)) debug: 4.4.3(supports-color@10.2.2) magic-string: 0.30.21 picocolors: 1.1.1 - vite: 8.2.2(@types/node@26.4.0)(terser@5.51.2) - vite-prerender-plugin: 0.5.13(vite@8.2.2(@types/node@26.4.0)(terser@5.51.2)) + vite: 8.2.2(@types/node@26.4.1)(terser@5.51.2) + vite-prerender-plugin: 0.5.13(vite@8.2.2(@types/node@26.4.1)(terser@5.51.2)) zimmerframe: 1.1.5 transitivePeerDependencies: - preact @@ -3421,7 +3421,7 @@ snapshots: '@prefresh/utils@1.2.1': {} - '@prefresh/vite@2.4.12(preact@10.29.8)(supports-color@10.2.2)(vite@8.2.2(@types/node@26.4.0)(terser@5.51.2))': + '@prefresh/vite@2.4.12(preact@10.29.8)(supports-color@10.2.2)(vite@8.2.2(@types/node@26.4.1)(terser@5.51.2))': dependencies: '@babel/core': 7.29.7(supports-color@10.2.2) '@prefresh/babel-plugin': 0.5.3 @@ -3429,7 +3429,7 @@ snapshots: '@prefresh/utils': 1.2.1 '@rollup/pluginutils': 4.2.1 preact: 10.29.8 - vite: 8.2.2(@types/node@26.4.0)(terser@5.51.2) + vite: 8.2.2(@types/node@26.4.1)(terser@5.51.2) transitivePeerDependencies: - supports-color @@ -3523,7 +3523,7 @@ snapshots: '@types/glob@7.2.0': dependencies: '@types/minimatch': 6.0.0 - '@types/node': 26.4.0 + '@types/node': 26.4.1 '@types/imagemin-gifsicle@7.0.4': dependencies: @@ -3552,23 +3552,23 @@ snapshots: '@types/imagemin@7.0.1': dependencies: - '@types/node': 26.4.0 + '@types/node': 26.4.1 '@types/imagemin@9.0.1': dependencies: - '@types/node': 26.4.0 + '@types/node': 26.4.1 '@types/json-schema@7.0.15': {} '@types/keyv@3.1.4': dependencies: - '@types/node': 26.4.0 + '@types/node': 26.4.1 '@types/minimatch@6.0.0': dependencies: minimatch: 10.2.6 - '@types/node@26.4.0': + '@types/node@26.4.1': dependencies: undici-types: 8.3.0 @@ -3590,11 +3590,11 @@ snapshots: '@types/responselike@1.0.3': dependencies: - '@types/node': 26.4.0 + '@types/node': 26.4.1 '@types/svgo@2.6.4': dependencies: - '@types/node': 26.4.0 + '@types/node': 26.4.1 '@typescript-eslint/eslint-plugin@8.69.0(@typescript-eslint/parser@8.69.0(eslint@10.9.1(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.9.1(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)': dependencies: @@ -5775,7 +5775,7 @@ snapshots: spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 - vite-plugin-imagemin@0.6.1(supports-color@10.2.2)(vite@8.2.2(@types/node@26.4.0)(terser@5.51.2)): + vite-plugin-imagemin@0.6.1(supports-color@10.2.2)(vite@8.2.2(@types/node@26.4.1)(terser@5.51.2)): dependencies: '@types/imagemin': 7.0.1 '@types/imagemin-gifsicle': 7.0.4 @@ -5800,11 +5800,11 @@ snapshots: imagemin-webp: 6.1.0 jpegtran-bin: 6.0.1 pathe: 0.2.0 - vite: 8.2.2(@types/node@26.4.0)(terser@5.51.2) + vite: 8.2.2(@types/node@26.4.1)(terser@5.51.2) transitivePeerDependencies: - supports-color - vite-prerender-plugin@0.5.13(vite@8.2.2(@types/node@26.4.0)(terser@5.51.2)): + vite-prerender-plugin@0.5.13(vite@8.2.2(@types/node@26.4.1)(terser@5.51.2)): dependencies: kolorist: 1.8.0 magic-string: 0.30.21 @@ -5812,9 +5812,9 @@ snapshots: simple-code-frame: 1.3.0 source-map: 0.7.6 stack-trace: 1.0.0 - vite: 8.2.2(@types/node@26.4.0)(terser@5.51.2) + vite: 8.2.2(@types/node@26.4.1)(terser@5.51.2) - vite@8.2.2(@types/node@26.4.0)(terser@5.51.2): + vite@8.2.2(@types/node@26.4.1)(terser@5.51.2): dependencies: lightningcss: 1.33.0 picomatch: 4.0.7 @@ -5822,7 +5822,7 @@ snapshots: rolldown: 1.2.6 tinyglobby: 0.2.17 optionalDependencies: - '@types/node': 26.4.0 + '@types/node': 26.4.1 fsevents: 2.3.3 terser: 5.51.2 diff --git a/interface/src/app/main/types.ts b/interface/src/app/main/types.ts index 5cced48dd..70d91b29d 100644 --- a/interface/src/app/main/types.ts +++ b/interface/src/app/main/types.ts @@ -39,7 +39,6 @@ export interface Settings { eth_power: number; eth_phy_addr: number; eth_clock_mode: number; - eth_10mbit: boolean; platform: string; modbus_enabled: boolean; modbus_port: number; diff --git a/interface/src/app/settings/ApplicationSettings.tsx b/interface/src/app/settings/ApplicationSettings.tsx index 1375340af..d9626d41b 100644 --- a/interface/src/app/settings/ApplicationSettings.tsx +++ b/interface/src/app/settings/ApplicationSettings.tsx @@ -820,18 +820,6 @@ const ApplicationSettings = () => { )} - {data.phy_type !== 0 && ( - - } - label="Force 10Mbit half-duplex" - /> - )} )} diff --git a/interface/src/app/settings/network/NetworkSettings.tsx b/interface/src/app/settings/network/NetworkSettings.tsx index ab6f4b503..350cc2e98 100644 --- a/interface/src/app/settings/network/NetworkSettings.tsx +++ b/interface/src/app/settings/network/NetworkSettings.tsx @@ -22,6 +22,7 @@ import { import * as NetworkApi from 'api/network'; import { API } from 'api/app'; +import { readSystemStatus } from 'api/system'; import { updateState, useRequest } from 'alova/client'; import type { APIcall } from 'app/main/types'; @@ -50,6 +51,8 @@ import { isNetworkOpen, networkSecurityMode } from './WiFiNetworkSelector'; const NetworkSettings = () => { const { LL } = useI18nContext(); + const { data: hardwareData } = useRequest(readSystemStatus); + const { selectedNetwork, deselectNetwork } = useContext(WiFiConnectionContext); const [initialized, setInitialized] = useState(false); @@ -92,7 +95,8 @@ const NetworkSettings = () => { nosleep: true, enableMDNS: true, enableCORS: false, - CORSOrigin: '*' + CORSOrigin: '*', + eth_10mbit: current_data ? current_data.eth_10mbit : false }) ); } @@ -136,7 +140,7 @@ const NetworkSettings = () => { }; const content = () => { - if (!data) { + if (!data || !hardwareData) { return ; } @@ -246,6 +250,23 @@ const NetworkSettings = () => { } label={LL.NETWORK_LOW_BAND()} /> + {hardwareData.esp_platform === 'ESP32' && ( + <> + + Ethernet + + + } + label="Force 10Mbit half-duplex" + /> + + )} {LL.GENERAL_OPTIONS()} diff --git a/interface/src/types/network.ts b/interface/src/types/network.ts index 9aef2621b..94e7a2984 100644 --- a/interface/src/types/network.ts +++ b/interface/src/types/network.ts @@ -54,6 +54,7 @@ export interface NetworkSettingsType { enableMDNS: boolean; enableCORS: boolean; CORSOrigin: string; + eth_10mbit: boolean; [key: string]: unknown; } diff --git a/lib_standalone/ESP32React.h b/lib_standalone/ESP32React.h index d3bd07d92..47b889105 100644 --- a/lib_standalone/ESP32React.h +++ b/lib_standalone/ESP32React.h @@ -31,6 +31,7 @@ class DummySettings { // SYSTEM bool bandwidth20 = false; bool nosleep = true; + bool eth_10mbit = false; // MQTT uint16_t publish_time = 10; diff --git a/mock-api/restServer.ts b/mock-api/restServer.ts index 842ae4147..de1fce771 100644 --- a/mock-api/restServer.ts +++ b/mock-api/restServer.ts @@ -58,7 +58,6 @@ let settings = { eth_power: 15, eth_phy_addr: 0, eth_clock_mode: 1, - eth_10mbit: false, led_type: 0, platform: 'ESP32', modbus_enabled: false, @@ -96,9 +95,9 @@ let system_status = { // network_status: 10, // ethernet connected // network_status: 6, // wifi disconnected wifi_rssi: -41, - esp_platform: 'ESP32S3', + esp_platform: 'ESP32', build_flags: 'DEMO', - cpu_type: 'ESP32-S3', + cpu_type: 'ESP32', cpu_rev: 0, cpu_cores: 2, cpu_freq_mhz: 240, @@ -203,8 +202,8 @@ system_status.partitions[0].version = THIS_VERSION; // app0 // set the ESP platform - using ESP32 will disable OTA and automatic version downloading let emulate_esp: string; -emulate_esp = 'ESP32S3'; -// emulate_esp = 'ESP32'; +// emulate_esp = 'ESP32S3'; +emulate_esp = 'ESP32'; switch (emulate_esp) { // ESP32 4MB @@ -330,10 +329,10 @@ function updateMask(entity: any, de: any, dd: any) { const old_custom_name = dd.nodes[dd_objIndex].cn; console.log( 'comparing names, old (' + - old_custom_name + - ') with new (' + - new_custom_name + - ')' + old_custom_name + + ') with new (' + + new_custom_name + + ')' ); if (old_custom_name !== new_custom_name) { changed = true; @@ -450,9 +449,9 @@ function upgradeImportantMessages(version: string) { console.log( 'upgradeImportantMessageType: version=' + - version + - ' type=' + - upgradeImportantMessageType_n + version + + ' type=' + + upgradeImportantMessageType_n ); return { upgradeImportantMessageType: upgradeImportantMessageType_n }; } @@ -503,17 +502,17 @@ function get_versions() { console.log( 'getVersions: current=' + - THIS_VERSION + - ' stable=' + - LATEST_STABLE_VERSION + - ' (upgradeable=' + - (STABLE_VERSION_IS_UPGRADEABLE ? 'YES' : 'NO') + - ') dev=' + - LATEST_DEV_VERSION + - ' (upgradeable=' + - (DEV_VERSION_IS_UPGRADEABLE ? 'YES' : 'NO') + - ')' + - (MOCK_OFFLINE ? ' [offline]' : '') + THIS_VERSION + + ' stable=' + + LATEST_STABLE_VERSION + + ' (upgradeable=' + + (STABLE_VERSION_IS_UPGRADEABLE ? 'YES' : 'NO') + + ') dev=' + + LATEST_DEV_VERSION + + ' (upgradeable=' + + (DEV_VERSION_IS_UPGRADEABLE ? 'YES' : 'NO') + + ')' + + (MOCK_OFFLINE ? ' [offline]' : '') ); return data; } @@ -583,6 +582,7 @@ let network_settings = { enableMDNS: true, enableCORS: false, CORSOrigin: '*', + eth_10mbit: false, local_ip: '', gateway_ip: '', subnet_mask: '', diff --git a/src/ESP32React/NetworkSettingsService.cpp b/src/ESP32React/NetworkSettingsService.cpp index 7a252f979..1b5ea05f5 100644 --- a/src/ESP32React/NetworkSettingsService.cpp +++ b/src/ESP32React/NetworkSettingsService.cpp @@ -24,6 +24,7 @@ void NetworkSettings::read(NetworkSettings & settings, JsonObject root) { root["enableCORS"] = settings.enableCORS; root["CORSOrigin"] = settings.CORSOrigin; root["tx_power"] = settings.tx_power; + root["eth_10mbit"] = settings.eth_10mbit; // extended settings JsonUtils::writeIP(root, "local_ip", settings.localIP); @@ -51,6 +52,7 @@ StateUpdateResult NetworkSettings::update(JsonObject root, NetworkSettings & set settings.enableMDNS = root["enableMDNS"] | true; settings.enableCORS = root["enableCORS"]; settings.CORSOrigin = root["CORSOrigin"] | "*"; + settings.eth_10mbit = root["eth_10mbit"]; // extended settings JsonUtils::readIP(root, "local_ip", settings.localIP); diff --git a/src/ESP32React/NetworkSettingsService.h b/src/ESP32React/NetworkSettingsService.h index 91fd7d6ec..e3dd58d7e 100644 --- a/src/ESP32React/NetworkSettingsService.h +++ b/src/ESP32React/NetworkSettingsService.h @@ -39,6 +39,7 @@ class NetworkSettings { bool enableMDNS = true; bool enableCORS = false; String CORSOrigin = "*"; + bool eth_10mbit = false; // force 10BASE-T half-duplex, no auto-negotiation // optional configuration for static IP address IPAddress localIP; diff --git a/src/core/network.cpp b/src/core/network.cpp index 3f5b4cd52..f99800eaa 100644 --- a/src/core/network.cpp +++ b/src/core/network.cpp @@ -49,15 +49,15 @@ void Network::begin() { nosleep_ = settings.nosleep; tx_power_ = settings.tx_power; bssid_ = settings.bssid; + eth_10mbit_ = settings.eth_10mbit; }); - // read Ethernet settings + // read Ethernet hardware settings EMSESP::webSettingsService.read([&](WebSettings & settings) { phy_type_ = settings.phy_type; eth_power_ = settings.eth_power; eth_phy_addr_ = settings.eth_phy_addr; eth_clock_mode_ = settings.eth_clock_mode; - eth_10mbit_ = settings.eth_10mbit; }); // get Access Point settings diff --git a/src/web/WebSettingsService.cpp b/src/web/WebSettingsService.cpp index abdb80b00..e46d1e093 100644 --- a/src/web/WebSettingsService.cpp +++ b/src/web/WebSettingsService.cpp @@ -79,7 +79,6 @@ void WebSettings::read(WebSettings & settings, JsonObject root) { root["eth_power"] = settings.eth_power; root["eth_phy_addr"] = settings.eth_phy_addr; root["eth_clock_mode"] = settings.eth_clock_mode; - root["eth_10mbit"] = settings.eth_10mbit; root["modbus_enabled"] = settings.modbus_enabled; root["modbus_port"] = settings.modbus_port; root["modbus_max_clients"] = settings.modbus_max_clients; @@ -121,7 +120,6 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) { settings.eth_power = root["eth_power"]; settings.eth_phy_addr = root["eth_phy_addr"]; settings.eth_clock_mode = root["eth_clock_mode"]; - settings.eth_10mbit = root["eth_10mbit"]; settings.led_type = root["led_type"]; // 1 = RGB-LED reset_flags(); @@ -147,7 +145,6 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) { if (settings.phy_type != PHY_type::PHY_TYPE_NONE) { check_flag(original_settings.eth_power, settings.eth_power, ChangeFlags::RESTART); check_flag(original_settings.eth_clock_mode, settings.eth_clock_mode, ChangeFlags::RESTART); - check_flag(original_settings.eth_10mbit, settings.eth_10mbit, ChangeFlags::RESTART); if (settings.eth_power != -1) { // Ethernet Power -1 means disabled EMSESP::system_.remove_gpio(settings.eth_power, true); } diff --git a/src/web/WebSettingsService.h b/src/web/WebSettingsService.h index 1f6398aa9..d8a600f81 100644 --- a/src/web/WebSettingsService.h +++ b/src/web/WebSettingsService.h @@ -119,7 +119,6 @@ class WebSettings { int8_t eth_power; // -1 means disabled uint8_t eth_phy_addr; uint8_t eth_clock_mode; - bool eth_10mbit; // force 10BASE-T half-duplex, no auto-negotiation bool developer_mode; // developer mode bool disable_reset; // disable reset