diff --git a/CHANGELOG_LATEST.md b/CHANGELOG_LATEST.md index f63cac508..89a912bdd 100644 --- a/CHANGELOG_LATEST.md +++ b/CHANGELOG_LATEST.md @@ -12,6 +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 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 @@ -36,4 +37,5 @@ This release is based on the latest Espressif/Arduino core version 3. It brings - changes to the Dialogs in Dashboard page, removed the run icon in the Commands page. Renamed Execute to Run. - set `None` for undefined values in HA `val_tpl` - changes in WebUI - remove multiple calls systemInfo endpoint, Vewrsion pages checks for internet connection [#3195](https://github.com/emsesp/EMS-ESP32/pull/3195) +- multiple optimization in network, power down WiFi when Ethernet and WiFi nosleep is instant when selected [#3213](https://github.com/emsesp/EMS-ESP32/pull/3213) diff --git a/data/pre_load.json b/data/pre_load.json index 24e5fea66..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, diff --git a/interface/package.json b/interface/package.json index 8697fa935..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", @@ -54,9 +54,9 @@ "rollup-plugin-visualizer": "^7.1.1", "terser": "^5.51.2", "typescript": "^6.0.3", - "typescript-eslint": "^8.68.0", + "typescript-eslint": "^8.69.0", "vite": "^8.2.2", "vite-plugin-imagemin": "^0.6.1" }, - "packageManager": "pnpm@11.24.0+sha512.bd27e345e976dcb0be0b7a1228217b049a817e21b1f355c90dbe7dc46671895a8bc1e6d06c24554505ea93ea0b45f489a27ec1bfbc8de6a9659fca0f16fa0000" + "packageManager": "pnpm@11.25.0+sha512.5cde925b4f075f725eb71fbae18a42ffe784524789f19b61c731cb8721ec28aaee160e01a8d5af4fedb2a42cdbf300efe23db356b0d4a17b4d63e11f8ab7c956" } diff --git a/interface/pnpm-lock.yaml b/interface/pnpm-lock.yaml index e19a0133d..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 @@ -97,14 +97,14 @@ importers: specifier: ^6.0.3 version: 6.0.3 typescript-eslint: - specifier: ^8.68.0 - version: 8.68.0(eslint@10.9.1(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3) + specifier: ^8.69.0 + 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==} @@ -696,63 +696,63 @@ packages: '@types/svgo@2.6.4': resolution: {integrity: sha512-l4cmyPEckf8moNYHdJ+4wkHvFxjyW6ulm9l4YGaOxeyBWPhBOT0gvni1InpFPdzx1dKf/2s62qGITwxNWnPQng==} - '@typescript-eslint/eslint-plugin@8.68.0': - resolution: {integrity: sha512-WASHDpCm6qO5jj9g1a+8NiW5+GCkAyLReR56/4VruYmNgfUmqpxOfZ2Yfb8xGfJPWv5Qi6LSD8sXdces3vbp/Q==} + '@typescript-eslint/eslint-plugin@8.69.0': + resolution: {integrity: sha512-t5jQTKPIgVW1PE6dR6H6Qz5gm8zjMlX5/2gRaOGd9eO6V7J+tQc6iWKukEe7dY8u9HyYasQ0yfF0/FSSTEO2gA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.68.0 + '@typescript-eslint/parser': ^8.69.0 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/parser@8.68.0': - resolution: {integrity: sha512-fHq2VC1kpyYfvEcbiMjOpySY4WS7voEp89yAThrHRX5sm9j2lzYppCb2umFMEed4fWcyeLjHxrz0mpjNBaBxMQ==} + '@typescript-eslint/parser@8.69.0': + resolution: {integrity: sha512-l4b0DhWioGg6Gt2ebGlvfkFMOjRsauxtsnDRwUSRX1qHq3HdTfQHV8wW9zEXeciai6HfeaKOedQn2Zoofx3WBw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/project-service@8.68.0': - resolution: {integrity: sha512-5GQtWZCXFcFYux955pvoS02WLc49pXNlvIxocKjS0clvwo3in1RdlzVKyiqQH9vE5AKWFLTaUgeQkOrTS+0Qxw==} + '@typescript-eslint/project-service@8.69.0': + resolution: {integrity: sha512-yi4obFrHMmnsesWehHbkg9zMA7Jt8cXT+mKM08G999pH1yT6nqgsHx7MYm0uY1wAj8CqiBXYRJ7WAT0QdQHQXg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/scope-manager@8.68.0': - resolution: {integrity: sha512-T5eXpcaJNg8bhjHJ8Rjp68Vq/QBteYtTKY8TZqVNPaUbuz0f6jI9t6aDkylwvalpAB9XTTFeFOjrjXAZ3YvmVA==} + '@typescript-eslint/scope-manager@8.69.0': + resolution: {integrity: sha512-ewfspqWvSxKSOaplqAUNbaSFO0eB6w1EtQ+esfYFRm3614Ty4uNtExkcbgd6nWsXphbqKyf9ZYdbZdv2xEoWEQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.68.0': - resolution: {integrity: sha512-F7zrGQfiJHojPwi8vhxZQC1tWtJzvL74cK/nqri2lk8YUXvYaYwl263xOJ69jDWPUk1hmcdoayFwk9lX09npVw==} + '@typescript-eslint/tsconfig-utils@8.69.0': + resolution: {integrity: sha512-xNqK7YTDZsLniQMV/4rpFR8Z5JlqeRvVjuG1YgF/mdPVH84HSD19L8CczMA0qg2RfwEV231GHH3VnToJDo4MfQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.68.0': - resolution: {integrity: sha512-X77zqoY1EjeWGs/0JNxeaMfp5C5lIz4Tw8y66F1Ne8Faq6g424sBNYM6xBAqElfGZPLpWS+CZAp0DXyKDzWiHg==} + '@typescript-eslint/type-utils@8.69.0': + resolution: {integrity: sha512-ZfoJAVg3JZndQEpEl9petVlxau3lRuElc4HRMuAlLCf8to04/iHz692RUSNmXKDjEuJmIL+KZ2/BsOcBc16dsA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/types@8.68.0': - resolution: {integrity: sha512-9RnpsGJjrAllCMefGVVsImJM24YurhC0Q1h4UbvivtvOqXmR/vEJge2OoE++z9m6hyg8T1Q8t5SNT6tHSbrxcg==} + '@typescript-eslint/types@8.69.0': + resolution: {integrity: sha512-K3VrubUPhlo9VDBS6QdI8YB5j7ClpqLRdefcz6PFrhnwicehBweqQ9Evhl4l+FYz0HdDmMqIiSX0aldGRYtDCA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.68.0': - resolution: {integrity: sha512-OKKsD0tYmoNiU5PW2zehO1yO56jYOm1ShYlxon/Z0SJNidAkdVg86eg9ruRuoXf8xfnuWZGbwDsStkoXbZtIIA==} + '@typescript-eslint/typescript-estree@8.69.0': + resolution: {integrity: sha512-AdFkgqck3Vudb/kWnxlyafU/4aBhHrbQ9locP2N4psXTy5mOBg0SHJumnLvx7r6g1gV4DKvUFwV2nJZBoqOD8w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@8.68.0': - resolution: {integrity: sha512-PB5gJMMOg0Q5P1tsgWtEAqQacJXq0qEqRHDX/YJ4FaTMLfZPpHB3gjl2EJuiZyPABxmj4ZQYiY9m1bdAJ5y7tQ==} + '@typescript-eslint/utils@8.69.0': + resolution: {integrity: sha512-tUbx60BBqQa31kXF5MCsOOLL5E/WzUuxIn7YpAvq+eaUlqvk8/NXnXMBNAdLCr0icjkzem7iUA5QqWHe/hJ1aw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/visitor-keys@8.68.0': - resolution: {integrity: sha512-YR65gGdGvTUAWLldC3xLOvOzamdGzB4A5/N8rehEaHs3Zvoe39BhgY+u0SPch1OvrVTfLcc55wsSgK2NcnTS/A==} + '@typescript-eslint/visitor-keys@8.69.0': + resolution: {integrity: sha512-+rmdgPA+EXkNgKYvHvFfhrs35utXbwaC5PGpDquSXcoXQDKUA5UjV0LmTucG/4JXkM31BTu4TilHtrN8IVBe8w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} acorn-jsx@5.3.2: @@ -1689,8 +1689,8 @@ packages: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} - ignore@7.0.6: - resolution: {integrity: sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==} + ignore@7.0.8: + resolution: {integrity: sha512-YYNsSlXBjMk92SKnkwvB5LOVSa6OznlFUGcsvrFgNJbJCd0M1XKeFVRc8ZByeCqz32FivYNHJVooLmdqrmvp/Q==} engines: {node: '>= 4'} imagemin-gifsicle@7.0.0: @@ -2816,8 +2816,8 @@ packages: peerDependencies: typescript: '>=3.5.1' - typescript-eslint@8.68.0: - resolution: {integrity: sha512-MHy0Y0ynqeEbx/S45+i/bBssdy3X6KNBfmJAP35GrgtNxu2TQ5K5xsFDhAnmsq1jvpdoZOPG1LGtJo0HWqYCrQ==} + typescript-eslint@8.69.0: + resolution: {integrity: sha512-B3MltX0VqjUBNEe3b3sSuiRbfa6XrfHFtBiPamjT5AsW/dfq+y+bc0wyuS9DxAS1LyzCxRp2+rxzpLUvqM2BvA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 @@ -2988,8 +2988,8 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - zimmerframe@1.1.4: - resolution: {integrity: sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==} + zimmerframe@1.1.5: + resolution: {integrity: sha512-msJxIvYDYcoNL+PJsu+7qmpDWsYmAxTY+2TNYXXF0hzBzBk0BMecOqDOG/EckUoKCuKwObfbugIl8QpqHDXeFA==} snapshots: @@ -3394,20 +3394,20 @@ 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)) - zimmerframe: 1.1.4 + 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 - rollup @@ -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,63 +3590,63 @@ 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.68.0(@typescript-eslint/parser@8.68.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)': + '@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: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.68.0(eslint@10.9.1(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3) - '@typescript-eslint/scope-manager': 8.68.0 - '@typescript-eslint/type-utils': 8.68.0(eslint@10.9.1(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3) - '@typescript-eslint/utils': 8.68.0(eslint@10.9.1(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3) - '@typescript-eslint/visitor-keys': 8.68.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) + '@typescript-eslint/scope-manager': 8.69.0 + '@typescript-eslint/type-utils': 8.69.0(eslint@10.9.1(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3) + '@typescript-eslint/utils': 8.69.0(eslint@10.9.1(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.69.0 eslint: 10.9.1(supports-color@10.2.2) - ignore: 7.0.6 + ignore: 7.0.8 natural-compare: 1.4.0 ts-api-utils: 2.5.0(typescript@6.0.3) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.68.0(eslint@10.9.1(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)': + '@typescript-eslint/parser@8.69.0(eslint@10.9.1(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)': dependencies: - '@typescript-eslint/scope-manager': 8.68.0 - '@typescript-eslint/types': 8.68.0 - '@typescript-eslint/typescript-estree': 8.68.0(supports-color@10.2.2)(typescript@6.0.3) - '@typescript-eslint/visitor-keys': 8.68.0 + '@typescript-eslint/scope-manager': 8.69.0 + '@typescript-eslint/types': 8.69.0 + '@typescript-eslint/typescript-estree': 8.69.0(supports-color@10.2.2)(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.69.0 debug: 4.4.3(supports-color@10.2.2) eslint: 10.9.1(supports-color@10.2.2) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.68.0(supports-color@10.2.2)(typescript@6.0.3)': + '@typescript-eslint/project-service@8.69.0(supports-color@10.2.2)(typescript@6.0.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.68.0(typescript@6.0.3) - '@typescript-eslint/types': 8.68.0 + '@typescript-eslint/tsconfig-utils': 8.69.0(typescript@6.0.3) + '@typescript-eslint/types': 8.69.0 debug: 4.4.3(supports-color@10.2.2) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.68.0': + '@typescript-eslint/scope-manager@8.69.0': dependencies: - '@typescript-eslint/types': 8.68.0 - '@typescript-eslint/visitor-keys': 8.68.0 + '@typescript-eslint/types': 8.69.0 + '@typescript-eslint/visitor-keys': 8.69.0 - '@typescript-eslint/tsconfig-utils@8.68.0(typescript@6.0.3)': + '@typescript-eslint/tsconfig-utils@8.69.0(typescript@6.0.3)': dependencies: typescript: 6.0.3 - '@typescript-eslint/type-utils@8.68.0(eslint@10.9.1(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)': + '@typescript-eslint/type-utils@8.69.0(eslint@10.9.1(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)': dependencies: - '@typescript-eslint/types': 8.68.0 - '@typescript-eslint/typescript-estree': 8.68.0(supports-color@10.2.2)(typescript@6.0.3) - '@typescript-eslint/utils': 8.68.0(eslint@10.9.1(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3) + '@typescript-eslint/types': 8.69.0 + '@typescript-eslint/typescript-estree': 8.69.0(supports-color@10.2.2)(typescript@6.0.3) + '@typescript-eslint/utils': 8.69.0(eslint@10.9.1(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3) debug: 4.4.3(supports-color@10.2.2) eslint: 10.9.1(supports-color@10.2.2) ts-api-utils: 2.5.0(typescript@6.0.3) @@ -3654,14 +3654,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.68.0': {} + '@typescript-eslint/types@8.69.0': {} - '@typescript-eslint/typescript-estree@8.68.0(supports-color@10.2.2)(typescript@6.0.3)': + '@typescript-eslint/typescript-estree@8.69.0(supports-color@10.2.2)(typescript@6.0.3)': dependencies: - '@typescript-eslint/project-service': 8.68.0(supports-color@10.2.2)(typescript@6.0.3) - '@typescript-eslint/tsconfig-utils': 8.68.0(typescript@6.0.3) - '@typescript-eslint/types': 8.68.0 - '@typescript-eslint/visitor-keys': 8.68.0 + '@typescript-eslint/project-service': 8.69.0(supports-color@10.2.2)(typescript@6.0.3) + '@typescript-eslint/tsconfig-utils': 8.69.0(typescript@6.0.3) + '@typescript-eslint/types': 8.69.0 + '@typescript-eslint/visitor-keys': 8.69.0 debug: 4.4.3(supports-color@10.2.2) minimatch: 10.2.6 semver: 7.8.5 @@ -3671,20 +3671,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.68.0(eslint@10.9.1(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)': + '@typescript-eslint/utils@8.69.0(eslint@10.9.1(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)': dependencies: '@eslint-community/eslint-utils': 4.10.1(eslint@10.9.1(supports-color@10.2.2)) - '@typescript-eslint/scope-manager': 8.68.0 - '@typescript-eslint/types': 8.68.0 - '@typescript-eslint/typescript-estree': 8.68.0(supports-color@10.2.2)(typescript@6.0.3) + '@typescript-eslint/scope-manager': 8.69.0 + '@typescript-eslint/types': 8.69.0 + '@typescript-eslint/typescript-estree': 8.69.0(supports-color@10.2.2)(typescript@6.0.3) eslint: 10.9.1(supports-color@10.2.2) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.68.0': + '@typescript-eslint/visitor-keys@8.69.0': dependencies: - '@typescript-eslint/types': 8.68.0 + '@typescript-eslint/types': 8.69.0 eslint-visitor-keys: 5.0.1 acorn-jsx@5.3.2(acorn@8.18.0): @@ -4707,7 +4707,7 @@ snapshots: ignore@5.3.2: {} - ignore@7.0.6: {} + ignore@7.0.8: {} imagemin-gifsicle@7.0.0: dependencies: @@ -5724,12 +5724,12 @@ snapshots: dependencies: typescript: 6.0.3 - typescript-eslint@8.68.0(eslint@10.9.1(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3): + typescript-eslint@8.69.0(eslint@10.9.1(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.68.0(@typescript-eslint/parser@8.68.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) - '@typescript-eslint/parser': 8.68.0(eslint@10.9.1(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3) - '@typescript-eslint/typescript-estree': 8.68.0(supports-color@10.2.2)(typescript@6.0.3) - '@typescript-eslint/utils': 8.68.0(eslint@10.9.1(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3) + '@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) + '@typescript-eslint/parser': 8.69.0(eslint@10.9.1(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3) + '@typescript-eslint/typescript-estree': 8.69.0(supports-color@10.2.2)(typescript@6.0.3) + '@typescript-eslint/utils': 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) typescript: 6.0.3 transitivePeerDependencies: @@ -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 @@ -5896,4 +5896,4 @@ snapshots: yocto-queue@0.1.0: {} - zimmerframe@1.1.4: {} + zimmerframe@1.1.5: {} 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/package.json b/mock-api/package.json index 66cc57780..2ec07a076 100644 --- a/mock-api/package.json +++ b/mock-api/package.json @@ -18,5 +18,5 @@ "@trivago/prettier-plugin-sort-imports": "^6.0.2", "prettier": "^3.9.6" }, - "packageManager": "pnpm@11.24.0+sha512.bd27e345e976dcb0be0b7a1228217b049a817e21b1f355c90dbe7dc46671895a8bc1e6d06c24554505ea93ea0b45f489a27ec1bfbc8de6a9659fca0f16fa0000" + "packageManager": "pnpm@11.25.0+sha512.5cde925b4f075f725eb71fbae18a42ffe784524789f19b61c731cb8721ec28aaee160e01a8d5af4fedb2a42cdbf300efe23db356b0d4a17b4d63e11f8ab7c956" } diff --git a/mock-api/restServer.ts b/mock-api/restServer.ts index 919620cb9..de1fce771 100644 --- a/mock-api/restServer.ts +++ b/mock-api/restServer.ts @@ -95,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, @@ -202,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 @@ -329,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; @@ -449,9 +449,9 @@ function upgradeImportantMessages(version: string) { console.log( 'upgradeImportantMessageType: version=' + - version + - ' type=' + - upgradeImportantMessageType_n + version + + ' type=' + + upgradeImportantMessageType_n ); return { upgradeImportantMessageType: upgradeImportantMessageType_n }; } @@ -502,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; } @@ -582,6 +582,7 @@ let network_settings = { enableMDNS: true, enableCORS: false, CORSOrigin: '*', + eth_10mbit: false, local_ip: '', gateway_ip: '', subnet_mask: '', diff --git a/project-words.txt b/project-words.txt index 242eb64b1..2aa5d4e27 100644 --- a/project-words.txt +++ b/project-words.txt @@ -1345,4 +1345,6 @@ Sumr eraseap roomtempoffset dhcpc -wifioff \ No newline at end of file +wifioff +autonegotiation +Mbit \ No newline at end of file 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/main.cpp b/src/core/main.cpp index 68130146c..d6597b301 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -28,4 +28,7 @@ void setup() { void loop() { application.loop(); +#ifndef EMSESP_STANDALONE + delay(1); // block for a tick so the idle task gets to run and the core can clock-gate +#endif } diff --git a/src/core/network.cpp b/src/core/network.cpp index b62baeb64..f99800eaa 100644 --- a/src/core/network.cpp +++ b/src/core/network.cpp @@ -49,9 +49,10 @@ 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; @@ -78,39 +79,16 @@ void Network::begin() { phase_ = initialPhase(); - // Initialise WiFi once when the Network service starts. - // persistent(false) keeps credentials in RAM so we don't auto-join leftover NVS config. - WiFi.persistent(false); - WiFi.setAutoReconnect(false); - WiFi.mode(WIFI_STA); + startWiFiRadio(); - // Keep the radio up. disconnect(wifioff=true) maps to STA.end() -> esp_wifi_stop() - if (WiFi.STA.started()) { - WiFi.disconnect(false, true); // drop leftover association, wipe RAM config +#if CONFIG_IDF_TARGET_ESP32 + // Ethernet is switched off but the board still has a PHY wired up. Hold its power/oscillator + // enable low so an unused LAN8720 isn't left clocked and burning current for the whole uptime. + if (phy_type_ == PHY_type::PHY_TYPE_NONE && eth_power_ != -1) { + pinMode(eth_power_, OUTPUT); + digitalWrite(eth_power_, LOW); } - - WiFi.setScanMethod(WIFI_ALL_CHANNEL_SCAN); - WiFi.setHostname(hostname_.c_str()); // updates shared default_hostname buffer - WiFi.enableSTA(true); // no-op if already STA; recreates netif after a full off - WiFi.STA.setHostname(hostname_.c_str()); // pushes to esp_netif_set_hostname - WiFi.enableIPv6(true); - if (staticIPConfig_) { - WiFi.config(localIP_, gatewayIP_, subnetMask_, dnsIP1_, dnsIP2_); // configure for static IP - } - - // www.esp32.com/viewtopic.php?t=12055 - if (bandwidth20_) { - esp_wifi_set_bandwidth(static_cast(ESP_IF_WIFI_STA), WIFI_BW_HT20); - } else { - esp_wifi_set_bandwidth(static_cast(ESP_IF_WIFI_STA), WIFI_BW_HT40); - } - if (nosleep_) { - WiFi.setSleep(false); // turn off sleep - WIFI_PS_NONE - } - - // scan settings give connect issues since arduino 2.0.14 and arduino 3.x.x with some wifi systems - // WiFi.setScanMethod(WIFI_ALL_CHANNEL_SCAN); // default is FAST_SCAN - // WiFi.setSortMethod(WIFI_CONNECT_AP_BY_SIGNAL); // is default, no need to set +#endif // avoid duplicate registration, so register the lambdas only once across the lifetime of this Network instance if (!wifi_events_registered_) { @@ -326,6 +304,10 @@ void Network::checkConnection() { network_iface_ = NetIface::NONE; if (lost_iface == NetIface::ETHERNET) { LOG_WARNING("Ethernet connection lost"); + // restore the radio now so the WiFi and AP fallbacks have something to work with + if (wifi_radio_off_) { + startWiFiRadio(); + } return; } begin(); @@ -502,6 +484,59 @@ const char * Network::disconnectReason([[maybe_unused]] uint8_t code) { return ""; } +// Bring up the STA interface and apply all the radio-level settings to it +// Safe to call repeatedly - enableSTA() is a no-op when the STA is already running, and recreates the netif after stopWiFiRadio() has torn it down +void Network::startWiFiRadio() { +#ifndef EMSESP_STANDALONE + WiFi.persistent(false); // keep credentials in RAM so we don't auto-join leftover NVS config + WiFi.setAutoReconnect(false); + WiFi.mode(WIFI_STA); + + // Keep the radio up. disconnect(wifioff=true) maps to STA.end() -> esp_wifi_stop() + if (WiFi.STA.started()) { + WiFi.disconnect(false, true); // drop leftover association, wipe RAM config + } + + // scan settings give connect issues since arduino 2.0.14 and arduino 3.x.x with some wifi systems + WiFi.setScanMethod(WIFI_ALL_CHANNEL_SCAN); // default is FAST_SCAN + WiFi.setHostname(hostname_.c_str()); // updates shared default_hostname buffer + WiFi.enableSTA(true); // no-op if already STA; recreates netif after a full off + WiFi.STA.setHostname(hostname_.c_str()); // pushes to esp_netif_set_hostname + WiFi.enableIPv6(true); + if (staticIPConfig_) { + WiFi.config(localIP_, gatewayIP_, subnetMask_, dnsIP1_, dnsIP2_); // configure for static IP + } + + // www.esp32.com/viewtopic.php?t=12055 + if (bandwidth20_) { + esp_wifi_set_bandwidth(static_cast(ESP_IF_WIFI_STA), WIFI_BW_HT20); + } else { + esp_wifi_set_bandwidth(static_cast(ESP_IF_WIFI_STA), WIFI_BW_HT40); + } + if (nosleep_) { + WiFi.setSleep(false); // turn off sleep - WIFI_PS_NONE + } else { + WiFi.setSleep(true); // WIFI_PS_MIN_MODEM + } + + wifi_radio_off_ = false; +#endif +} + +// Power down the WiFi radio completely (esp_wifi_stop), used when Ethernet is carrying the traffic. +// An idle STA still keeps the receiver powered. It also unloads the driver's DMA buffer pool of around 20KB +void Network::stopWiFiRadio() { +#ifndef EMSESP_STANDALONE + if (wifi_radio_off_) { + return; + } + WiFi.mode(WIFI_OFF); + wifi_radio_off_ = true; + wifi_connect_pending_ = false; + LOG_DEBUG("Powering down WiFi radio, Ethernet is active"); +#endif +} + // WiFi management void Network::startWIFI() { #ifndef EMSESP_STANDALONE @@ -510,6 +545,11 @@ void Network::startWIFI() { return; } + // the radio was powered down while Ethernet was up, so bring it back before trying to associate + if (wifi_radio_off_) { + startWiFiRadio(); + } + // exit if WiFi or Ethernet is already connected, or if we have no SSID or another Wifi.begin() is already in progress if (WiFi.isConnected() || ssid_.isEmpty() || ethernet_connected() || wifi_connect_pending_) { return; @@ -529,14 +569,7 @@ void Network::startWIFI() { } #if CONFIG_IDF_TARGET_ESP32 && !defined(EMSESP_STANDALONE) -// Unlike WiFi, which stamps the hostname onto the STA netif as it is created, the Arduino ETH class -// leaves it unset, so lwIP falls back to CONFIG_LWIP_LOCAL_HOSTNAME ("tasmota" in the SDK we build -// against). esp_eth_start() polls the PHY synchronously, so on a warm reboot where the link never -// dropped the DHCP DISCOVER can go out before ETH.begin() has even returned. This handler is -// registered ahead of the esp_netif glue and therefore runs first, applying the hostname before the -// netif is handed to lwIP. static char eth_hostname[33] = {0}; - static void ethApplyHostname(void * /*arg*/, esp_event_base_t /*base*/, int32_t /*event_id*/, void * /*event_data*/) { if (eth_hostname[0] != '\0' && ETH.netif() != nullptr) { esp_netif_set_hostname(ETH.netif(), eth_hostname); @@ -555,11 +588,7 @@ void Network::startEthernet() { return; } - // The driver is installed once and then left alone. Re-running the bring-up on a live interface - // tears it down behind our back: pinMode() on the PHY power pin hands the pin from the Ethernet - // bus back to GPIO, which fires the peripheral manager's deinit callback and calls ETH.end(), - // destroying the netif, its event group and the event handlers from the main loop task while the - // arduino_events task may be dispatching a link-up on the other core. + // Ensure the Ethernet driver is installed once and then left alone if (ethernet_started_ || ethernet_connect_pending_ || ethernet_connected()) { return; } @@ -610,6 +639,13 @@ void Network::startEthernet() { eth_hostname_handler_registered_ = true; } + // Forcing 10BASE-T roughly halves the PHY's power draw + if (eth_10mbit_) { + ETH.setAutoNegotiation(false); + ETH.setLinkSpeed(10); + ETH.setFullDuplex(false); + } + if (ETH.begin(type, eth_phy_addr_, 23, 18, eth_power_, (eth_clock_mode_t)eth_clock_mode_)) { // LOG_DEBUG("Ethernet module found - initialising"); ethernet_started_ = true; @@ -739,6 +775,11 @@ void Network::findNetworks() { stopAP(); } + // Ethernet is carrying the traffic so the STA is dead weight - shut the radio down. + if (network_iface_ == NetIface::ETHERNET) { + stopWiFiRadio(); + } + // count the number of restarts (for Wifi and Eth) if (juststopped_) { juststopped_ = false; @@ -823,6 +864,11 @@ void Network::startAP() { return; } + // the AP needs the radio, which may have been powered down while Ethernet was up + if (wifi_radio_off_) { + startWiFiRadio(); + } + if (!WiFi.softAPConfig(ap_localIP_, ap_gatewayIP_, ap_subnetMask_)) { LOG_DEBUG("softAPConfig failed"); return; diff --git a/src/core/network.h b/src/core/network.h index 13ae4ab41..d97320af0 100644 --- a/src/core/network.h +++ b/src/core/network.h @@ -186,6 +186,8 @@ class Network { void startAP(); void startWIFI(); void startEthernet(); + void startWiFiRadio(); + void stopWiFiRadio(); void setWiFiPower(uint8_t tx_power); const char * disconnectReason(uint8_t code); void stopAP(); @@ -216,6 +218,7 @@ class Network { bool ethernet_started_ = false; // ETH.begin() succeeded; the driver runs for the lifetime of the boot bool wifi_ever_connected_ = false; // set true once we've successfully obtained an IP bool ethernet_ever_connected_ = false; // set true once we've successfully obtained an IP + bool wifi_radio_off_ = false; // STA powered down because Ethernet is carrying the traffic // Network and AP settings bool enableMDNS_; @@ -236,6 +239,7 @@ class Network { int8_t eth_power_; uint8_t eth_phy_addr_; uint8_t eth_clock_mode_; + bool eth_10mbit_; // AP settings uint8_t ap_provisionMode_; diff --git a/src/emsesp_version.h b/src/emsesp_version.h index e7d93e24b..2bce065ab 100644 --- a/src/emsesp_version.h +++ b/src/emsesp_version.h @@ -1 +1 @@ -#define EMSESP_APP_VERSION "3.9.0-dev.6" +#define EMSESP_APP_VERSION "3.9.0-dev.7"