mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2026-05-02 04:05:14 +00:00
Compare commits
123 Commits
db2be70d66
...
core3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0e08334132 | ||
|
|
3d51acf9e7 | ||
|
|
fd6ea5ed7e | ||
|
|
d18e5b1f14 | ||
|
|
20327d817d | ||
|
|
051c332426 | ||
|
|
a09258325e | ||
|
|
61dca0cbda | ||
|
|
2bff299193 | ||
|
|
1329b13db3 | ||
|
|
9dd894f0fe | ||
|
|
30d1ae5642 | ||
|
|
79aceef382 | ||
|
|
a28e52210a | ||
|
|
08eb294213 | ||
|
|
888baed81a | ||
|
|
4de3955db2 | ||
|
|
25f08c7624 | ||
|
|
1e8013100c | ||
|
|
62c8f55568 | ||
|
|
c40d828749 | ||
|
|
84ad08887a | ||
|
|
ed0a678020 | ||
|
|
37107d8500 | ||
|
|
dde6a8c5db | ||
|
|
e2750b8572 | ||
|
|
acd23925b5 | ||
|
|
b0db054e11 | ||
|
|
51cea8e757 | ||
|
|
bbb086ea41 | ||
|
|
539e6ed080 | ||
|
|
1d33a26318 | ||
|
|
86a20fc97a | ||
|
|
d6e00c4534 | ||
|
|
a813d38108 | ||
|
|
685a49c212 | ||
|
|
2c8eb534af | ||
|
|
5210fab4cb | ||
|
|
49787d27f1 | ||
|
|
dfe7b46461 | ||
|
|
f8257de0dd | ||
|
|
3b3ecc9f1d | ||
|
|
84105acf5d | ||
|
|
def5173692 | ||
|
|
6b31fef1af | ||
|
|
c9c059ca65 | ||
|
|
4d3b31e5a1 | ||
|
|
51d90095aa | ||
|
|
16c0370443 | ||
|
|
67bb38dcf4 | ||
|
|
049231a36e | ||
|
|
349d6b7375 | ||
|
|
b72b368d3c | ||
|
|
7f9fd44a02 | ||
|
|
a400c5974c | ||
|
|
afca995fe5 | ||
|
|
81504fedc5 | ||
|
|
3da3345683 | ||
|
|
c6c2889306 | ||
|
|
b60f0d260a | ||
|
|
cd750e4777 | ||
|
|
4e5d503b35 | ||
|
|
bd09e17e49 | ||
|
|
835eb743bb | ||
|
|
69a129d80e | ||
|
|
434bf483fd | ||
|
|
2b8e170b40 | ||
|
|
dc9b95f3e7 | ||
|
|
1616b0da0a | ||
|
|
91c457b22b | ||
|
|
70c60647c7 | ||
|
|
c0bea66d27 | ||
|
|
ed7cc078ed | ||
|
|
60b7d6d795 | ||
|
|
947f29cca0 | ||
|
|
d2a13ec0da | ||
|
|
cc39ba409e | ||
|
|
ac9db6256e | ||
|
|
096f628d97 | ||
|
|
22312812bb | ||
|
|
3584975acb | ||
|
|
30b9ca4e6c | ||
|
|
7c6ff01ebe | ||
|
|
a54edcaf5b | ||
|
|
e446954844 | ||
|
|
4a2d0d6787 | ||
|
|
9725314135 | ||
|
|
e610f0d57f | ||
|
|
8244af2940 | ||
|
|
40f371d23b | ||
|
|
817b791e59 | ||
|
|
25a7aac360 | ||
|
|
37115a174d | ||
|
|
1397f81fd0 | ||
|
|
56365cb403 | ||
|
|
dfd245ee7b | ||
|
|
9c81e4b34d | ||
|
|
67676df131 | ||
|
|
a73b129596 | ||
|
|
4600d886b5 | ||
|
|
0fe45a2405 | ||
|
|
db87213242 | ||
|
|
5c3c010d5a | ||
|
|
c804cedd7a | ||
|
|
aa30ca99bf | ||
|
|
c0ca9d1069 | ||
|
|
5e79e1d57f | ||
|
|
8c732f9f1e | ||
|
|
5e94c2f636 | ||
|
|
64e5d29996 | ||
|
|
b320d8ded2 | ||
|
|
0be1b20996 | ||
|
|
6c55460622 | ||
|
|
d627404dc2 | ||
|
|
f317123c26 | ||
|
|
e4df1887b0 | ||
|
|
34142c3e85 | ||
|
|
6e7f8bdf02 | ||
|
|
3dd9fcfb58 | ||
|
|
35e2954b8b | ||
|
|
59aa63db0f | ||
|
|
7a41a190f8 | ||
|
|
6741232450 |
@@ -12,6 +12,7 @@ For more details go to [emsesp.org](https://emsesp.org/).
|
|||||||
- prometheus metrics for temperature/analog/scheduler/custom [#2962](https://github.com/emsesp/EMS-ESP32/issues/2962)
|
- prometheus metrics for temperature/analog/scheduler/custom [#2962](https://github.com/emsesp/EMS-ESP32/issues/2962)
|
||||||
- boiler pumpkick [#2965](https://github.com/emsesp/EMS-ESP32/discussions/2965)
|
- boiler pumpkick [#2965](https://github.com/emsesp/EMS-ESP32/discussions/2965)
|
||||||
- heatpump reset [#2933](https://github.com/emsesp/EMS-ESP32/issues/2933)
|
- heatpump reset [#2933](https://github.com/emsesp/EMS-ESP32/issues/2933)
|
||||||
|
- e-mail notification using ReadyMail Client
|
||||||
- 2.nd freshwater module (dhw4, dhw5) [#2991](https://github.com/emsesp/EMS-ESP32/issues/2991)
|
- 2.nd freshwater module (dhw4, dhw5) [#2991](https://github.com/emsesp/EMS-ESP32/issues/2991)
|
||||||
- full system backup and restore
|
- full system backup and restore
|
||||||
|
|
||||||
@@ -31,6 +32,8 @@ For more details go to [emsesp.org](https://emsesp.org/).
|
|||||||
- support `minflowtemp` and `baseflowtemp` [#2969](https://github.com/emsesp/EMS-ESP32/discussions/2969)
|
- support `minflowtemp` and `baseflowtemp` [#2969](https://github.com/emsesp/EMS-ESP32/discussions/2969)
|
||||||
- update version if it is 00.00 in first read [#2981](https://github.com/emsesp/EMS-ESP32/issues/2981)
|
- update version if it is 00.00 in first read [#2981](https://github.com/emsesp/EMS-ESP32/issues/2981)
|
||||||
- device class for % values [#2980](https://github.com/emsesp/EMS-ESP32/issues/2980)
|
- device class for % values [#2980](https://github.com/emsesp/EMS-ESP32/issues/2980)
|
||||||
|
- use tasmota core 2026.03.30
|
||||||
|
- secure mqtt uses ESP_SSLClient
|
||||||
- fetch telegrams: set length to fetch [#3017](https://github.com/emsesp/EMS-ESP32/issues/3017)
|
- fetch telegrams: set length to fetch [#3017](https://github.com/emsesp/EMS-ESP32/issues/3017)
|
||||||
- move http client from stack to heap
|
- move http client from stack to heap
|
||||||
- heap optimizations [#3021](https://github.com/emsesp/EMS-ESP32/discussions/3021)
|
- heap optimizations [#3021](https://github.com/emsesp/EMS-ESP32/discussions/3021)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
},
|
},
|
||||||
"core": "esp32",
|
"core": "esp32",
|
||||||
"extra_flags": [
|
"extra_flags": [
|
||||||
"-DTASMOTA_SDK",
|
"-DNO_TLS_SUPPORT",
|
||||||
"-DARDUINO_LOLIN_C3_MINI",
|
"-DARDUINO_LOLIN_C3_MINI",
|
||||||
"-DARDUINO_USB_MODE=1",
|
"-DARDUINO_USB_MODE=1",
|
||||||
"-DARDUINO_USB_CDC_ON_BOOT=1"
|
"-DARDUINO_USB_CDC_ON_BOOT=1"
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
"core": "esp32",
|
"core": "esp32",
|
||||||
"extra_flags": [
|
"extra_flags": [
|
||||||
"-DBOARD_HAS_PSRAM",
|
"-DBOARD_HAS_PSRAM",
|
||||||
"-DTASMOTA_SDK",
|
"-DNO_TLS_SUPPORT",
|
||||||
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
||||||
"-DARDUINO_USB_MODE=0"
|
"-DARDUINO_USB_MODE=0"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
"arduino",
|
"arduino",
|
||||||
"espidf"
|
"espidf"
|
||||||
],
|
],
|
||||||
"name": "Espressif ESP32-S3 32M Flash OPI PSRAM, 4608KB Code/OTA, 2MB FS",
|
"name": "Tasmota ESP32-S3 32M Flash OPI PSRAM, 4608KB Code/OTA, 2MB FS",
|
||||||
"upload": {
|
"upload": {
|
||||||
"flash_size": "32MB",
|
"flash_size": "32MB",
|
||||||
"maximum_ram_size": 327680,
|
"maximum_ram_size": 327680,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"build": {
|
"build": {
|
||||||
"core": "esp32",
|
"core": "esp32",
|
||||||
"extra_flags": "-DTASMOTA_SDK",
|
"extra_flags": "-DNO_TLS_SUPPORT",
|
||||||
"f_cpu": "240000000L",
|
"f_cpu": "240000000L",
|
||||||
"f_flash": "40000000L",
|
"f_flash": "40000000L",
|
||||||
"flash_mode": "dio",
|
"flash_mode": "dio",
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
"arduino",
|
"arduino",
|
||||||
"espidf"
|
"espidf"
|
||||||
],
|
],
|
||||||
"name": "Espressif ESP32 16M Flash, 4608KB Code/OTA, 2MB FS",
|
"name": "Tasmota ESP32 16M Flash, 4608KB Code/OTA, 2MB FS",
|
||||||
"upload": {
|
"upload": {
|
||||||
"flash_size": "16MB",
|
"flash_size": "16MB",
|
||||||
"maximum_ram_size": 327680,
|
"maximum_ram_size": 327680,
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
"arduino",
|
"arduino",
|
||||||
"espidf"
|
"espidf"
|
||||||
],
|
],
|
||||||
"name": "Espressif ESP32 16M Flash DIO PSRAM, 4608KB Code/OTA, 2MB FS",
|
"name": "Tasmota ESP32 16M Flash DIO PSRAM, 4608KB Code/OTA, 2MB FS",
|
||||||
"upload": {
|
"upload": {
|
||||||
"flash_size": "16MB",
|
"flash_size": "16MB",
|
||||||
"maximum_ram_size": 327680,
|
"maximum_ram_size": 327680,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"build": {
|
"build": {
|
||||||
"core": "esp32",
|
"core": "esp32",
|
||||||
"extra_flags": "-DTASMOTA_SDK",
|
"extra_flags": "-DNO_TLS_SUPPORT",
|
||||||
"f_cpu": "240000000L",
|
"f_cpu": "240000000L",
|
||||||
"f_flash": "40000000L",
|
"f_flash": "40000000L",
|
||||||
"flash_mode": "dio",
|
"flash_mode": "dio",
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
"build": {
|
"build": {
|
||||||
"core": "esp32",
|
"core": "esp32",
|
||||||
"extra_flags": [
|
"extra_flags": [
|
||||||
|
"-DNO_TLS_SUPPORT",
|
||||||
"-DARDUINO_XIAO_ESP32C6",
|
"-DARDUINO_XIAO_ESP32C6",
|
||||||
"-DARDUINO_USB_MODE=1",
|
"-DARDUINO_USB_MODE=1",
|
||||||
"-DARDUINO_USB_CDC_ON_BOOT=1"
|
"-DARDUINO_USB_CDC_ON_BOOT=1"
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
"@mui/material": "^9.0.0",
|
"@mui/material": "^9.0.0",
|
||||||
"@preact/compat": "^18.3.2",
|
"@preact/compat": "^18.3.2",
|
||||||
"@table-library/react-table-library": "4.1.15",
|
"@table-library/react-table-library": "4.1.15",
|
||||||
"alova": "3.5.1",
|
"alova": "^3.5.1",
|
||||||
"async-validator": "^4.2.5",
|
"async-validator": "^4.2.5",
|
||||||
"etag": "^1.8.1",
|
"etag": "^1.8.1",
|
||||||
"formidable": "^3.5.4",
|
"formidable": "^3.5.4",
|
||||||
@@ -64,8 +64,7 @@
|
|||||||
"terser": "^5.46.1",
|
"terser": "^5.46.1",
|
||||||
"typescript-eslint": "^8.59.0",
|
"typescript-eslint": "^8.59.0",
|
||||||
"vite": "^8.0.9",
|
"vite": "^8.0.9",
|
||||||
"vite-plugin-imagemin": "^0.6.1",
|
"vite-plugin-imagemin": "^0.6.1"
|
||||||
"vite-tsconfig-paths": "^6.1.1"
|
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.33.1+sha512.05ba3c1d5d1c18f68df06470d74055e62d41fc110a0c660db1b2dfb2785327f04cf0f68345d4609bc52089e7fa0343c31593b2f9594e2c5d5da426230acc9820"
|
"packageManager": "pnpm@10.33.1+sha512.05ba3c1d5d1c18f68df06470d74055e62d41fc110a0c660db1b2dfb2785327f04cf0f68345d4609bc52089e7fa0343c31593b2f9594e2c5d5da426230acc9820"
|
||||||
}
|
}
|
||||||
|
|||||||
39
interface/pnpm-lock.yaml
generated
39
interface/pnpm-lock.yaml
generated
@@ -30,7 +30,7 @@ importers:
|
|||||||
specifier: 4.1.15
|
specifier: 4.1.15
|
||||||
version: 4.1.15(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
|
version: 4.1.15(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
|
||||||
alova:
|
alova:
|
||||||
specifier: 3.5.1
|
specifier: ^3.5.1
|
||||||
version: 3.5.1
|
version: 3.5.1
|
||||||
async-validator:
|
async-validator:
|
||||||
specifier: ^4.2.5
|
specifier: ^4.2.5
|
||||||
@@ -126,9 +126,6 @@ importers:
|
|||||||
vite-plugin-imagemin:
|
vite-plugin-imagemin:
|
||||||
specifier: ^0.6.1
|
specifier: ^0.6.1
|
||||||
version: 0.6.1(vite@8.0.9(@types/node@25.6.0)(esbuild@0.27.4)(terser@5.46.1))
|
version: 0.6.1(vite@8.0.9(@types/node@25.6.0)(esbuild@0.27.4)(terser@5.46.1))
|
||||||
vite-tsconfig-paths:
|
|
||||||
specifier: ^6.1.1
|
|
||||||
version: 6.1.1(typescript@6.0.3)(vite@8.0.9(@types/node@25.6.0)(esbuild@0.27.4)(terser@5.46.1))
|
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
@@ -1986,9 +1983,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==}
|
resolution: {integrity: sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
globrex@0.1.2:
|
|
||||||
resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==}
|
|
||||||
|
|
||||||
gopd@1.2.0:
|
gopd@1.2.0:
|
||||||
resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
|
resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -3176,16 +3170,6 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
typescript: '>=4.8.4'
|
typescript: '>=4.8.4'
|
||||||
|
|
||||||
tsconfck@3.1.6:
|
|
||||||
resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==}
|
|
||||||
engines: {node: ^18 || >=20}
|
|
||||||
hasBin: true
|
|
||||||
peerDependencies:
|
|
||||||
typescript: ^5.0.0
|
|
||||||
peerDependenciesMeta:
|
|
||||||
typescript:
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
tslib@2.8.1:
|
tslib@2.8.1:
|
||||||
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
||||||
|
|
||||||
@@ -3274,11 +3258,6 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
vite: 5.x || 6.x || 7.x || 8.x
|
vite: 5.x || 6.x || 7.x || 8.x
|
||||||
|
|
||||||
vite-tsconfig-paths@6.1.1:
|
|
||||||
resolution: {integrity: sha512-2cihq7zliibCCZ8P9cKJrQBkfgdvcFkOOc3Y02o3GWUDLgqjWsZudaoiuOwO/gzTzy17cS5F7ZPo4bsnS4DGkg==}
|
|
||||||
peerDependencies:
|
|
||||||
vite: '*'
|
|
||||||
|
|
||||||
vite@8.0.9:
|
vite@8.0.9:
|
||||||
resolution: {integrity: sha512-t7g7GVRpMXjNpa67HaVWI/8BWtdVIQPCL2WoozXXA7LBGEFK4AkkKkHx2hAQf5x1GZSlcmEDPkVLSGahxnEEZw==}
|
resolution: {integrity: sha512-t7g7GVRpMXjNpa67HaVWI/8BWtdVIQPCL2WoozXXA7LBGEFK4AkkKkHx2hAQf5x1GZSlcmEDPkVLSGahxnEEZw==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
@@ -5265,8 +5244,6 @@ snapshots:
|
|||||||
merge2: 1.4.1
|
merge2: 1.4.1
|
||||||
slash: 3.0.0
|
slash: 3.0.0
|
||||||
|
|
||||||
globrex@0.1.2: {}
|
|
||||||
|
|
||||||
gopd@1.2.0: {}
|
gopd@1.2.0: {}
|
||||||
|
|
||||||
got@7.1.0:
|
got@7.1.0:
|
||||||
@@ -6400,10 +6377,6 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
typescript: 6.0.3
|
typescript: 6.0.3
|
||||||
|
|
||||||
tsconfck@3.1.6(typescript@6.0.3):
|
|
||||||
optionalDependencies:
|
|
||||||
typescript: 6.0.3
|
|
||||||
|
|
||||||
tslib@2.8.1: {}
|
tslib@2.8.1: {}
|
||||||
|
|
||||||
tunnel-agent@0.6.0:
|
tunnel-agent@0.6.0:
|
||||||
@@ -6516,16 +6489,6 @@ snapshots:
|
|||||||
stack-trace: 1.0.0-pre2
|
stack-trace: 1.0.0-pre2
|
||||||
vite: 8.0.9(@types/node@25.6.0)(esbuild@0.27.4)(terser@5.46.1)
|
vite: 8.0.9(@types/node@25.6.0)(esbuild@0.27.4)(terser@5.46.1)
|
||||||
|
|
||||||
vite-tsconfig-paths@6.1.1(typescript@6.0.3)(vite@8.0.9(@types/node@25.6.0)(esbuild@0.27.4)(terser@5.46.1)):
|
|
||||||
dependencies:
|
|
||||||
debug: 4.4.3
|
|
||||||
globrex: 0.1.2
|
|
||||||
tsconfck: 3.1.6(typescript@6.0.3)
|
|
||||||
vite: 8.0.9(@types/node@25.6.0)(esbuild@0.27.4)(terser@5.46.1)
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- supports-color
|
|
||||||
- typescript
|
|
||||||
|
|
||||||
vite@8.0.9(@types/node@25.6.0)(esbuild@0.27.4)(terser@5.46.1):
|
vite@8.0.9(@types/node@25.6.0)(esbuild@0.27.4)(terser@5.46.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
lightningcss: 1.32.0
|
lightningcss: 1.32.0
|
||||||
|
|||||||
@@ -43,6 +43,16 @@ export interface Settings {
|
|||||||
modbus_port: number;
|
modbus_port: number;
|
||||||
modbus_max_clients: number;
|
modbus_max_clients: number;
|
||||||
modbus_timeout: number;
|
modbus_timeout: number;
|
||||||
|
email_enabled: boolean;
|
||||||
|
email_ssl?: boolean;
|
||||||
|
email_starttls?: boolean;
|
||||||
|
email_server: string;
|
||||||
|
email_port: number;
|
||||||
|
email_login: string;
|
||||||
|
email_pass: string;
|
||||||
|
email_sender: string;
|
||||||
|
email_recp: string;
|
||||||
|
email_subject: string;
|
||||||
developer_mode: boolean;
|
developer_mode: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import {
|
|||||||
FormLoader,
|
FormLoader,
|
||||||
MessageBox,
|
MessageBox,
|
||||||
SectionContent,
|
SectionContent,
|
||||||
|
ValidatedPasswordField,
|
||||||
ValidatedTextField,
|
ValidatedTextField,
|
||||||
useLayoutTitle
|
useLayoutTitle
|
||||||
} from 'components';
|
} from 'components';
|
||||||
@@ -351,6 +352,156 @@ const ApplicationSettings = () => {
|
|||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
)}
|
)}
|
||||||
|
<Typography color="secondary">eMail</Typography>
|
||||||
|
<BlockFormControlLabel
|
||||||
|
control={
|
||||||
|
<Checkbox
|
||||||
|
checked={data.email_enabled}
|
||||||
|
onChange={updateFormValue}
|
||||||
|
name="email_enabled"
|
||||||
|
disabled={!hardwareData.psram}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label={
|
||||||
|
<Typography color={!hardwareData.psram ? 'grey' : 'default'}>
|
||||||
|
Enable eMail notification
|
||||||
|
{!hardwareData.psram && (
|
||||||
|
<Typography variant="caption">
|
||||||
|
({LL.IS_REQUIRED('PSRAM')})
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</Typography>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{data.email_enabled && (
|
||||||
|
<>
|
||||||
|
<Grid
|
||||||
|
container
|
||||||
|
spacing={2}
|
||||||
|
direction="row"
|
||||||
|
justifyContent="flex-start"
|
||||||
|
alignItems="flex-start"
|
||||||
|
>
|
||||||
|
<Grid>
|
||||||
|
<ValidatedTextField
|
||||||
|
fieldErrors={fieldErrors || {}}
|
||||||
|
name="email_server"
|
||||||
|
label="SMTP Server"
|
||||||
|
variant="outlined"
|
||||||
|
value={data.email_server}
|
||||||
|
onChange={updateFormValue}
|
||||||
|
margin="normal"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid>
|
||||||
|
<ValidatedTextField
|
||||||
|
fieldErrors={fieldErrors || {}}
|
||||||
|
sx={{ width: '12ch' }}
|
||||||
|
name="email_port"
|
||||||
|
variant="outlined"
|
||||||
|
label="Port"
|
||||||
|
value={numberValue(data.email_port)}
|
||||||
|
type="number"
|
||||||
|
onChange={updateFormValue}
|
||||||
|
margin="normal"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid size={4} mt={!data.email_ssl && !data.email_starttls ? 0 : 3}>
|
||||||
|
{!data.email_starttls && (
|
||||||
|
<BlockFormControlLabel
|
||||||
|
sx={{ width: '12ch' }}
|
||||||
|
control={
|
||||||
|
<Checkbox
|
||||||
|
checked={data.email_ssl}
|
||||||
|
onChange={updateFormValue}
|
||||||
|
name="email_ssl"
|
||||||
|
disabled={
|
||||||
|
data.email_starttls || data.email_ssl === undefined
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label="SSL/TLS"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{!data.email_ssl && (
|
||||||
|
<BlockFormControlLabel
|
||||||
|
sx={{ width: '12ch' }}
|
||||||
|
control={
|
||||||
|
<Checkbox
|
||||||
|
checked={data.email_starttls}
|
||||||
|
onChange={updateFormValue}
|
||||||
|
name="email_starttls"
|
||||||
|
disabled={
|
||||||
|
data.email_ssl || data.email_starttls === undefined
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label="STARTTLS"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
<Grid container spacing={2} rowSpacing={0}>
|
||||||
|
<Grid>
|
||||||
|
<ValidatedTextField
|
||||||
|
fieldErrors={fieldErrors || {}}
|
||||||
|
name="email_login"
|
||||||
|
label="Login"
|
||||||
|
variant="outlined"
|
||||||
|
value={data.email_login}
|
||||||
|
onChange={updateFormValue}
|
||||||
|
margin="normal"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid>
|
||||||
|
<ValidatedPasswordField
|
||||||
|
fieldErrors={fieldErrors || {}}
|
||||||
|
name="email_pass"
|
||||||
|
label="Password"
|
||||||
|
variant="outlined"
|
||||||
|
value={data.email_pass}
|
||||||
|
onChange={updateFormValue}
|
||||||
|
margin="normal"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
<Grid container spacing={2} rowSpacing={0}>
|
||||||
|
<Grid>
|
||||||
|
<ValidatedTextField
|
||||||
|
fieldErrors={fieldErrors || {}}
|
||||||
|
name="email_sender"
|
||||||
|
label="From"
|
||||||
|
variant="outlined"
|
||||||
|
value={data.email_sender}
|
||||||
|
onChange={updateFormValue}
|
||||||
|
margin="normal"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid>
|
||||||
|
<ValidatedTextField
|
||||||
|
fieldErrors={fieldErrors || {}}
|
||||||
|
name="email_recp"
|
||||||
|
label="To"
|
||||||
|
variant="outlined"
|
||||||
|
value={data.email_recp}
|
||||||
|
onChange={updateFormValue}
|
||||||
|
margin="normal"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid>
|
||||||
|
<ValidatedTextField
|
||||||
|
fieldErrors={fieldErrors || {}}
|
||||||
|
name="email_subject"
|
||||||
|
label="Subject"
|
||||||
|
variant="outlined"
|
||||||
|
value={data.email_subject}
|
||||||
|
onChange={updateFormValue}
|
||||||
|
margin="normal"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<Typography sx={{ pb: 1, pt: 2 }} variant="h6" color="primary">
|
<Typography sx={{ pb: 1, pt: 2 }} variant="h6" color="primary">
|
||||||
{LL.SENSORS()}
|
{LL.SENSORS()}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|||||||
@@ -315,22 +315,13 @@ const InstallDialog = memo(
|
|||||||
fetchDevVersion ? latestDevVersion?.name : latestVersion?.name
|
fetchDevVersion ? latestDevVersion?.name : latestVersion?.name
|
||||||
)}
|
)}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
|
{upgradeImportantMessageType === 1 && LL.UPGRADE_IMPORTANT_MESSAGES_1()}
|
||||||
{upgradeImportantMessageType === 2 && LL.UPGRADE_IMPORTANT_MESSAGES_2()}
|
{upgradeImportantMessageType === 2 && LL.UPGRADE_IMPORTANT_MESSAGES_2()}
|
||||||
{upgradeImportantMessageType === 1 && (
|
|
||||||
<>
|
|
||||||
{LL.UPGRADE_IMPORTANT_MESSAGES_1()}
|
|
||||||
<Typography sx={{ mt: 2 }}>
|
|
||||||
<Link to="/settings/downloadUpload" style={{ color: 'lightblue' }}>
|
|
||||||
{LL.DOWNLOAD_SYSTEM_BACKUP()}
|
|
||||||
</Link>
|
|
||||||
</Typography>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<Typography sx={{ mt: 2 }}>
|
<Typography sx={{ mt: 2 }}>
|
||||||
<Link
|
<Link
|
||||||
to="https://docs.emsesp.org/FAQ#upgrading-the-firmware"
|
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
to="https://docs.emsesp.org/FAQ#upgrading-the-firmware"
|
||||||
style={{ color: 'lightblue' }}
|
style={{ color: 'lightblue' }}
|
||||||
>
|
>
|
||||||
{LL.ONLINE_HELP()}
|
{LL.ONLINE_HELP()}
|
||||||
|
|||||||
@@ -49,6 +49,10 @@ the LICENSE file.
|
|||||||
#define EMC_CLIENTID_LENGTH 23 + 1
|
#define EMC_CLIENTID_LENGTH 23 + 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef EMSESP_MQTT_STACKSIZE
|
||||||
|
#define EMC_TASK_STACK_SIZE EMSESP_MQTT_STACKSIZE
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef EMC_TASK_STACK_SIZE
|
#ifndef EMC_TASK_STACK_SIZE
|
||||||
#define EMC_TASK_STACK_SIZE 5120
|
#define EMC_TASK_STACK_SIZE 5120
|
||||||
#endif
|
#endif
|
||||||
@@ -73,7 +77,3 @@ the LICENSE file.
|
|||||||
#define EMC_SIZE_POOL_ELEMENTS 128
|
#define EMC_SIZE_POOL_ELEMENTS 128
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef TASMOTA_SDK
|
|
||||||
#define EMC_CLIENT_SECURE
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -62,14 +62,19 @@ MqttClient::MqttClient(espMqttClientTypes::UseInternalTask useInternalTask, uint
|
|||||||
_xSemaphore = xSemaphoreCreateMutex();
|
_xSemaphore = xSemaphoreCreateMutex();
|
||||||
EMC_SEMAPHORE_GIVE(); // release before first use
|
EMC_SEMAPHORE_GIVE(); // release before first use
|
||||||
if (_useInternalTask == espMqttClientTypes::UseInternalTask::YES) {
|
if (_useInternalTask == espMqttClientTypes::UseInternalTask::YES) {
|
||||||
|
if (core > 1) {
|
||||||
|
xTaskCreate((TaskFunction_t)_loop, "mqttclient", EMC_TASK_STACK_SIZE, this, priority, &_taskHandle);
|
||||||
|
} else {
|
||||||
xTaskCreatePinnedToCore((TaskFunction_t)_loop, "mqttclient", EMC_TASK_STACK_SIZE, this, priority, &_taskHandle, core);
|
xTaskCreatePinnedToCore((TaskFunction_t)_loop, "mqttclient", EMC_TASK_STACK_SIZE, this, priority, &_taskHandle, core);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
(void) useInternalTask;
|
(void) useInternalTask;
|
||||||
(void) priority;
|
(void) priority;
|
||||||
(void) core;
|
(void) core;
|
||||||
#endif
|
#endif
|
||||||
_clientId = _generatedClientId;
|
_clientId = _generatedClientId;
|
||||||
|
_core = core;
|
||||||
}
|
}
|
||||||
|
|
||||||
MqttClient::~MqttClient() {
|
MqttClient::~MqttClient() {
|
||||||
|
|||||||
@@ -69,6 +69,16 @@ class MqttClient {
|
|||||||
const char* getClientId() const;
|
const char* getClientId() const;
|
||||||
size_t queueSize(); // No const because of mutex
|
size_t queueSize(); // No const because of mutex
|
||||||
void loop();
|
void loop();
|
||||||
|
uint32_t stack() {
|
||||||
|
#ifndef EMSESP_STANDALONE
|
||||||
|
return uxTaskGetStackHighWaterMark(_taskHandle);
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
uint8_t core() {
|
||||||
|
return _core;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit MqttClient(espMqttClientTypes::UseInternalTask useInternalTask, uint8_t priority = 1, uint8_t core = 1);
|
explicit MqttClient(espMqttClientTypes::UseInternalTask useInternalTask, uint8_t priority = 1, uint8_t core = 1);
|
||||||
@@ -98,6 +108,7 @@ class MqttClient {
|
|||||||
uint8_t _willQos;
|
uint8_t _willQos;
|
||||||
bool _willRetain;
|
bool _willRetain;
|
||||||
uint32_t _timeout;
|
uint32_t _timeout;
|
||||||
|
uint8_t _core;
|
||||||
|
|
||||||
// state is protected to allow state changes by the transport system, defined in child classes
|
// state is protected to allow state changes by the transport system, defined in child classes
|
||||||
// eg. to allow AsyncTCP
|
// eg. to allow AsyncTCP
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ the LICENSE file.
|
|||||||
|
|
||||||
#include "ClientPosix.h"
|
#include "ClientPosix.h"
|
||||||
|
|
||||||
#if defined(__linux__)
|
#if defined(__linux__) || defined(__APPLE__)
|
||||||
|
|
||||||
namespace espMqttClientInternals {
|
namespace espMqttClientInternals {
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ the LICENSE file.
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#if defined(__linux__)
|
#if defined(__linux__) || defined(__APPLE__)
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|||||||
@@ -6,28 +6,31 @@ For a copy, see <https://opensource.org/licenses/MIT> or
|
|||||||
the LICENSE file.
|
the LICENSE file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
|
#ifndef NO_TLS_SUPPORT
|
||||||
|
|
||||||
#include "ClientSecureSync.h"
|
#include "ClientSecureSync.h"
|
||||||
#include <lwip/sockets.h> // socket options
|
#include <lwip/sockets.h>
|
||||||
|
#include "../Config.h"
|
||||||
|
|
||||||
namespace espMqttClientInternals {
|
namespace espMqttClientInternals {
|
||||||
|
|
||||||
ClientSecureSync::ClientSecureSync()
|
ClientSecureSync::ClientSecureSync()
|
||||||
: client() {
|
: client() {
|
||||||
// empty
|
client.setClient(&basic_client, true);
|
||||||
|
client.setBufferSizes(EMC_RX_BUFFER_SIZE, EMC_TX_BUFFER_SIZE);
|
||||||
|
client.setSessionTimeout(120); // Set the timeout in seconds (>=120 seconds)
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientSecureSync::~ClientSecureSync() {
|
||||||
|
stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ClientSecureSync::connect(IPAddress ip, uint16_t port) {
|
bool ClientSecureSync::connect(IPAddress ip, uint16_t port) {
|
||||||
bool ret = client.connect(ip, port); // implicit conversion of return code int --> bool
|
bool ret = client.connect(ip, port); // implicit conversion of return code int --> bool
|
||||||
if (ret) {
|
if (ret) {
|
||||||
#if defined(ARDUINO_ARCH_ESP8266)
|
|
||||||
client.setNoDelay(true);
|
|
||||||
#elif defined(ARDUINO_ARCH_ESP32)
|
|
||||||
// Set TCP option directly to bypass lack of working setNoDelay for WiFiClientSecure
|
// Set TCP option directly to bypass lack of working setNoDelay for WiFiClientSecure
|
||||||
int val = true;
|
int val = true;
|
||||||
client.setSocketOption(IPPROTO_TCP, TCP_NODELAY, &val, sizeof(int));
|
basic_client.setSocketOption(IPPROTO_TCP, TCP_NODELAY, &val, sizeof(int));
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -35,13 +38,9 @@ bool ClientSecureSync::connect(IPAddress ip, uint16_t port) {
|
|||||||
bool ClientSecureSync::connect(const char * host, uint16_t port) {
|
bool ClientSecureSync::connect(const char * host, uint16_t port) {
|
||||||
bool ret = client.connect(host, port); // implicit conversion of return code int --> bool
|
bool ret = client.connect(host, port); // implicit conversion of return code int --> bool
|
||||||
if (ret) {
|
if (ret) {
|
||||||
#if defined(ARDUINO_ARCH_ESP8266)
|
|
||||||
client.setNoDelay(true);
|
|
||||||
#elif defined(ARDUINO_ARCH_ESP32)
|
|
||||||
// Set TCP option directly to bypass lack of working setNoDelay for WiFiClientSecure
|
// Set TCP option directly to bypass lack of working setNoDelay for WiFiClientSecure
|
||||||
int val = true;
|
int val = true;
|
||||||
client.setSocketOption(IPPROTO_TCP, TCP_NODELAY, &val, sizeof(int));
|
basic_client.setSocketOption(IPPROTO_TCP, TCP_NODELAY, &val, sizeof(int));
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,15 +8,11 @@ the LICENSE file.
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
|
#ifndef NO_TLS_SUPPORT
|
||||||
|
|
||||||
// Added for EMS-ESP
|
// #include "esp_tls.h"
|
||||||
#include "../Config.h"
|
|
||||||
#if defined(EMC_CLIENT_SECURE)
|
|
||||||
#include <WiFiClientSecure.h> // includes IPAddress
|
|
||||||
#else
|
|
||||||
#include <WiFiClient.h>
|
#include <WiFiClient.h>
|
||||||
#endif
|
#include <ESP_SSLClient.h>
|
||||||
#include "Transport.h"
|
#include "Transport.h"
|
||||||
|
|
||||||
namespace espMqttClientInternals {
|
namespace espMqttClientInternals {
|
||||||
@@ -24,6 +20,7 @@ namespace espMqttClientInternals {
|
|||||||
class ClientSecureSync : public Transport {
|
class ClientSecureSync : public Transport {
|
||||||
public:
|
public:
|
||||||
ClientSecureSync();
|
ClientSecureSync();
|
||||||
|
~ClientSecureSync();
|
||||||
bool connect(IPAddress ip, uint16_t port) override;
|
bool connect(IPAddress ip, uint16_t port) override;
|
||||||
bool connect(const char * host, uint16_t port) override;
|
bool connect(const char * host, uint16_t port) override;
|
||||||
size_t write(const uint8_t * buf, size_t size) override;
|
size_t write(const uint8_t * buf, size_t size) override;
|
||||||
@@ -31,12 +28,9 @@ class ClientSecureSync : public Transport {
|
|||||||
void stop() override;
|
void stop() override;
|
||||||
bool connected() override;
|
bool connected() override;
|
||||||
bool disconnected() override;
|
bool disconnected() override;
|
||||||
// added for EMS-ESP
|
|
||||||
#if defined(EMC_CLIENT_SECURE)
|
WiFiClient basic_client;
|
||||||
WiFiClientSecure client;
|
ESP_SSLClient client;
|
||||||
#else
|
|
||||||
WiFiClient client;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace espMqttClientInternals
|
} // namespace espMqttClientInternals
|
||||||
|
|||||||
@@ -8,50 +8,6 @@ the LICENSE file.
|
|||||||
|
|
||||||
#include "espMqttClient.h"
|
#include "espMqttClient.h"
|
||||||
|
|
||||||
#if defined(ARDUINO_ARCH_ESP8266)
|
|
||||||
espMqttClient::espMqttClient()
|
|
||||||
: MqttClientSetup(espMqttClientTypes::UseInternalTask::NO)
|
|
||||||
, _client() {
|
|
||||||
_transport = &_client;
|
|
||||||
}
|
|
||||||
|
|
||||||
espMqttClientSecure::espMqttClientSecure()
|
|
||||||
: MqttClientSetup(espMqttClientTypes::UseInternalTask::NO)
|
|
||||||
, _client() {
|
|
||||||
_transport = &_client;
|
|
||||||
}
|
|
||||||
|
|
||||||
espMqttClientSecure & espMqttClientSecure::setInsecure() {
|
|
||||||
_client.client.setInsecure();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
espMqttClientSecure & espMqttClientSecure::setFingerprint(const uint8_t fingerprint[20]) {
|
|
||||||
_client.client.setFingerprint(fingerprint);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
espMqttClientSecure & espMqttClientSecure::setTrustAnchors(const X509List * ta) {
|
|
||||||
_client.client.setTrustAnchors(ta);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
espMqttClientSecure & espMqttClientSecure::setClientRSACert(const X509List * cert, const PrivateKey * sk) {
|
|
||||||
_client.client.setClientRSACert(cert, sk);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
espMqttClientSecure & espMqttClientSecure::setClientECCert(const X509List * cert, const PrivateKey * sk, unsigned allowed_usages, unsigned cert_issuer_key_type) {
|
|
||||||
_client.client.setClientECCert(cert, sk, allowed_usages, cert_issuer_key_type);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
espMqttClientSecure & espMqttClientSecure::setCertStore(CertStoreBase * certStore) {
|
|
||||||
_client.client.setCertStore(certStore);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(ARDUINO_ARCH_ESP32)
|
#if defined(ARDUINO_ARCH_ESP32)
|
||||||
espMqttClient::espMqttClient(espMqttClientTypes::UseInternalTask useInternalTask)
|
espMqttClient::espMqttClient(espMqttClientTypes::UseInternalTask useInternalTask)
|
||||||
: MqttClientSetup(useInternalTask)
|
: MqttClientSetup(useInternalTask)
|
||||||
@@ -78,51 +34,45 @@ espMqttClientSecure::espMqttClientSecure(uint8_t priority, uint8_t core)
|
|||||||
}
|
}
|
||||||
|
|
||||||
espMqttClientSecure & espMqttClientSecure::setInsecure() {
|
espMqttClientSecure & espMqttClientSecure::setInsecure() {
|
||||||
#if defined(EMC_CLIENT_SECURE)
|
#ifndef NO_TLS_SUPPORT
|
||||||
_client.client.setInsecure();
|
_client.client.setInsecure();
|
||||||
#endif
|
#endif
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
espMqttClientSecure & espMqttClientSecure::setCACert(const char * rootCA) {
|
espMqttClientSecure & espMqttClientSecure::setCACert(const char * rootCA) {
|
||||||
#if defined(EMC_CLIENT_SECURE)
|
#ifndef NO_TLS_SUPPORT
|
||||||
_client.client.setCACert(rootCA);
|
_client.client.setCACert(rootCA);
|
||||||
#endif
|
#endif
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
espMqttClientSecure & espMqttClientSecure::setCertificate(const char * clientCa) {
|
espMqttClientSecure & espMqttClientSecure::setCertificate(const char * clientCa) {
|
||||||
#if defined(EMC_CLIENT_SECURE)
|
#ifndef NO_TLS_SUPPORT
|
||||||
_client.client.setCertificate(clientCa);
|
_client.client.setCertificate(clientCa);
|
||||||
#endif
|
#endif
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
espMqttClientSecure & espMqttClientSecure::setPrivateKey(const char * privateKey) {
|
espMqttClientSecure & espMqttClientSecure::setPrivateKey(const char * privateKey) {
|
||||||
#if defined(EMC_CLIENT_SECURE)
|
#ifndef NO_TLS_SUPPORT
|
||||||
_client.client.setPrivateKey(privateKey);
|
_client.client.setPrivateKey(privateKey);
|
||||||
#endif
|
#endif
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
espMqttClientSecure & espMqttClientSecure::setPreSharedKey(const char * pskIdent, const char * psKey) {
|
espMqttClientSecure & espMqttClientSecure::setPreSharedKey(const char * pskIdent, const char * psKey) {
|
||||||
#if defined(EMC_CLIENT_SECURE)
|
#ifndef NO_TLS_SUPPORT
|
||||||
_client.client.setPreSharedKey(pskIdent, psKey);
|
|
||||||
#endif
|
#endif
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__linux__)
|
#if defined(__linux__) || defined(__APPLE__)
|
||||||
espMqttClient::espMqttClient()
|
espMqttClient::espMqttClient()
|
||||||
: MqttClientSetup(espMqttClientTypes::UseInternalTask::NO)
|
: MqttClientSetup(espMqttClientTypes::UseInternalTask::NO)
|
||||||
, _client() {
|
, _client() {
|
||||||
_transport = &_client;
|
_transport = &_client;
|
||||||
}
|
}
|
||||||
#elif defined(_WIN32) || defined(__APPLE__)
|
|
||||||
// Windows
|
|
||||||
espMqttClient::espMqttClient()
|
|
||||||
: MqttClientSetup(espMqttClientTypes::UseInternalTask::NO) {
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ the LICENSE file.
|
|||||||
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
|
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
|
||||||
#include "Transport/ClientSync.h"
|
#include "Transport/ClientSync.h"
|
||||||
#include "Transport/ClientSecureSync.h"
|
#include "Transport/ClientSecureSync.h"
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__) || defined(__APPLE__)
|
||||||
#include "Transport/ClientPosix.h"
|
#include "Transport/ClientPosix.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -65,10 +65,16 @@ class espMqttClientSecure : public MqttClientSetup<espMqttClientSecure> {
|
|||||||
espMqttClientSecure & setPreSharedKey(const char * pskIdent, const char * psKey);
|
espMqttClientSecure & setPreSharedKey(const char * pskIdent, const char * psKey);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
#ifndef NO_TLS_SUPPORT
|
||||||
espMqttClientInternals::ClientSecureSync _client;
|
espMqttClientInternals::ClientSecureSync _client;
|
||||||
|
#else
|
||||||
|
espMqttClientInternals::ClientSync _client;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#elif defined(__linux__)
|
#endif
|
||||||
|
|
||||||
|
#if defined(__linux__) || defined(__APPLE__)
|
||||||
class espMqttClient : public MqttClientSetup<espMqttClient> {
|
class espMqttClient : public MqttClientSetup<espMqttClient> {
|
||||||
public:
|
public:
|
||||||
espMqttClient();
|
espMqttClient();
|
||||||
@@ -76,10 +82,4 @@ class espMqttClient : public MqttClientSetup<espMqttClient> {
|
|||||||
protected:
|
protected:
|
||||||
espMqttClientInternals::ClientPosix _client;
|
espMqttClientInternals::ClientPosix _client;
|
||||||
};
|
};
|
||||||
#elif defined(_WIN32) || defined(__APPLE__)
|
|
||||||
class espMqttClient : public MqttClientSetup<espMqttClient> {
|
|
||||||
public:
|
|
||||||
espMqttClient();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ extra_configs =
|
|||||||
pio_local.ini
|
pio_local.ini
|
||||||
|
|
||||||
[common]
|
[common]
|
||||||
core_build_flags = -std=gnu++2a -O3 -flto=auto -Wno-type-limits -Wall -Wextra -Wno-unused-parameter -Wno-unused-variable -Wno-format -Wno-missing-field-initializers
|
core_build_flags = -std=gnu++20 -O3 -flto=auto -Wno-type-limits -Wall -Wextra -Wno-unused-parameter -Wno-unused-variable -Wno-format -Wno-missing-field-initializers
|
||||||
core_unbuild_flags = -std=gnu++11 -std=gnu++14 -std=gnu++17 -fno-lto
|
core_unbuild_flags = -std=gnu++11 -std=gnu++14 -std=gnu++17 -fno-lto
|
||||||
|
|
||||||
my_build_flags =
|
my_build_flags =
|
||||||
@@ -53,13 +53,21 @@ build_flags =
|
|||||||
unbuild_flags =
|
unbuild_flags =
|
||||||
${common.core_unbuild_flags}
|
${common.core_unbuild_flags}
|
||||||
|
|
||||||
|
; 4MB Flash variants
|
||||||
|
[espressif32_base_4M]
|
||||||
|
framework = arduino
|
||||||
|
board_build.partitions = partitions/esp32_partition_4M.csv
|
||||||
|
board_upload.flash_size = 4MB
|
||||||
|
board_build.app_partition_name = app0
|
||||||
|
platform = https://github.com/tasmota/platform-espressif32/releases/download/2026.04.50/platform-espressif32.zip ; Platform 2026.04.50 Tasmota Arduino Core 3.3.8 based on IDF 5.5.4.260407
|
||||||
|
|
||||||
; 16MB Flash variants
|
; 16MB Flash variants
|
||||||
[espressif32_base_16M]
|
[espressif32_base_16M]
|
||||||
framework = arduino
|
framework = arduino
|
||||||
board_build.partitions = partitions/esp32_partition_16M.csv
|
board_build.partitions = partitions/esp32_partition_16M.csv
|
||||||
board_upload.flash_size = 16MB
|
board_upload.flash_size = 16MB
|
||||||
board_build.app_partition_name = app0
|
board_build.app_partition_name = app0
|
||||||
platform = espressif32@6.13.0 ; Arduino Core 2.0.17 / IDF 4.4.7
|
platform = https://github.com/tasmota/platform-espressif32/releases/download/2026.04.50/platform-espressif32.zip ; Platform 2026.04.50 Tasmota Arduino Core 3.3.8 based on IDF 5.5.4.260407
|
||||||
|
|
||||||
; 32MB Flash variants
|
; 32MB Flash variants
|
||||||
[espressif32_base_32M]
|
[espressif32_base_32M]
|
||||||
@@ -67,29 +75,7 @@ framework = arduino
|
|||||||
board_build.partitions = partitions/esp32_partition_32M.csv
|
board_build.partitions = partitions/esp32_partition_32M.csv
|
||||||
board_upload.flash_size = 32MB
|
board_upload.flash_size = 32MB
|
||||||
board_build.app_partition_name = app0
|
board_build.app_partition_name = app0
|
||||||
platform = espressif32@6.13.0 ; Arduino Core 2.0.17 / IDF 4.4.7
|
platform = https://github.com/tasmota/platform-espressif32/releases/download/2026.04.50/platform-espressif32.zip ; Platform 2026.04.50 Tasmota Arduino Core 3.3.8 based on IDF 5.5.4.260407
|
||||||
|
|
||||||
; use Tasmota's library for 4MB Flash variants.
|
|
||||||
; Removes libs (like mbedtsl, so no WiFi_secure.h) to increase available heap
|
|
||||||
[espressif32_base_T_4M]
|
|
||||||
framework = arduino
|
|
||||||
board_build.partitions = partitions/esp32_partition_4M.csv
|
|
||||||
board_upload.flash_size = 4MB
|
|
||||||
board_build.app_partition_name = app0
|
|
||||||
platform = https://github.com/tasmota/platform-espressif32/releases/download/2024.06.00/platform-espressif32.zip ; Arduino Core 2.0.18 with IPv6 support, based on IDF 4.4.8
|
|
||||||
; Tasmota Arduino Core 3.1.3.250302 based on IDF 5.3.2.250228
|
|
||||||
; platform = https://github.com/tasmota/platform-espressif32/releases/download/2025.03.30/platform-espressif32.zip
|
|
||||||
|
|
||||||
; use Tasmota's library for 16MB Flash variants.
|
|
||||||
; Removes libs (like mbedtsl, so no WiFi_secure.h) to increase available heap
|
|
||||||
[espressif32_base_T_16M]
|
|
||||||
framework = arduino
|
|
||||||
board_build.partitions = partitions/esp32_partition_16M.csv
|
|
||||||
board_upload.flash_size = 16MB
|
|
||||||
board_build.app_partition_name = app0
|
|
||||||
platform = https://github.com/tasmota/platform-espressif32/releases/download/2024.06.00/platform-espressif32.zip ; Arduino Core 2.0.18 with IPv6 support, based on IDF 4.4.8
|
|
||||||
; Tasmota Arduino Core 3.1.3.250302 based on IDF 5.3.2.250228
|
|
||||||
; platform = https://github.com/tasmota/platform-espressif32/releases/download/2025.03.30/platform-espressif32.zip
|
|
||||||
|
|
||||||
[env]
|
[env]
|
||||||
build_flags =
|
build_flags =
|
||||||
@@ -106,6 +92,8 @@ lib_deps =
|
|||||||
bblanchon/ArduinoJson @ 7.4.3
|
bblanchon/ArduinoJson @ 7.4.3
|
||||||
ESP32Async/AsyncTCP @ 3.4.10
|
ESP32Async/AsyncTCP @ 3.4.10
|
||||||
ESP32Async/ESPAsyncWebServer @ 3.10.3
|
ESP32Async/ESPAsyncWebServer @ 3.10.3
|
||||||
|
https://github.com/mobizt/ReadyMail.git @ 0.4.0
|
||||||
|
https://github.com/mobizt/ESP_SSLClient.git @ 3.1.3
|
||||||
; https://github.com/emsesp/EMS-ESP-Modules.git @ 1.0.8
|
; https://github.com/emsesp/EMS-ESP-Modules.git @ 1.0.8
|
||||||
|
|
||||||
; builds the web interface only, not the firmware
|
; builds the web interface only, not the firmware
|
||||||
@@ -118,18 +106,17 @@ build_src_filter = -<*>
|
|||||||
|
|
||||||
;
|
;
|
||||||
; Builds for different board types
|
; Builds for different board types
|
||||||
; We use Tasmota for boards without PSRAM as this framework has mbedtls removed to save memory.
|
|
||||||
; If you're building for a single target environment, we recommend creating a pio_local.ini (see example file)
|
; If you're building for a single target environment, we recommend creating a pio_local.ini (see example file)
|
||||||
;
|
;
|
||||||
|
|
||||||
[env:s_4M]
|
[env:s_4M]
|
||||||
; 4MB ESP32 - no SSL, no PSRAM - like a BBQKees older S32 and E32 models - uses Tasmota
|
; 4MB ESP32 - no SSL, no PSRAM - like a BBQKees older S32 and E32 models
|
||||||
extends = espressif32_base_T_4M
|
extends = espressif32_base_4M
|
||||||
board = s_4M
|
board = s_4M
|
||||||
|
|
||||||
[env:s_16M]
|
[env:s_16M]
|
||||||
; 16MB ESP32 - no PSRAM - like a BBQKees later S32 V2 models - uses Tasmota
|
; 16MB ESP32 - no PSRAM - like a BBQKees later S32 V2 models
|
||||||
extends = espressif32_base_T_16M
|
extends = espressif32_base_16M
|
||||||
board = s_16M
|
board = s_16M
|
||||||
|
|
||||||
[env:s_16M_P]
|
[env:s_16M_P]
|
||||||
@@ -148,24 +135,30 @@ extends = espressif32_base_32M
|
|||||||
board = s3_32M_P
|
board = s3_32M_P
|
||||||
|
|
||||||
[env:s2_4M_P]
|
[env:s2_4M_P]
|
||||||
; based on lolin_s2_mini 4MB with 2MB PSRAM - uses Tasmota
|
; based on lolin_s2_mini 4MB with 2MB PSRAM
|
||||||
extends = espressif32_base_T_4M
|
extends = espressif32_base_4M
|
||||||
board = s2_4M_P
|
board = s2_4M_P
|
||||||
|
|
||||||
[env:c3_mini_4M]
|
[env:c3_mini_4M]
|
||||||
; based on lolin_c3_mini 4MB, no PSRAM - uses Tasmota
|
; based on lolin_c3_mini 4MB, no PSRAM
|
||||||
extends = espressif32_base_T_4M
|
extends = espressif32_base_4M
|
||||||
board = c3_mini_4M
|
board = c3_mini_4M
|
||||||
|
|
||||||
; lolin C3 mini v1 needs special wifi initialization
|
; lolin C3 mini v1 needs special wifi initialization
|
||||||
; https://www.wemos.cc/en/latest/c3/c3_mini_1_0_0.html#about-wifi
|
; https://www.wemos.cc/en/latest/c3/c3_mini_1_0_0.html#about-wifi
|
||||||
[env:c3_miniv1_4M]
|
[env:c3_miniv1_4M]
|
||||||
extends = espressif32_base_T_4M
|
extends = espressif32_base_4M
|
||||||
board = c3_mini_4M
|
board = c3_mini_4M
|
||||||
build_flags =
|
build_flags =
|
||||||
${common.build_flags}
|
${common.build_flags}
|
||||||
-DBOARD_C3_MINI_V1
|
-DBOARD_C3_MINI_V1
|
||||||
|
|
||||||
|
; XIAO ESP32C - 512KB SRAM & 4MB Flash - https://wiki.seeedstudio.com/xiao_esp32c6_getting_started/
|
||||||
|
[env:c6_xiao_4M]
|
||||||
|
extends = espressif32_base_4M
|
||||||
|
board_build.app_partition_name = app0
|
||||||
|
board = seeed_xiao_esp32c6
|
||||||
|
|
||||||
; foundation for building and testing natively, standalone without an ESP32
|
; foundation for building and testing natively, standalone without an ESP32
|
||||||
; use the `standalone` environment instead of `native` for testing
|
; use the `standalone` environment instead of `native` for testing
|
||||||
[env:native]
|
[env:native]
|
||||||
@@ -175,7 +168,8 @@ build_flags =
|
|||||||
build_src_flags =
|
build_src_flags =
|
||||||
-DEMSESP_STANDALONE -DEMSESP_TEST
|
-DEMSESP_STANDALONE -DEMSESP_TEST
|
||||||
-DARDUINOJSON_ENABLE_ARDUINO_STRING=1
|
-DARDUINOJSON_ENABLE_ARDUINO_STRING=1
|
||||||
-std=gnu++2a -Og -ggdb
|
-DNO_TLS_SUPPORT
|
||||||
|
-std=gnu++20 -Og -ggdb
|
||||||
-Wall -Wextra
|
-Wall -Wextra
|
||||||
-Wno-unused-parameter -Wno-sign-compare -Wno-missing-braces
|
-Wno-unused-parameter -Wno-sign-compare -Wno-missing-braces
|
||||||
-Wno-vla-cxx-extension -Wno-tautological-constant-out-of-range-compare
|
-Wno-vla-cxx-extension -Wno-tautological-constant-out-of-range-compare
|
||||||
@@ -213,8 +207,9 @@ build_src_flags =
|
|||||||
-DEMSESP_STANDALONE -DEMSESP_TEST
|
-DEMSESP_STANDALONE -DEMSESP_TEST
|
||||||
-DEMSESP_UNITY
|
-DEMSESP_UNITY
|
||||||
-DARDUINOJSON_ENABLE_ARDUINO_STRING=1
|
-DARDUINOJSON_ENABLE_ARDUINO_STRING=1
|
||||||
|
-DNO_TLS_SUPPORT
|
||||||
-DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32\"
|
-DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32\"
|
||||||
-std=gnu++2a -Og -ggdb
|
-std=gnu++20 -Og -ggdb
|
||||||
-Wall -Wextra
|
-Wall -Wextra
|
||||||
-Wno-unused-parameter -Wno-sign-compare -Wno-missing-braces
|
-Wno-unused-parameter -Wno-sign-compare -Wno-missing-braces
|
||||||
-Wno-vla-cxx-extension -Wno-tautological-constant-out-of-range-compare
|
-Wno-vla-cxx-extension -Wno-tautological-constant-out-of-range-compare
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ APSettingsService::APSettingsService(AsyncWebServer * server, FS * fs, SecurityM
|
|||||||
, _reconfigureAp(false)
|
, _reconfigureAp(false)
|
||||||
, _connected(0) {
|
, _connected(0) {
|
||||||
addUpdateHandler([this] { reconfigureAP(); }, false);
|
addUpdateHandler([this] { reconfigureAP(); }, false);
|
||||||
WiFi.onEvent([this](WiFiEvent_t event, WiFiEventInfo_t info) { WiFiEvent(event); });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void APSettingsService::begin() {
|
void APSettingsService::begin() {
|
||||||
@@ -19,39 +18,27 @@ void APSettingsService::begin() {
|
|||||||
// reconfigureAP();
|
// reconfigureAP();
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait 10 sec on STA disconnect before starting AP
|
|
||||||
void APSettingsService::WiFiEvent(WiFiEvent_t event) {
|
|
||||||
const uint8_t was_connected = _connected;
|
|
||||||
switch (event) {
|
|
||||||
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
|
|
||||||
_connected &= ~1U;
|
|
||||||
break;
|
|
||||||
case ARDUINO_EVENT_ETH_DISCONNECTED:
|
|
||||||
_connected &= ~2U;
|
|
||||||
break;
|
|
||||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
|
|
||||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP6:
|
|
||||||
_connected |= 1U;
|
|
||||||
break;
|
|
||||||
case ARDUINO_EVENT_ETH_GOT_IP:
|
|
||||||
case ARDUINO_EVENT_ETH_GOT_IP6:
|
|
||||||
_connected |= 2U;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// wait 10 sec before starting AP
|
|
||||||
if (was_connected && !_connected) {
|
|
||||||
_lastManaged = uuid::get_uptime();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void APSettingsService::reconfigureAP() {
|
void APSettingsService::reconfigureAP() {
|
||||||
_lastManaged = uuid::get_uptime() - MANAGE_NETWORK_DELAY;
|
_lastManaged = uuid::get_uptime() - MANAGE_NETWORK_DELAY;
|
||||||
_reconfigureAp = true;
|
_reconfigureAp = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void APSettingsService::loop() {
|
void APSettingsService::loop() {
|
||||||
|
const uint8_t was_connected = _connected;
|
||||||
|
if (WiFi.isConnected()) {
|
||||||
|
_connected |= 1U;
|
||||||
|
} else {
|
||||||
|
_connected &= ~1U;
|
||||||
|
}
|
||||||
|
if (ETH.connected()) {
|
||||||
|
_connected |= 2U;
|
||||||
|
} else {
|
||||||
|
_connected &= ~2U;
|
||||||
|
}
|
||||||
|
// wait 10 sec before starting AP
|
||||||
|
if (was_connected && !_connected) {
|
||||||
|
_lastManaged = uuid::get_uptime();
|
||||||
|
}
|
||||||
const unsigned long currentMillis = uuid::get_uptime();
|
const unsigned long currentMillis = uuid::get_uptime();
|
||||||
if ((currentMillis - _lastManaged) >= MANAGE_NETWORK_DELAY) {
|
if ((currentMillis - _lastManaged) >= MANAGE_NETWORK_DELAY) {
|
||||||
_lastManaged = currentMillis;
|
_lastManaged = currentMillis;
|
||||||
@@ -76,11 +63,7 @@ void APSettingsService::manageAP() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void APSettingsService::startAP() {
|
void APSettingsService::startAP() {
|
||||||
#if ESP_IDF_VERSION_MAJOR < 5
|
|
||||||
WiFi.softAPenableIpV6(); // force IPV6, same as for WiFi - fixes https://github.com/emsesp/EMS-ESP32/issues/1922
|
|
||||||
#else
|
|
||||||
WiFi.softAPenableIPv6(); // force IPV6, same as for WiFi - fixes https://github.com/emsesp/EMS-ESP32/issues/1922
|
WiFi.softAPenableIPv6(); // force IPV6, same as for WiFi - fixes https://github.com/emsesp/EMS-ESP32/issues/1922
|
||||||
#endif
|
|
||||||
WiFi.softAPConfig(_state.localIP, _state.gatewayIP, _state.subnetMask);
|
WiFi.softAPConfig(_state.localIP, _state.gatewayIP, _state.subnetMask);
|
||||||
esp_wifi_set_bandwidth(static_cast<wifi_interface_t>(ESP_IF_WIFI_AP), WIFI_BW_HT20);
|
esp_wifi_set_bandwidth(static_cast<wifi_interface_t>(ESP_IF_WIFI_AP), WIFI_BW_HT20);
|
||||||
WiFi.softAP(_state.ssid.c_str(), _state.password.c_str(), _state.channel, _state.ssidHidden, _state.maxClients);
|
WiFi.softAP(_state.ssid.c_str(), _state.password.c_str(), _state.channel, _state.ssidHidden, _state.maxClients);
|
||||||
|
|||||||
@@ -104,7 +104,6 @@ class APSettingsService : public StatefulService<APSettings> {
|
|||||||
void startAP();
|
void startAP();
|
||||||
void stopAP();
|
void stopAP();
|
||||||
void handleDNS();
|
void handleDNS();
|
||||||
void WiFiEvent(WiFiEvent_t event);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
static constexpr const char CACHE_CONTROL[] = "public,max-age=60";
|
static constexpr const char CACHE_CONTROL[] = "public,max-age=60";
|
||||||
|
|
||||||
// Single static-content handler serving all assets embedded in WWWData.h.
|
// Single static-content handler serving all assets embedded in WWWData.h
|
||||||
class StaticContentHandler : public AsyncWebHandler {
|
class StaticContentHandler : public AsyncWebHandler {
|
||||||
public:
|
public:
|
||||||
bool canHandle(AsyncWebServerRequest * request) const override {
|
bool canHandle(AsyncWebServerRequest * request) const override {
|
||||||
@@ -15,8 +15,7 @@ class StaticContentHandler : public AsyncWebHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void handleRequest(AsyncWebServerRequest * request) override {
|
void handleRequest(AsyncWebServerRequest * request) override {
|
||||||
// OPTIONS is handled generically - the server-level CORS headers are
|
// OPTIONS is handled generically - the server-level CORS headers are attached via DefaultHeaders in ESP32React::begin().
|
||||||
// attached via DefaultHeaders in ESP32React::begin().
|
|
||||||
if (request->method() == HTTP_OPTIONS) {
|
if (request->method() == HTTP_OPTIONS) {
|
||||||
request->send(200);
|
request->send(200);
|
||||||
return;
|
return;
|
||||||
@@ -57,8 +56,7 @@ class StaticContentHandler : public AsyncWebHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns the /index.html asset, used as the SPA fallback for any GET
|
// Returns the /index.html asset, used as the SPA fallback for any GET
|
||||||
// that didn't match an embedded asset (React Router handles routing on
|
// that didn't match an embedded asset (React Router handles routing on the client side).
|
||||||
// the client side).
|
|
||||||
static const WWWAsset * index_asset() {
|
static const WWWAsset * index_asset() {
|
||||||
static const WWWAsset * cached = nullptr;
|
static const WWWAsset * cached = nullptr;
|
||||||
if (cached == nullptr) {
|
if (cached == nullptr) {
|
||||||
@@ -106,4 +104,5 @@ void ESP32React::loop() {
|
|||||||
_networkSettingsService.loop();
|
_networkSettingsService.loop();
|
||||||
_apSettingsService.loop();
|
_apSettingsService.loop();
|
||||||
_mqttSettingsService.loop();
|
_mqttSettingsService.loop();
|
||||||
|
_ntpSettingsService.loop();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ MqttSettingsService::MqttSettingsService(AsyncWebServer * server, FS * fs, Secur
|
|||||||
, _disconnectedAt(0)
|
, _disconnectedAt(0)
|
||||||
, _disconnectReason(espMqttClientTypes::DisconnectReason::TCP_DISCONNECTED)
|
, _disconnectReason(espMqttClientTypes::DisconnectReason::TCP_DISCONNECTED)
|
||||||
, _mqttClient(nullptr) {
|
, _mqttClient(nullptr) {
|
||||||
WiFi.onEvent([this](WiFiEvent_t event, WiFiEventInfo_t info) { WiFiEvent(event); });
|
|
||||||
addUpdateHandler([this] { onConfigUpdated(); }, false);
|
addUpdateHandler([this] { onConfigUpdated(); }, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,6 +28,7 @@ MqttSettingsService::~MqttSettingsService() {
|
|||||||
void MqttSettingsService::begin() {
|
void MqttSettingsService::begin() {
|
||||||
_fsPersistence.readFromFS();
|
_fsPersistence.readFromFS();
|
||||||
startClient();
|
startClient();
|
||||||
|
_reconfigureMqtt = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MqttSettingsService::startClient() {
|
void MqttSettingsService::startClient() {
|
||||||
@@ -41,7 +41,7 @@ void MqttSettingsService::startClient() {
|
|||||||
delete _mqttClient;
|
delete _mqttClient;
|
||||||
_mqttClient = nullptr;
|
_mqttClient = nullptr;
|
||||||
}
|
}
|
||||||
#ifndef TASMOTA_SDK
|
#ifndef NO_TLS_SUPPORT
|
||||||
if (_state.enableTLS) {
|
if (_state.enableTLS) {
|
||||||
isSecure = true;
|
isSecure = true;
|
||||||
if (emsesp::EMSESP::system_.PSram() == 0) {
|
if (emsesp::EMSESP::system_.PSram() == 0) {
|
||||||
@@ -79,6 +79,10 @@ void MqttSettingsService::startClient() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MqttSettingsService::loop() {
|
void MqttSettingsService::loop() {
|
||||||
|
if (_state.enabled && _mqttClient && _mqttClient->connected() && !emsesp::EMSESP::system_.network_connected()) {
|
||||||
|
// emsesp::EMSESP::logger().info("Network connection dropped, stopping MQTT client");
|
||||||
|
_mqttClient->disconnect(true);
|
||||||
|
}
|
||||||
if (_reconfigureMqtt || (_disconnectedAt && static_cast<uint32_t>(uuid::get_uptime() - _disconnectedAt) >= MQTT_RECONNECTION_DELAY)) {
|
if (_reconfigureMqtt || (_disconnectedAt && static_cast<uint32_t>(uuid::get_uptime() - _disconnectedAt) >= MQTT_RECONNECTION_DELAY)) {
|
||||||
// reconfigure MQTT client
|
// reconfigure MQTT client
|
||||||
_disconnectedAt = configureMqtt() ? 0 : uuid::get_uptime();
|
_disconnectedAt = configureMqtt() ? 0 : uuid::get_uptime();
|
||||||
@@ -142,28 +146,6 @@ void MqttSettingsService::onConfigUpdated() {
|
|||||||
emsesp::EMSESP::mqtt_.start(); // reload EMS-ESP MQTT settings
|
emsesp::EMSESP::mqtt_.start(); // reload EMS-ESP MQTT settings
|
||||||
}
|
}
|
||||||
|
|
||||||
void MqttSettingsService::WiFiEvent(WiFiEvent_t event) {
|
|
||||||
switch (event) {
|
|
||||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
|
|
||||||
case ARDUINO_EVENT_ETH_GOT_IP:
|
|
||||||
case ARDUINO_EVENT_ETH_GOT_IP6:
|
|
||||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP6:
|
|
||||||
if (_state.enabled && !_mqttClient->connected()) {
|
|
||||||
onConfigUpdated();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
|
|
||||||
case ARDUINO_EVENT_ETH_DISCONNECTED:
|
|
||||||
if (_state.enabled) {
|
|
||||||
_mqttClient->disconnect(true);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MqttSettingsService::configureMqtt() {
|
bool MqttSettingsService::configureMqtt() {
|
||||||
// disconnect if already connected
|
// disconnect if already connected
|
||||||
if (_mqttClient->connected()) {
|
if (_mqttClient->connected()) {
|
||||||
@@ -182,7 +164,7 @@ bool MqttSettingsService::configureMqtt() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_reconfigureMqtt = false;
|
_reconfigureMqtt = false;
|
||||||
#ifndef TASMOTA_SDK
|
#ifndef NO_TLS_SUPPORT
|
||||||
if (_state.enableTLS) {
|
if (_state.enableTLS) {
|
||||||
if (_state.rootCA == "insecure") {
|
if (_state.rootCA == "insecure") {
|
||||||
emsesp::EMSESP::logger().debug("Start insecure MQTT");
|
emsesp::EMSESP::logger().debug("Start insecure MQTT");
|
||||||
@@ -219,7 +201,7 @@ bool MqttSettingsService::configureMqtt() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MqttSettings::read(MqttSettings & settings, JsonObject root) {
|
void MqttSettings::read(MqttSettings & settings, JsonObject root) {
|
||||||
#ifndef TASMOTA_SDK
|
#ifndef NO_TLS_SUPPORT
|
||||||
root["enableTLS"] = settings.enableTLS;
|
root["enableTLS"] = settings.enableTLS;
|
||||||
root["rootCA"] = settings.rootCA;
|
root["rootCA"] = settings.rootCA;
|
||||||
#endif
|
#endif
|
||||||
@@ -258,7 +240,7 @@ StateUpdateResult MqttSettings::update(JsonObject root, MqttSettings & settings)
|
|||||||
MqttSettings newSettings;
|
MqttSettings newSettings;
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
|
|
||||||
#ifndef TASMOTA_SDK
|
#ifndef NO_TLS_SUPPORT
|
||||||
newSettings.enableTLS = root["enableTLS"];
|
newSettings.enableTLS = root["enableTLS"];
|
||||||
newSettings.rootCA = root["rootCA"] | "";
|
newSettings.rootCA = root["rootCA"] | "";
|
||||||
#else
|
#else
|
||||||
@@ -389,7 +371,7 @@ StateUpdateResult MqttSettings::update(JsonObject root, MqttSettings & settings)
|
|||||||
emsesp::EMSESP::mqtt_.set_publish_time_heartbeat(newSettings.publish_time_heartbeat);
|
emsesp::EMSESP::mqtt_.set_publish_time_heartbeat(newSettings.publish_time_heartbeat);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef TASMOTA_SDK
|
#ifndef NO_TLS_SUPPORT
|
||||||
// strip down to certificate only
|
// strip down to certificate only
|
||||||
newSettings.rootCA.replace("\r", "");
|
newSettings.rootCA.replace("\r", "");
|
||||||
newSettings.rootCA.replace("\n", "");
|
newSettings.rootCA.replace("\n", "");
|
||||||
|
|||||||
@@ -134,7 +134,6 @@ class MqttSettingsService : public StatefulService<MqttSettings> {
|
|||||||
// the MQTT client instance
|
// the MQTT client instance
|
||||||
MqttClient * _mqttClient;
|
MqttClient * _mqttClient;
|
||||||
|
|
||||||
void WiFiEvent(WiFiEvent_t event);
|
|
||||||
void onMqttConnect(bool sessionPresent);
|
void onMqttConnect(bool sessionPresent);
|
||||||
void onMqttDisconnect(espMqttClientTypes::DisconnectReason reason);
|
void onMqttDisconnect(espMqttClientTypes::DisconnectReason reason);
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -11,37 +11,18 @@ NTPSettingsService::NTPSettingsService(AsyncWebServer * server, FS * fs, Securit
|
|||||||
configureTime(request, json);
|
configureTime(request, json);
|
||||||
});
|
});
|
||||||
|
|
||||||
WiFi.onEvent([this](WiFiEvent_t event, WiFiEventInfo_t info) { WiFiEvent(event); });
|
|
||||||
addUpdateHandler([this] { configureNTP(); }, false);
|
addUpdateHandler([this] { configureNTP(); }, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NTPSettingsService::begin() {
|
void NTPSettingsService::begin() {
|
||||||
_fsPersistence.readFromFS();
|
_fsPersistence.readFromFS();
|
||||||
configureNTP();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// handles both WiFI and Ethernet
|
void NTPSettingsService::loop() {
|
||||||
void NTPSettingsService::WiFiEvent(WiFiEvent_t event) {
|
if (_connected != emsesp::EMSESP::system_.network_connected()) {
|
||||||
switch (event) {
|
_connected = emsesp::EMSESP::system_.network_connected();
|
||||||
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
|
|
||||||
case ARDUINO_EVENT_ETH_DISCONNECTED:
|
|
||||||
if (_connected && emsesp::EMSESP::system_.ntp_connected()) {
|
|
||||||
emsesp::EMSESP::logger().info("WiFi connection dropped, stopping NTP");
|
|
||||||
_connected = false;
|
|
||||||
configureNTP();
|
configureNTP();
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
|
|
||||||
case ARDUINO_EVENT_ETH_GOT_IP:
|
|
||||||
// emsesp::EMSESP::logger().info("Got IP address, starting NTP synchronization");
|
|
||||||
_connected = true;
|
|
||||||
configureNTP();
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://werner.rothschopf.net/microcontroller/202103_arduino_esp32_ntp_en.htm
|
// https://werner.rothschopf.net/microcontroller/202103_arduino_esp32_ntp_en.htm
|
||||||
@@ -55,9 +36,11 @@ void NTPSettingsService::configureNTP() {
|
|||||||
} else {
|
} else {
|
||||||
setenv("TZ", _state.tzFormat.c_str(), 1);
|
setenv("TZ", _state.tzFormat.c_str(), 1);
|
||||||
tzset();
|
tzset();
|
||||||
|
if (esp_sntp_enabled()) {
|
||||||
esp_sntp_stop();
|
esp_sntp_stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void NTPSettingsService::configureTime(AsyncWebServerRequest * request, JsonVariant json) {
|
void NTPSettingsService::configureTime(AsyncWebServerRequest * request, JsonVariant json) {
|
||||||
if (json.is<JsonObject>()) {
|
if (json.is<JsonObject>()) {
|
||||||
@@ -68,7 +51,12 @@ void NTPSettingsService::configureTime(AsyncWebServerRequest * request, JsonVari
|
|||||||
tm.tm_isdst = -1; // not set by strptime, tells mktime to determine daylightsaving
|
tm.tm_isdst = -1; // not set by strptime, tells mktime to determine daylightsaving
|
||||||
time_t time = mktime(&tm);
|
time_t time = mktime(&tm);
|
||||||
struct timeval now = {.tv_sec = time, .tv_usec = {}};
|
struct timeval now = {.tv_sec = time, .tv_usec = {}};
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32C3
|
||||||
|
// settimeofday and adjtime() does not work, unknown how to set time
|
||||||
|
emsesp::EMSESP::logger().warning("manual clock setting not possible");
|
||||||
|
#else
|
||||||
settimeofday(&now, nullptr);
|
settimeofday(&now, nullptr);
|
||||||
|
#endif
|
||||||
AsyncWebServerResponse * response = request->beginResponse(200);
|
AsyncWebServerResponse * response = request->beginResponse(200);
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ class NTPSettingsService : public StatefulService<NTPSettings> {
|
|||||||
NTPSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager);
|
NTPSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager);
|
||||||
|
|
||||||
void begin();
|
void begin();
|
||||||
|
void loop();
|
||||||
static void ntp_received(struct timeval * tv);
|
static void ntp_received(struct timeval * tv);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -51,7 +52,6 @@ class NTPSettingsService : public StatefulService<NTPSettings> {
|
|||||||
FSPersistence<NTPSettings> _fsPersistence;
|
FSPersistence<NTPSettings> _fsPersistence;
|
||||||
volatile bool _connected;
|
volatile bool _connected;
|
||||||
|
|
||||||
void WiFiEvent(WiFiEvent_t event);
|
|
||||||
void configureNTP();
|
void configureNTP();
|
||||||
void configureTime(AsyncWebServerRequest * request, JsonVariant json);
|
void configureTime(AsyncWebServerRequest * request, JsonVariant json);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ NetworkSettingsService::NetworkSettingsService(AsyncWebServer * server, FS * fs,
|
|||||||
, _stopping(false) {
|
, _stopping(false) {
|
||||||
addUpdateHandler([this] { reconfigureWiFiConnection(); }, false);
|
addUpdateHandler([this] { reconfigureWiFiConnection(); }, false);
|
||||||
// Eth is also bound to the WifiGeneric event handler
|
// Eth is also bound to the WifiGeneric event handler
|
||||||
WiFi.onEvent([this](WiFiEvent_t event, WiFiEventInfo_t info) { WiFiEvent(event, info); });
|
// Network.onEvent([this](arduino_event_id_t event, arduino_event_info_t info) { WiFiEvent(event, info); });
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool formatBssid(const String & bssid, uint8_t (&mac)[6]) {
|
static bool formatBssid(const String & bssid, uint8_t (&mac)[6]) {
|
||||||
@@ -34,8 +34,8 @@ void NetworkSettingsService::begin() {
|
|||||||
WiFi.persistent(false);
|
WiFi.persistent(false);
|
||||||
WiFi.setAutoReconnect(false);
|
WiFi.setAutoReconnect(false);
|
||||||
|
|
||||||
WiFi.mode(WIFI_MODE_MAX);
|
WiFi.mode(WIFI_STA);
|
||||||
WiFi.mode(WIFI_MODE_NULL);
|
WiFi.mode(WIFI_OFF);
|
||||||
|
|
||||||
// scan settings give connect issues since arduino 2.0.14 and arduino 3.x.x with some wifi systems
|
// 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.setScanMethod(WIFI_ALL_CHANNEL_SCAN); // default is FAST_SCAN
|
||||||
@@ -62,28 +62,124 @@ void NetworkSettingsService::loop() {
|
|||||||
_lastConnectionAttempt = currentMillis;
|
_lastConnectionAttempt = currentMillis;
|
||||||
manageSTA();
|
manageSTA();
|
||||||
}
|
}
|
||||||
|
static uint8_t connect = 0;
|
||||||
|
enum uint8_t {
|
||||||
|
CONNECT_IDLE = 0,
|
||||||
|
CONNECT_WAIT_ETH,
|
||||||
|
CONNECT_WAIT_IP4,
|
||||||
|
CONNECT_WAIT_ETH_IP4,
|
||||||
|
CONNECT_WAIT_IP6,
|
||||||
|
CONNECT_WAIT_ETH_IP6,
|
||||||
|
CONNECT_ETH_ACTIVE,
|
||||||
|
CONNECT_WIFI_ACTIVE
|
||||||
|
};
|
||||||
|
switch (connect) {
|
||||||
|
default:
|
||||||
|
connect = CONNECT_IDLE;
|
||||||
|
break;
|
||||||
|
case CONNECT_IDLE:
|
||||||
|
if (ETH.started() && _state.ssid.length() == 0) {
|
||||||
|
emsesp::EMSESP::logger().info("ETH started");
|
||||||
|
ETH.setHostname(emsesp::EMSESP::system_.hostname().c_str());
|
||||||
|
ETH.enableIPv6(true);
|
||||||
|
if (_state.staticIPConfig) {
|
||||||
|
ETH.config(_state.localIP, _state.gatewayIP, _state.subnetMask, _state.dnsIP1, _state.dnsIP2);
|
||||||
|
}
|
||||||
|
connect = CONNECT_WAIT_ETH;
|
||||||
|
}
|
||||||
|
if (WiFi.isConnected()) {
|
||||||
|
emsesp::EMSESP::logger().info("Wifi connected");
|
||||||
|
if (_state.tx_power == 0) {
|
||||||
|
setWiFiPowerOnRSSI();
|
||||||
|
}
|
||||||
|
mDNS_start();
|
||||||
|
emsesp::EMSESP::system_.has_ipv6(true);
|
||||||
|
connect = CONNECT_WAIT_IP4;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CONNECT_WAIT_ETH:
|
||||||
|
if (ETH.connected()) {
|
||||||
|
emsesp::EMSESP::logger().info("ETH connected");
|
||||||
|
emsesp::EMSESP::system_.ethernet_connected(true);
|
||||||
|
mDNS_start();
|
||||||
|
emsesp::EMSESP::system_.has_ipv6(true);
|
||||||
|
connect = CONNECT_WAIT_ETH_IP4;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CONNECT_WAIT_ETH_IP4:
|
||||||
|
if (ETH.hasIP()) {
|
||||||
|
emsesp::EMSESP::logger().info("ETH IPv4: %s", ETH.localIP().toString().c_str());
|
||||||
|
connect = CONNECT_WAIT_ETH_IP6;
|
||||||
|
}
|
||||||
|
if (!ETH.connected()) {
|
||||||
|
connect = CONNECT_ETH_ACTIVE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CONNECT_WAIT_ETH_IP6:
|
||||||
|
if (ETH.hasLinkLocalIPv6() && ETH.hasGlobalIPv6()) {
|
||||||
|
emsesp::EMSESP::system_.has_ipv6(true);
|
||||||
|
connect = CONNECT_ETH_ACTIVE;
|
||||||
|
}
|
||||||
|
if (!ETH.connected()) {
|
||||||
|
connect = CONNECT_ETH_ACTIVE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CONNECT_ETH_ACTIVE:
|
||||||
|
if (!ETH.connected()) {
|
||||||
|
emsesp::EMSESP::logger().info("ETH disconnected");
|
||||||
|
emsesp::EMSESP::system_.ethernet_connected(false);
|
||||||
|
emsesp::EMSESP::system_.has_ipv6(false);
|
||||||
|
connect = CONNECT_IDLE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CONNECT_WAIT_IP4:
|
||||||
|
if (!WiFi.localIP().toString().isEmpty()) {
|
||||||
|
emsesp::EMSESP::logger().info("Wifi IPv4: %s", WiFi.localIP().toString().c_str());
|
||||||
|
connect = CONNECT_WAIT_IP6;
|
||||||
|
}
|
||||||
|
if (!WiFi.isConnected()) {
|
||||||
|
connect = CONNECT_ETH_ACTIVE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CONNECT_WAIT_IP6:
|
||||||
|
if (WiFi.linkLocalIPv6().toString() != "::" && WiFi.globalIPv6().toString() != "::") {
|
||||||
|
emsesp::EMSESP::logger().info("Wifi IPv6: %s, %s", WiFi.linkLocalIPv6().toString().c_str(), WiFi.globalIPv6().toString().c_str());
|
||||||
|
emsesp::EMSESP::system_.has_ipv6(true);
|
||||||
|
connect = CONNECT_WIFI_ACTIVE;
|
||||||
|
}
|
||||||
|
if (!WiFi.isConnected()) {
|
||||||
|
connect = CONNECT_WIFI_ACTIVE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CONNECT_WIFI_ACTIVE:
|
||||||
|
if (!WiFi.isConnected()) {
|
||||||
|
emsesp::EMSESP::logger().info("WiFi disconnected");
|
||||||
|
if (_stopping) {
|
||||||
|
_lastConnectionAttempt = 0;
|
||||||
|
_stopping = false;
|
||||||
|
}
|
||||||
|
emsesp::EMSESP::system_.has_ipv6(false);
|
||||||
|
connect = CONNECT_IDLE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkSettingsService::manageSTA() {
|
void NetworkSettingsService::manageSTA() {
|
||||||
// Abort if already connected, or if we have no SSID
|
// Abort if already connected, or if we have no SSID
|
||||||
if (WiFi.isConnected() || _state.ssid.length() == 0) {
|
if (WiFi.isConnected() || _state.ssid.length() == 0) {
|
||||||
#if ESP_IDF_VERSION_MAJOR >= 5
|
|
||||||
if (_state.ssid.length() == 0) {
|
|
||||||
ETH.enableIPv6(true);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connect or reconnect as required
|
// Connect or reconnect as required
|
||||||
if ((WiFi.getMode() & WIFI_STA) == 0) {
|
if ((WiFi.getMode() & WIFI_STA) == 0) {
|
||||||
#if ESP_IDF_VERSION_MAJOR >= 5
|
WiFi.setHostname(_state.hostname.c_str()); // updates shared default_hostname buffer
|
||||||
|
WiFi.enableSTA(true); // creates the STA netif
|
||||||
|
WiFi.STA.setHostname(_state.hostname.c_str()); // pushes to esp_netif_set_hostname
|
||||||
WiFi.enableIPv6(true);
|
WiFi.enableIPv6(true);
|
||||||
#endif
|
|
||||||
if (_state.staticIPConfig) {
|
if (_state.staticIPConfig) {
|
||||||
WiFi.config(_state.localIP, _state.gatewayIP, _state.subnetMask, _state.dnsIP1, _state.dnsIP2); // configure for static IP
|
WiFi.config(_state.localIP, _state.gatewayIP, _state.subnetMask, _state.dnsIP1, _state.dnsIP2); // configure for static IP
|
||||||
}
|
}
|
||||||
WiFi.setHostname(_state.hostname.c_str()); // set hostname
|
|
||||||
|
|
||||||
// www.esp32.com/viewtopic.php?t=12055
|
// www.esp32.com/viewtopic.php?t=12055
|
||||||
if (_state.bandwidth20) {
|
if (_state.bandwidth20) {
|
||||||
@@ -293,7 +389,7 @@ const char * NetworkSettingsService::disconnectReason(uint8_t code) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// handles both WiFI and Ethernet
|
// handles both WiFI and Ethernet
|
||||||
void NetworkSettingsService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
|
void NetworkSettingsService::WiFiEvent(arduino_event_id_t event, arduino_event_info_t info) {
|
||||||
#ifndef EMSESP_STANDALONE
|
#ifndef EMSESP_STANDALONE
|
||||||
|
|
||||||
switch (event) {
|
switch (event) {
|
||||||
@@ -305,7 +401,7 @@ void NetworkSettingsService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
|
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
|
||||||
connectcount_++; // count the number of WiFi reconnects
|
connectcount_ = connectcount_ + 1; // count the number of WiFi reconnects
|
||||||
emsesp::EMSESP::logger().warning("WiFi disconnected (#%d). Reason: %s (%d)",
|
emsesp::EMSESP::logger().warning("WiFi disconnected (#%d). Reason: %s (%d)",
|
||||||
connectcount_,
|
connectcount_,
|
||||||
disconnectReason(info.wifi_sta_disconnected.reason),
|
disconnectReason(info.wifi_sta_disconnected.reason),
|
||||||
@@ -325,11 +421,11 @@ void NetworkSettingsService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ARDUINO_EVENT_ETH_START:
|
case ARDUINO_EVENT_ETH_START:
|
||||||
// configure for static IP
|
// apply hostname FIRST so DHCP DISCOVER carries the correct name
|
||||||
|
ETH.setHostname(emsesp::EMSESP::system_.hostname().c_str());
|
||||||
if (_state.staticIPConfig) {
|
if (_state.staticIPConfig) {
|
||||||
ETH.config(_state.localIP, _state.gatewayIP, _state.subnetMask, _state.dnsIP1, _state.dnsIP2);
|
ETH.config(_state.localIP, _state.gatewayIP, _state.subnetMask, _state.dnsIP1, _state.dnsIP2);
|
||||||
}
|
}
|
||||||
ETH.setHostname(emsesp::EMSESP::system_.hostname().c_str());
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ARDUINO_EVENT_ETH_GOT_IP:
|
case ARDUINO_EVENT_ETH_GOT_IP:
|
||||||
@@ -360,25 +456,15 @@ void NetworkSettingsService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info)
|
|||||||
if (_state.tx_power == 0) {
|
if (_state.tx_power == 0) {
|
||||||
setWiFiPowerOnRSSI();
|
setWiFiPowerOnRSSI();
|
||||||
}
|
}
|
||||||
#if ESP_IDF_VERSION_MAJOR < 5
|
|
||||||
WiFi.enableIpV6(); // force ipv6
|
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ARDUINO_EVENT_ETH_CONNECTED:
|
case ARDUINO_EVENT_ETH_CONNECTED:
|
||||||
#if ESP_IDF_VERSION_MAJOR < 5
|
|
||||||
ETH.enableIpV6(); // force ipv6
|
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// IPv6 specific - WiFi/Eth
|
// IPv6 specific - WiFi/Eth
|
||||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP6:
|
case ARDUINO_EVENT_WIFI_STA_GOT_IP6:
|
||||||
case ARDUINO_EVENT_ETH_GOT_IP6: {
|
case ARDUINO_EVENT_ETH_GOT_IP6: {
|
||||||
#if !TASMOTA_SDK && ESP_IDF_VERSION_MAJOR < 5
|
|
||||||
auto ip6 = IPv6Address((uint8_t *)info.got_ip6.ip6_info.ip.addr).toString();
|
|
||||||
#else
|
|
||||||
auto ip6 = IPAddress(IPv6, (uint8_t *)info.got_ip6.ip6_info.ip.addr, 0).toString();
|
auto ip6 = IPAddress(IPv6, (uint8_t *)info.got_ip6.ip6_info.ip.addr, 0).toString();
|
||||||
#endif
|
|
||||||
const char * link = event == ARDUINO_EVENT_ETH_GOT_IP6 ? "Eth" : "WiFi";
|
const char * link = event == ARDUINO_EVENT_ETH_GOT_IP6 ? "Eth" : "WiFi";
|
||||||
if (ip6.startsWith("fe80")) {
|
if (ip6.startsWith("fe80")) {
|
||||||
emsesp::EMSESP::logger().info("IPv6 (%s) local: %s", link, ip6.c_str());
|
emsesp::EMSESP::logger().info("IPv6 (%s) local: %s", link, ip6.c_str());
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ class NetworkSettingsService : public StatefulService<NetworkSettings> {
|
|||||||
|
|
||||||
volatile uint16_t connectcount_ = 0; // number of wifi reconnects
|
volatile uint16_t connectcount_ = 0; // number of wifi reconnects
|
||||||
|
|
||||||
void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info);
|
void WiFiEvent(arduino_event_id_t event, arduino_event_info_t info);
|
||||||
void mDNS_start() const;
|
void mDNS_start() const;
|
||||||
const char * disconnectReason(uint8_t code);
|
const char * disconnectReason(uint8_t code);
|
||||||
void reconfigureWiFiConnection();
|
void reconfigureWiFiConnection();
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include <emsesp.h>
|
#include <emsesp.h>
|
||||||
|
|
||||||
#ifdef TASMOTA_SDK
|
#ifdef NO_TLS_SUPPORT
|
||||||
#include "lwip/dns.h"
|
#include "lwip/dns.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -32,21 +32,12 @@ void NetworkStatus::networkStatus(AsyncWebServerRequest * request) {
|
|||||||
if (ethernet_connected) {
|
if (ethernet_connected) {
|
||||||
// Ethernet
|
// Ethernet
|
||||||
root["local_ip"] = ETH.localIP().toString();
|
root["local_ip"] = ETH.localIP().toString();
|
||||||
#if ESP_IDF_VERSION_MAJOR < 5
|
|
||||||
root["local_ipv6"] = ETH.localIPv6().toString();
|
|
||||||
#else
|
|
||||||
root["local_ipv6"] = ETH.linkLocalIPv6().toString();
|
root["local_ipv6"] = ETH.linkLocalIPv6().toString();
|
||||||
#endif
|
|
||||||
root["mac_address"] = ETH.macAddress();
|
root["mac_address"] = ETH.macAddress();
|
||||||
root["subnet_mask"] = ETH.subnetMask().toString();
|
root["subnet_mask"] = ETH.subnetMask().toString();
|
||||||
root["gateway_ip"] = ETH.gatewayIP().toString();
|
root["gateway_ip"] = ETH.gatewayIP().toString();
|
||||||
#ifdef TASMOTA_SDK
|
|
||||||
IPAddress dnsIP1 = IPAddress(dns_getserver(0));
|
|
||||||
IPAddress dnsIP2 = IPAddress(dns_getserver(1));
|
|
||||||
#else
|
|
||||||
IPAddress dnsIP1 = ETH.dnsIP(0);
|
IPAddress dnsIP1 = ETH.dnsIP(0);
|
||||||
IPAddress dnsIP2 = ETH.dnsIP(1);
|
IPAddress dnsIP2 = ETH.dnsIP(1);
|
||||||
#endif
|
|
||||||
if (IPUtils::isSet(dnsIP1)) {
|
if (IPUtils::isSet(dnsIP1)) {
|
||||||
root["dns_ip_1"] = dnsIP1.toString();
|
root["dns_ip_1"] = dnsIP1.toString();
|
||||||
}
|
}
|
||||||
@@ -55,11 +46,7 @@ void NetworkStatus::networkStatus(AsyncWebServerRequest * request) {
|
|||||||
}
|
}
|
||||||
} else if (wifi_status == WL_CONNECTED) {
|
} else if (wifi_status == WL_CONNECTED) {
|
||||||
root["local_ip"] = WiFi.localIP().toString();
|
root["local_ip"] = WiFi.localIP().toString();
|
||||||
#if ESP_IDF_VERSION_MAJOR < 5
|
|
||||||
root["local_ipv6"] = WiFi.localIPv6().toString();
|
|
||||||
#else
|
|
||||||
root["local_ipv6"] = WiFi.linkLocalIPv6().toString();
|
root["local_ipv6"] = WiFi.linkLocalIPv6().toString();
|
||||||
#endif
|
|
||||||
root["mac_address"] = WiFi.macAddress();
|
root["mac_address"] = WiFi.macAddress();
|
||||||
root["rssi"] = WiFi.RSSI();
|
root["rssi"] = WiFi.RSSI();
|
||||||
root["ssid"] = WiFi.SSID();
|
root["ssid"] = WiFi.SSID();
|
||||||
@@ -71,14 +58,8 @@ void NetworkStatus::networkStatus(AsyncWebServerRequest * request) {
|
|||||||
if (WiFi.gatewayIP() != INADDR_NONE) {
|
if (WiFi.gatewayIP() != INADDR_NONE) {
|
||||||
root["gateway_ip"] = WiFi.gatewayIP().toString();
|
root["gateway_ip"] = WiFi.gatewayIP().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TASMOTA_SDK
|
|
||||||
IPAddress dnsIP1 = IPAddress(dns_getserver(0));
|
|
||||||
IPAddress dnsIP2 = IPAddress(dns_getserver(1));
|
|
||||||
#else
|
|
||||||
IPAddress dnsIP1 = WiFi.dnsIP(0);
|
IPAddress dnsIP1 = WiFi.dnsIP(0);
|
||||||
IPAddress dnsIP2 = WiFi.dnsIP(1);
|
IPAddress dnsIP2 = WiFi.dnsIP(1);
|
||||||
#endif
|
|
||||||
if (dnsIP1 != INADDR_NONE) {
|
if (dnsIP1 != INADDR_NONE) {
|
||||||
root["dns_ip_1"] = dnsIP1.toString();
|
root["dns_ip_1"] = dnsIP1.toString();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -347,23 +347,13 @@ void AnalogSensor::reload(bool get_nvs) {
|
|||||||
sensor.polltime_ = sensor.value() != 0 ? uuid::get_uptime() + (sensor.factor() * 1000) : 0;
|
sensor.polltime_ = sensor.value() != 0 ? uuid::get_uptime() + (sensor.factor() * 1000) : 0;
|
||||||
} else if (sensor.type() >= AnalogType::PWM_0 && sensor.type() <= AnalogType::PWM_2) {
|
} else if (sensor.type() >= AnalogType::PWM_0 && sensor.type() <= AnalogType::PWM_2) {
|
||||||
LOG_DEBUG("PWM output on GPIO %02d", sensor.gpio());
|
LOG_DEBUG("PWM output on GPIO %02d", sensor.gpio());
|
||||||
#if ESP_IDF_VERSION_MAJOR >= 5
|
|
||||||
ledcAttach(sensor.gpio(), sensor.factor(), 13);
|
ledcAttach(sensor.gpio(), sensor.factor(), 13);
|
||||||
#else
|
|
||||||
uint8_t channel = sensor.type() - AnalogType::PWM_0;
|
|
||||||
ledcSetup(channel, sensor.factor(), 13);
|
|
||||||
ledcAttachPin(sensor.gpio(), channel);
|
|
||||||
#endif
|
|
||||||
if (sensor.offset() > 100) {
|
if (sensor.offset() > 100) {
|
||||||
sensor.set_offset(100);
|
sensor.set_offset(100);
|
||||||
} else if (sensor.offset() < 0) {
|
} else if (sensor.offset() < 0) {
|
||||||
sensor.set_offset(0);
|
sensor.set_offset(0);
|
||||||
}
|
}
|
||||||
#if ESP_IDF_VERSION_MAJOR >= 5
|
|
||||||
ledcWrite(sensor.gpio(), (uint32_t)(sensor.offset() * 8191 / 100));
|
ledcWrite(sensor.gpio(), (uint32_t)(sensor.offset() * 8191 / 100));
|
||||||
#else
|
|
||||||
ledcWrite(channel, (uint32_t)(sensor.offset() * 8191 / 100));
|
|
||||||
#endif
|
|
||||||
sensor.set_value(sensor.offset());
|
sensor.set_value(sensor.offset());
|
||||||
sensor.set_uom(DeviceValueUOM::PERCENT);
|
sensor.set_uom(DeviceValueUOM::PERCENT);
|
||||||
publish_sensor(sensor);
|
publish_sensor(sensor);
|
||||||
@@ -1041,12 +1031,7 @@ bool AnalogSensor::command_setvalue(const char * value, const int8_t gpio) {
|
|||||||
}
|
}
|
||||||
sensor.set_offset(val);
|
sensor.set_offset(val);
|
||||||
sensor.set_value(val);
|
sensor.set_value(val);
|
||||||
#if ESP_IDF_VERSION_MAJOR >= 5
|
|
||||||
ledcWrite(sensor.gpio(), (uint32_t)(sensor.offset() * 8191 / 100));
|
ledcWrite(sensor.gpio(), (uint32_t)(sensor.offset() * 8191 / 100));
|
||||||
#else
|
|
||||||
uint8_t channel = sensor.type() - AnalogType::PWM_0;
|
|
||||||
ledcWrite(channel, (uint32_t)(val * 8191 / 100));
|
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -285,6 +285,8 @@ enum {
|
|||||||
#define EMSESP_PLATFORM "ESP32S3"
|
#define EMSESP_PLATFORM "ESP32S3"
|
||||||
#elif CONFIG_IDF_TARGET_ESP32 || EMSESP_STANDALONE
|
#elif CONFIG_IDF_TARGET_ESP32 || EMSESP_STANDALONE
|
||||||
#define EMSESP_PLATFORM "ESP32"
|
#define EMSESP_PLATFORM "ESP32"
|
||||||
|
#elif CONFIG_IDF_TARGET_ESP32C6
|
||||||
|
#define EMSESP_PLATFORM "ESP32C6"
|
||||||
#else
|
#else
|
||||||
#error Target CONFIG_IDF_TARGET is not supported
|
#error Target CONFIG_IDF_TARGET is not supported
|
||||||
#endif
|
#endif
|
||||||
@@ -293,12 +295,9 @@ enum {
|
|||||||
#ifndef STRINGIZE
|
#ifndef STRINGIZE
|
||||||
#define STRINGIZE(s) #s
|
#define STRINGIZE(s) #s
|
||||||
#endif
|
#endif
|
||||||
#ifdef TASMOTA_SDK
|
|
||||||
#define ARDUINO_VERSION_STR(major, minor, patch) "Tasmota Arduino v" STRINGIZE(major) "." STRINGIZE(minor) "." STRINGIZE(patch)
|
#define ARDUINO_VERSION_STR(major, minor, patch) "Tasmota Arduino v" STRINGIZE(major) "." STRINGIZE(minor) "." STRINGIZE(patch)
|
||||||
#else
|
|
||||||
#define ARDUINO_VERSION_STR(major, minor, patch) "ESP32 Arduino v" STRINGIZE(major) "." STRINGIZE(minor) "." STRINGIZE(patch)
|
|
||||||
#endif
|
|
||||||
#define ARDUINO_VERSION ARDUINO_VERSION_STR(ESP_ARDUINO_VERSION_MAJOR, ESP_ARDUINO_VERSION_MINOR, ESP_ARDUINO_VERSION_PATCH)
|
#define ARDUINO_VERSION ARDUINO_VERSION_STR(ESP_ARDUINO_VERSION_MAJOR, ESP_ARDUINO_VERSION_MINOR, ESP_ARDUINO_VERSION_PATCH)
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1727,6 +1727,8 @@ void EMSESP::start() {
|
|||||||
#ifndef EMSESP_STANDALONE
|
#ifndef EMSESP_STANDALONE
|
||||||
if (factory_settings) {
|
if (factory_settings) {
|
||||||
LOG_WARNING("No settings found on filesystem. Using factory settings.");
|
LOG_WARNING("No settings found on filesystem. Using factory settings.");
|
||||||
|
// make sure OTAdata is updated with core3 format
|
||||||
|
esp_ota_set_boot_partition(esp_ota_get_running_partition());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -380,12 +380,16 @@ std::string commands(std::string & expr, bool quotes) {
|
|||||||
if (return_code != CommandRet::OK && return_code != CommandRet::NO_VALUE) {
|
if (return_code != CommandRet::OK && return_code != CommandRet::NO_VALUE) {
|
||||||
return expr = "";
|
return expr = "";
|
||||||
}
|
}
|
||||||
|
std::string data;
|
||||||
std::string data = output["api_data"] | "";
|
if (output["api_data"].is<std::string>()) {
|
||||||
|
data = output["api_data"].as<std::string>();
|
||||||
if (!isnum(data) && quotes) {
|
if (!isnum(data) && quotes) {
|
||||||
data.insert(data.begin(), '"');
|
data.insert(data.begin(), '"');
|
||||||
data.insert(data.end(), '"');
|
data.insert(data.end(), '"');
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
serializeJson(output, data);
|
||||||
|
}
|
||||||
expr.replace(f, l, data);
|
expr.replace(f, l, data);
|
||||||
e = f + data.length();
|
e = f + data.length();
|
||||||
expr_new = Helpers::toLower(expr);
|
expr_new = Helpers::toLower(expr);
|
||||||
@@ -700,7 +704,6 @@ std::string compute(const std::string & expr) {
|
|||||||
std::string cmd = expr_new.substr(f, e - f).c_str();
|
std::string cmd = expr_new.substr(f, e - f).c_str();
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
if (DeserializationError::Ok == deserializeJson(doc, cmd)) {
|
if (DeserializationError::Ok == deserializeJson(doc, cmd)) {
|
||||||
HTTPClient * http = new HTTPClient;
|
|
||||||
std::string url, header_s, value_s, method_s, key_s, keys_s;
|
std::string url, header_s, value_s, method_s, key_s, keys_s;
|
||||||
// search keys lower case
|
// search keys lower case
|
||||||
for (JsonPair p : doc.as<JsonObject>()) {
|
for (JsonPair p : doc.as<JsonObject>()) {
|
||||||
@@ -720,33 +723,126 @@ std::string compute(const std::string & expr) {
|
|||||||
keys_s = p.key().c_str();
|
keys_s = p.key().c_str();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (http->begin(url.c_str())) {
|
bool content_set = false;
|
||||||
|
std::string value = doc[value_s] | "";
|
||||||
|
std::string method = doc[method_s] | "GET";
|
||||||
|
if (value.length()) {
|
||||||
|
method = "POST";
|
||||||
|
}
|
||||||
|
std::string result;
|
||||||
int httpResult = 0;
|
int httpResult = 0;
|
||||||
|
#ifndef NO_TLS_SUPPORT
|
||||||
|
if (Helpers::toLower(url.c_str()).starts_with("https://")) {
|
||||||
|
WiFiClient * basic_client = new WiFiClient;
|
||||||
|
ESP_SSLClient * ssl_client = new ESP_SSLClient;
|
||||||
|
ssl_client->setInsecure(); // with root CA we should set here: ssl_client->setCACert(rootCACert);
|
||||||
|
ssl_client->setBufferSizes(1024, 1024);
|
||||||
|
ssl_client->setSessionTimeout(120); // Set the timeout in seconds (>=120 seconds)
|
||||||
|
url.replace(0, 8, "");
|
||||||
|
std::string host = url;
|
||||||
|
auto index = url.find_first_of('/');
|
||||||
|
if (index != std::string::npos) {
|
||||||
|
host = url.substr(0, index);
|
||||||
|
url.replace(0, index, "");
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
index = host.find_first_of('@');
|
||||||
|
std::string auth;
|
||||||
|
if (index != std::string::npos) {
|
||||||
|
auth = base64::encode(host.substr(0, index));
|
||||||
|
host.replace(0, index, "");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
ssl_client->setClient(basic_client);
|
||||||
|
if (ssl_client->connect(host.c_str(), 443)) {
|
||||||
|
if (value.length() || Helpers::toLower(method) == "post") {
|
||||||
|
ssl_client->print("POST ");
|
||||||
|
ssl_client->print(url.c_str());
|
||||||
|
ssl_client->println(" HTTP/1.1");
|
||||||
|
ssl_client->print("Host: ");
|
||||||
|
ssl_client->println(host.c_str());
|
||||||
|
for (JsonPair p : doc[header_s].as<JsonObject>()) {
|
||||||
|
content_set |= (emsesp::Helpers::toLower(p.key().c_str()) == "content-type");
|
||||||
|
ssl_client->print(p.key().c_str());
|
||||||
|
ssl_client->print(": ");
|
||||||
|
ssl_client->println(p.value().as<std::string>().c_str());
|
||||||
|
}
|
||||||
|
if (!content_set) {
|
||||||
|
ssl_client->print("Content-Type: ");
|
||||||
|
if (value.starts_with('{')) {
|
||||||
|
ssl_client->println(asyncsrv::T_application_json);
|
||||||
|
} else {
|
||||||
|
ssl_client->println(asyncsrv::T_text_plain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ssl_client->print("Content-Length: ");
|
||||||
|
ssl_client->println(value.length());
|
||||||
|
ssl_client->println("Connection: close");
|
||||||
|
ssl_client->print("\r\n");
|
||||||
|
ssl_client->print(value.c_str());
|
||||||
|
} else {
|
||||||
|
ssl_client->print("GET ");
|
||||||
|
ssl_client->print(url.c_str());
|
||||||
|
ssl_client->println(" HTTP/1.1");
|
||||||
|
ssl_client->print("Host: ");
|
||||||
|
ssl_client->println(host.c_str());
|
||||||
|
for (JsonPair p : doc[header_s].as<JsonObject>()) {
|
||||||
|
ssl_client->print(p.key().c_str());
|
||||||
|
ssl_client->print(": ");
|
||||||
|
ssl_client->println(p.value().as<std::string>().c_str());
|
||||||
|
}
|
||||||
|
ssl_client->println("Connection: close");
|
||||||
|
}
|
||||||
|
auto ms = millis();
|
||||||
|
while (!ssl_client->available() && millis() - ms < 3000) {
|
||||||
|
delay(0);
|
||||||
|
}
|
||||||
|
while (ssl_client->available()) {
|
||||||
|
result += (char)ssl_client->read();
|
||||||
|
}
|
||||||
|
ssl_client->stop();
|
||||||
|
index = result.find_first_of(' ');
|
||||||
|
if (index != std::string::npos) {
|
||||||
|
httpResult = stoi(result.substr(index + 1, 3));
|
||||||
|
}
|
||||||
|
index = result.find("\r\n\r\n");
|
||||||
|
if (index != std::string::npos) {
|
||||||
|
result.replace(0, index + 4, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete ssl_client;
|
||||||
|
delete basic_client;
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
if (Helpers::toLower(url.c_str()).starts_with("http://")) {
|
||||||
|
HTTPClient * http = new HTTPClient;
|
||||||
|
if (http->begin(url.c_str())) {
|
||||||
for (JsonPair p : doc[header_s].as<JsonObject>()) {
|
for (JsonPair p : doc[header_s].as<JsonObject>()) {
|
||||||
http->addHeader(p.key().c_str(), p.value().as<std::string>().c_str());
|
http->addHeader(p.key().c_str(), p.value().as<std::string>().c_str());
|
||||||
|
content_set |= (emsesp::Helpers::toLower(p.key().c_str()) == "content-type");
|
||||||
}
|
}
|
||||||
std::string value = doc[value_s] | "";
|
|
||||||
std::string method = doc[method_s] | "get";
|
|
||||||
|
|
||||||
// if there is data, force a POST
|
|
||||||
if (value.length() || Helpers::toLower(method) == "post") {
|
if (value.length() || Helpers::toLower(method) == "post") {
|
||||||
if (value.find_first_of('{') != std::string::npos) {
|
if (!content_set) {
|
||||||
http->addHeader(asyncsrv::T_Content_Type, asyncsrv::T_application_json, false); // auto-set to JSON
|
http->addHeader("Content-Type", value.starts_with('{') ? asyncsrv::T_application_json : asyncsrv::T_text_plain);
|
||||||
}
|
}
|
||||||
httpResult = http->POST(value.c_str());
|
httpResult = http->POST(value.c_str());
|
||||||
} else {
|
} else {
|
||||||
httpResult = http->GET(); // normal GET
|
httpResult = http->GET(); // normal GET
|
||||||
}
|
}
|
||||||
|
|
||||||
if (httpResult > 0) {
|
if (httpResult > 0) {
|
||||||
std::string result = http->getString().c_str();
|
result = http->getString().c_str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
http->end();
|
||||||
|
delete http;
|
||||||
|
}
|
||||||
|
if (httpResult == 200) {
|
||||||
std::string key = doc[key_s] | "";
|
std::string key = doc[key_s] | "";
|
||||||
JsonDocument keys_doc; // JsonDocument to hold "keys" after doc is parsed with HTTP body
|
JsonDocument keys_doc; // JsonDocument to hold "keys" after doc is parsed with HTTP body
|
||||||
if (doc[keys_s].is<JsonArray>()) {
|
if (doc[keys_s].is<JsonArray>()) {
|
||||||
keys_doc.set(doc[keys_s].as<JsonArray>());
|
keys_doc.set(doc[keys_s].as<JsonArray>());
|
||||||
}
|
}
|
||||||
JsonArray keys = keys_doc.as<JsonArray>();
|
JsonArray keys = keys_doc.as<JsonArray>();
|
||||||
|
|
||||||
if (key.length() || !keys.isNull()) {
|
if (key.length() || !keys.isNull()) {
|
||||||
doc.clear();
|
doc.clear();
|
||||||
if (DeserializationError::Ok == deserializeJson(doc, result)) {
|
if (DeserializationError::Ok == deserializeJson(doc, result)) {
|
||||||
@@ -767,10 +863,9 @@ std::string compute(const std::string & expr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expr_new.replace(f, e - f, result.c_str());
|
expr_new.replace(f, e - f, result);
|
||||||
}
|
} else if (httpResult != 0) {
|
||||||
http->end();
|
EMSESP::logger().warning("URL command failed with https code: %d, response: %s", httpResult, result.c_str());
|
||||||
delete http;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f = expr_new.find_first_of('{', e);
|
f = expr_new.find_first_of('{', e);
|
||||||
|
|||||||
@@ -37,6 +37,15 @@
|
|||||||
#include "../test/test.h"
|
#include "../test/test.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef NO_TLS_SUPPORT
|
||||||
|
#define ENABLE_SMTP
|
||||||
|
#define USE_ESP_SSLCLIENT
|
||||||
|
#define READYCLIENT_SSL_CLIENT ESP_SSLClient
|
||||||
|
#define READYCLIENT_TYPE_1 // TYPE 1 when using ESP_SSLClient
|
||||||
|
#include <ESP_SSLClient.h>
|
||||||
|
#include <ReadyMail.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
// Languages supported. Note: the order is important
|
// Languages supported. Note: the order is important
|
||||||
@@ -105,6 +114,115 @@ bool System::command_send(const char * value, const int8_t id) {
|
|||||||
return EMSESP::txservice_.send_raw(value); // ignore id
|
return EMSESP::txservice_.send_raw(value); // ignore id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool System::command_sendmail(const char * value, const int8_t id) {
|
||||||
|
bool enabled = false;
|
||||||
|
bool ssl, starttls;
|
||||||
|
uint16_t port;
|
||||||
|
String server, login, pass, sender, recp, subject;
|
||||||
|
EMSESP::webSettingsService.read([&](WebSettings & settings) {
|
||||||
|
enabled = settings.email_enabled;
|
||||||
|
ssl = settings.email_ssl;
|
||||||
|
starttls = settings.email_starttls;
|
||||||
|
server = settings.email_server;
|
||||||
|
port = settings.email_port;
|
||||||
|
login = settings.email_login;
|
||||||
|
pass = settings.email_pass;
|
||||||
|
sender = settings.email_sender;
|
||||||
|
recp = settings.email_recp;
|
||||||
|
subject = settings.email_subject;
|
||||||
|
});
|
||||||
|
if (!enabled) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
LOG_DEBUG("Command sendmail port %d%s called with '%s'", port, ssl ? " (SSL)" : starttls ? " (STARTTLS)" : "", value);
|
||||||
|
// LOG_DEBUG("Command sendmail port %d called with '%s'", port, value);
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
|
#ifndef NO_TLS_SUPPORT
|
||||||
|
WiFiClient * basic_client = new WiFiClient;
|
||||||
|
ESP_SSLClient * ssl_client = new ESP_SSLClient;
|
||||||
|
ReadyClient * r_client = new ReadyClient(*ssl_client);
|
||||||
|
SMTPClient * smtp = new SMTPClient(*r_client);
|
||||||
|
|
||||||
|
ssl_client->setClient(basic_client);
|
||||||
|
ssl_client->setInsecure();
|
||||||
|
ssl_client->setBufferSizes(1024, 1024);
|
||||||
|
r_client->addPort(port, starttls ? readymail_protocol_tls : ssl ? readymail_protocol_ssl : readymail_protocol_plain_text);
|
||||||
|
|
||||||
|
// smtp->connect(server, port, sendmailCallback);
|
||||||
|
smtp->connect(server, port);
|
||||||
|
if (!smtp->isConnected()) {
|
||||||
|
LOG_ERROR("Sendmail connection error");
|
||||||
|
delete smtp;
|
||||||
|
delete r_client;
|
||||||
|
delete ssl_client;
|
||||||
|
delete basic_client;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// LOG_INFO("authenticate %s:%s", login.c_str(), pass.c_str());
|
||||||
|
smtp->authenticate(login, pass, readymail_auth_password);
|
||||||
|
if (!smtp->isAuthenticated()) {
|
||||||
|
LOG_ERROR("Sendmail authenticate error");
|
||||||
|
delete smtp;
|
||||||
|
delete r_client;
|
||||||
|
delete ssl_client;
|
||||||
|
delete basic_client;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
JsonDocument doc;
|
||||||
|
String body = value;
|
||||||
|
if (body.length()) {
|
||||||
|
auto error = deserializeJson(doc, (const char *)value);
|
||||||
|
if (!error && doc.as<JsonObject>().size() >= 0) {
|
||||||
|
subject = doc["subject"] | subject;
|
||||||
|
recp = doc["to"] | recp;
|
||||||
|
sender = doc["from"] | sender;
|
||||||
|
body = doc["body"] | body;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SMTPMessage & msg = smtp->getMessage();
|
||||||
|
msg.headers.add(rfc822_subject, subject);
|
||||||
|
msg.headers.add(rfc822_from, sender);
|
||||||
|
msg.headers.add(rfc822_to, recp);
|
||||||
|
|
||||||
|
// Use addCustom to add custom header e.g. Importance and Priority.
|
||||||
|
// msg.headers.addCustom("Importance", PRIORITY);
|
||||||
|
// msg.headers.addCustom("X-MSMail-Priority", PRIORITY);
|
||||||
|
// msg.headers.addCustom("X-Priority", PRIORITY_NUM);
|
||||||
|
EMSESP::webSchedulerService.computed_value.clear();
|
||||||
|
EMSESP::webSchedulerService.raw_value = body.c_str();
|
||||||
|
for (uint16_t wait = 0; wait < 2000 && !EMSESP::webSchedulerService.raw_value.empty(); wait++) {
|
||||||
|
delay(1);
|
||||||
|
}
|
||||||
|
if (!EMSESP::webSchedulerService.computed_value.empty()) {
|
||||||
|
body = EMSESP::webSchedulerService.computed_value.c_str();
|
||||||
|
EMSESP::webSchedulerService.computed_value.clear();
|
||||||
|
EMSESP::webSchedulerService.computed_value.shrink_to_fit(); // free allocated memory
|
||||||
|
}
|
||||||
|
msg.text.body(body);
|
||||||
|
|
||||||
|
// bodyText.replace("\r\n", "<br>\r\n");
|
||||||
|
// msg.html.body("<html><body><div style=\"color:#cc0066;\">" + bodyText + "</div></body></html>");
|
||||||
|
// msg.html.transferEncoding("base64");
|
||||||
|
|
||||||
|
// With embedFile function, the html message will send as attachment.
|
||||||
|
// if (EMBED_MESSAGE)
|
||||||
|
// msg.html.embedFile(true, "msg.html", embed_message_type_attachment);
|
||||||
|
|
||||||
|
msg.timestamp = time(nullptr);
|
||||||
|
|
||||||
|
success = smtp->send(msg);
|
||||||
|
|
||||||
|
delete smtp;
|
||||||
|
delete r_client;
|
||||||
|
delete ssl_client;
|
||||||
|
delete basic_client;
|
||||||
|
#endif
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
// return string of languages and count
|
// return string of languages and count
|
||||||
std::string System::languages_string() {
|
std::string System::languages_string() {
|
||||||
std::string languages_string = std::to_string(NUM_LANGUAGES) + " languages (";
|
std::string languages_string = std::to_string(NUM_LANGUAGES) + " languages (";
|
||||||
@@ -237,7 +355,8 @@ bool System::command_message(const char * value, const int8_t id, JsonObject out
|
|||||||
LOG_INFO("Message: %s", EMSESP::webSchedulerService.computed_value.c_str()); // send to log
|
LOG_INFO("Message: %s", EMSESP::webSchedulerService.computed_value.c_str()); // send to log
|
||||||
Mqtt::queue_publish(F_(message), EMSESP::webSchedulerService.computed_value); // send to MQTT if enabled
|
Mqtt::queue_publish(F_(message), EMSESP::webSchedulerService.computed_value); // send to MQTT if enabled
|
||||||
output["api_data"] = EMSESP::webSchedulerService.computed_value; // send to API
|
output["api_data"] = EMSESP::webSchedulerService.computed_value; // send to API
|
||||||
|
EMSESP::webSchedulerService.computed_value.clear();
|
||||||
|
EMSESP::webSchedulerService.computed_value.shrink_to_fit();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -461,7 +580,6 @@ void System::system_restart(const char * partitionname) {
|
|||||||
|
|
||||||
Mqtt::disconnect(); // gracefully disconnect MQTT, needed for QOS1
|
Mqtt::disconnect(); // gracefully disconnect MQTT, needed for QOS1
|
||||||
EMSuart::stop(); // stop UART so there is no interference
|
EMSuart::stop(); // stop UART so there is no interference
|
||||||
|
|
||||||
#ifndef EMSESP_STANDALONE
|
#ifndef EMSESP_STANDALONE
|
||||||
delay(1000); // wait 1 second
|
delay(1000); // wait 1 second
|
||||||
ESP.restart(); // ka-boom! - this is the only place where the ESP32 restart is called
|
ESP.restart(); // ka-boom! - this is the only place where the ESP32 restart is called
|
||||||
@@ -563,7 +681,6 @@ void System::store_settings(WebSettings & settings) {
|
|||||||
|
|
||||||
locale_ = settings.locale;
|
locale_ = settings.locale;
|
||||||
developer_mode_ = settings.developer_mode;
|
developer_mode_ = settings.developer_mode;
|
||||||
|
|
||||||
// start services
|
// start services
|
||||||
if (settings.modbus_enabled) {
|
if (settings.modbus_enabled) {
|
||||||
if (EMSESP::modbus_ == nullptr) {
|
if (EMSESP::modbus_ == nullptr) {
|
||||||
@@ -605,20 +722,11 @@ void System::start() {
|
|||||||
appfree_ = esp_ota_get_running_partition()->size / 1024 - appused_;
|
appfree_ = esp_ota_get_running_partition()->size / 1024 - appused_;
|
||||||
refreshHeapMem(); // refresh free heap and max alloc heap
|
refreshHeapMem(); // refresh free heap and max alloc heap
|
||||||
#if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2
|
#if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2
|
||||||
#if ESP_IDF_VERSION_MAJOR < 5
|
|
||||||
temp_sensor_config_t temp_sensor = TSENS_CONFIG_DEFAULT();
|
|
||||||
temp_sensor_get_config(&temp_sensor);
|
|
||||||
temp_sensor.dac_offset = TSENS_DAC_DEFAULT; // DEFAULT: range:-10℃ ~ 80℃, error < 1℃.
|
|
||||||
temp_sensor_set_config(temp_sensor);
|
|
||||||
temp_sensor_start();
|
|
||||||
temp_sensor_read_celsius(&temperature_);
|
|
||||||
#else
|
|
||||||
temperature_sensor_config_t temp_sensor_config = TEMPERATURE_SENSOR_CONFIG_DEFAULT(-10, 80);
|
temperature_sensor_config_t temp_sensor_config = TEMPERATURE_SENSOR_CONFIG_DEFAULT(-10, 80);
|
||||||
temperature_sensor_install(&temp_sensor_config, &temperature_handle_);
|
temperature_sensor_install(&temp_sensor_config, &temperature_handle_);
|
||||||
temperature_sensor_enable(temperature_handle_);
|
temperature_sensor_enable(temperature_handle_);
|
||||||
temperature_sensor_get_celsius(temperature_handle_, &temperature_);
|
temperature_sensor_get_celsius(temperature_handle_, &temperature_);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
EMSESP::esp32React.getNetworkSettingsService()->read([&](NetworkSettings & networkSettings) {
|
EMSESP::esp32React.getNetworkSettingsService()->read([&](NetworkSettings & networkSettings) {
|
||||||
@@ -839,16 +947,9 @@ void System::send_info_mqtt() {
|
|||||||
doc["IPv4 gateway"] = uuid::printable_to_string(WiFi.gatewayIP());
|
doc["IPv4 gateway"] = uuid::printable_to_string(WiFi.gatewayIP());
|
||||||
doc["IPv4 nameserver"] = uuid::printable_to_string(WiFi.dnsIP());
|
doc["IPv4 nameserver"] = uuid::printable_to_string(WiFi.dnsIP());
|
||||||
|
|
||||||
#if ESP_IDF_VERSION_MAJOR < 5
|
|
||||||
if (WiFi.localIPv6().toString() != "0000:0000:0000:0000:0000:0000:0000:0000" && WiFi.localIPv6().toString() != "::") {
|
|
||||||
doc["IPv6 address"] = uuid::printable_to_string(WiFi.localIPv6());
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (WiFi.linkLocalIPv6().toString() != "0000:0000:0000:0000:0000:0000:0000:0000" && WiFi.linkLocalIPv6().toString() != "::") {
|
if (WiFi.linkLocalIPv6().toString() != "0000:0000:0000:0000:0000:0000:0000:0000" && WiFi.linkLocalIPv6().toString() != "::") {
|
||||||
doc["IPv6 address"] = uuid::printable_to_string(WiFi.linkLocalIPv6());
|
doc["IPv6 address"] = uuid::printable_to_string(WiFi.linkLocalIPv6());
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
Mqtt::queue_publish_retain(F_(info), doc.as<JsonObject>()); // topic called "info" and it's Retained
|
Mqtt::queue_publish_retain(F_(info), doc.as<JsonObject>()); // topic called "info" and it's Retained
|
||||||
@@ -957,12 +1058,11 @@ void System::network_init() {
|
|||||||
delay(500);
|
delay(500);
|
||||||
digitalWrite(eth_power_, HIGH);
|
digitalWrite(eth_power_, HIGH);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ESP_IDF_VERSION_MAJOR < 5
|
|
||||||
eth_present_ = ETH.begin(phy_addr, power, mdc, mdio, type, clock_mode);
|
|
||||||
#else
|
|
||||||
eth_present_ = ETH.begin(type, phy_addr, mdc, mdio, power, clock_mode);
|
eth_present_ = ETH.begin(type, phy_addr, mdc, mdio, power, clock_mode);
|
||||||
#endif
|
if (eth_present_) {
|
||||||
|
// Push hostname to the ETH netif immediately after it's created
|
||||||
|
ETH.setHostname(hostname_.c_str());
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -974,13 +1074,9 @@ void System::system_check() {
|
|||||||
|
|
||||||
#ifndef EMSESP_STANDALONE
|
#ifndef EMSESP_STANDALONE
|
||||||
#if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2
|
#if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2
|
||||||
#if ESP_IDF_VERSION_MAJOR < 5
|
|
||||||
temp_sensor_read_celsius(&temperature_);
|
|
||||||
#else
|
|
||||||
temperature_sensor_get_celsius(temperature_handle_, &temperature_);
|
temperature_sensor_get_celsius(temperature_handle_, &temperature_);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef EMSESP_PINGTEST
|
#ifdef EMSESP_PINGTEST
|
||||||
static uint64_t ping_count = 0;
|
static uint64_t ping_count = 0;
|
||||||
@@ -1032,6 +1128,7 @@ void System::commands_init() {
|
|||||||
Command::add(EMSdevice::DeviceType::SYSTEM, F_(read), System::command_read, FL_(read_cmd), CommandFlag::ADMIN_ONLY);
|
Command::add(EMSdevice::DeviceType::SYSTEM, F_(read), System::command_read, FL_(read_cmd), CommandFlag::ADMIN_ONLY);
|
||||||
Command::add(EMSdevice::DeviceType::SYSTEM, F_(send), System::command_send, FL_(send_cmd), CommandFlag::ADMIN_ONLY);
|
Command::add(EMSdevice::DeviceType::SYSTEM, F_(send), System::command_send, FL_(send_cmd), CommandFlag::ADMIN_ONLY);
|
||||||
Command::add(EMSdevice::DeviceType::SYSTEM, F_(fetch), System::command_fetch, FL_(fetch_cmd), CommandFlag::ADMIN_ONLY);
|
Command::add(EMSdevice::DeviceType::SYSTEM, F_(fetch), System::command_fetch, FL_(fetch_cmd), CommandFlag::ADMIN_ONLY);
|
||||||
|
Command::add(EMSdevice::DeviceType::SYSTEM, F_(sendmail), System::command_sendmail, FL_(sendmail_cmd), CommandFlag::ADMIN_ONLY);
|
||||||
Command::add(EMSdevice::DeviceType::SYSTEM, F_(restart), System::command_restart, FL_(restart_cmd), CommandFlag::ADMIN_ONLY);
|
Command::add(EMSdevice::DeviceType::SYSTEM, F_(restart), System::command_restart, FL_(restart_cmd), CommandFlag::ADMIN_ONLY);
|
||||||
Command::add(EMSdevice::DeviceType::SYSTEM, F_(format), System::command_format, FL_(format_cmd), CommandFlag::ADMIN_ONLY);
|
Command::add(EMSdevice::DeviceType::SYSTEM, F_(format), System::command_format, FL_(format_cmd), CommandFlag::ADMIN_ONLY);
|
||||||
Command::add(EMSdevice::DeviceType::SYSTEM, F_(txpause), System::command_txpause, FL_(txpause_cmd), CommandFlag::ADMIN_ONLY);
|
Command::add(EMSdevice::DeviceType::SYSTEM, F_(txpause), System::command_txpause, FL_(txpause_cmd), CommandFlag::ADMIN_ONLY);
|
||||||
@@ -1280,16 +1377,9 @@ void System::show_system(uuid::console::Shell & shell) {
|
|||||||
shell.printfln(" IPv4 address: %s/%s", uuid::printable_to_string(WiFi.localIP()).c_str(), uuid::printable_to_string(WiFi.subnetMask()).c_str());
|
shell.printfln(" IPv4 address: %s/%s", uuid::printable_to_string(WiFi.localIP()).c_str(), uuid::printable_to_string(WiFi.subnetMask()).c_str());
|
||||||
shell.printfln(" IPv4 gateway: %s", uuid::printable_to_string(WiFi.gatewayIP()).c_str());
|
shell.printfln(" IPv4 gateway: %s", uuid::printable_to_string(WiFi.gatewayIP()).c_str());
|
||||||
shell.printfln(" IPv4 nameserver: %s", uuid::printable_to_string(WiFi.dnsIP()).c_str());
|
shell.printfln(" IPv4 nameserver: %s", uuid::printable_to_string(WiFi.dnsIP()).c_str());
|
||||||
#if ESP_IDF_VERSION_MAJOR < 5
|
|
||||||
if (WiFi.localIPv6().toString() != "0000:0000:0000:0000:0000:0000:0000:0000" && WiFi.localIPv6().toString() != "::") {
|
|
||||||
shell.printfln(" IPv6 address: %s", uuid::printable_to_string(WiFi.localIPv6()).c_str());
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (WiFi.linkLocalIPv6().toString() != "0000:0000:0000:0000:0000:0000:0000:0000" && WiFi.linkLocalIPv6().toString() != "::") {
|
if (WiFi.linkLocalIPv6().toString() != "0000:0000:0000:0000:0000:0000:0000:0000" && WiFi.linkLocalIPv6().toString() != "::") {
|
||||||
shell.printfln(" IPv6 address: %s", uuid::printable_to_string(WiFi.linkLocalIPv6()).c_str());
|
shell.printfln(" IPv6 address: %s", uuid::printable_to_string(WiFi.linkLocalIPv6()).c_str());
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WL_CONNECT_FAILED:
|
case WL_CONNECT_FAILED:
|
||||||
@@ -1320,15 +1410,9 @@ void System::show_system(uuid::console::Shell & shell) {
|
|||||||
shell.printfln(" IPv4 address: %s/%s", uuid::printable_to_string(ETH.localIP()).c_str(), uuid::printable_to_string(ETH.subnetMask()).c_str());
|
shell.printfln(" IPv4 address: %s/%s", uuid::printable_to_string(ETH.localIP()).c_str(), uuid::printable_to_string(ETH.subnetMask()).c_str());
|
||||||
shell.printfln(" IPv4 gateway: %s", uuid::printable_to_string(ETH.gatewayIP()).c_str());
|
shell.printfln(" IPv4 gateway: %s", uuid::printable_to_string(ETH.gatewayIP()).c_str());
|
||||||
shell.printfln(" IPv4 nameserver: %s", uuid::printable_to_string(ETH.dnsIP()).c_str());
|
shell.printfln(" IPv4 nameserver: %s", uuid::printable_to_string(ETH.dnsIP()).c_str());
|
||||||
#if ESP_IDF_VERSION_MAJOR < 5
|
|
||||||
if (ETH.localIPv6().toString() != "0000:0000:0000:0000:0000:0000:0000:0000" && ETH.localIPv6().toString() != "::") {
|
|
||||||
shell.printfln(" IPv6 address: %s", uuid::printable_to_string(ETH.localIPv6()).c_str());
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (ETH.linkLocalIPv6().toString() != "0000:0000:0000:0000:0000:0000:0000:0000" && ETH.linkLocalIPv6().toString() != "::") {
|
if (ETH.linkLocalIPv6().toString() != "0000:0000:0000:0000:0000:0000:0000:0000" && ETH.linkLocalIPv6().toString() != "::") {
|
||||||
shell.printfln(" IPv6 address: %s", uuid::printable_to_string(ETH.linkLocalIPv6()).c_str());
|
shell.printfln(" IPv6 address: %s", uuid::printable_to_string(ETH.linkLocalIPv6()).c_str());
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
shell.println();
|
shell.println();
|
||||||
|
|
||||||
@@ -1350,10 +1434,10 @@ void System::show_system(uuid::console::Shell & shell) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
shell.println();
|
shell.println();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// see if there is a restore of an older settings file that needs to be applied
|
// see if there is a restore of an older settings file that needs to be applied
|
||||||
// note there can be only one file at a time
|
// note there can be only one file at a time
|
||||||
bool System::check_restore() {
|
bool System::check_restore() {
|
||||||
@@ -1653,8 +1737,8 @@ bool System::check_upgrade() {
|
|||||||
return false; // no reboot required
|
return false; // no reboot required
|
||||||
}
|
}
|
||||||
|
|
||||||
// map each config filename to its human-readable section key
|
|
||||||
#ifndef EMSESP_STANDALONE
|
#ifndef EMSESP_STANDALONE
|
||||||
|
// map each config filename to its human-readable section key
|
||||||
static const std::pair<const char *, const char *> SECTION_MAP[] = {
|
static const std::pair<const char *, const char *> SECTION_MAP[] = {
|
||||||
{NETWORK_SETTINGS_FILE, "Network"},
|
{NETWORK_SETTINGS_FILE, "Network"},
|
||||||
{AP_SETTINGS_FILE, "AP"},
|
{AP_SETTINGS_FILE, "AP"},
|
||||||
@@ -1769,27 +1853,16 @@ void System::exportSystemBackup(JsonObject output) {
|
|||||||
|
|
||||||
const char * nvs_part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, "nvs1") ? "nvs1" : "nvs"; // nvs1 is on 16MBs
|
const char * nvs_part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, "nvs1") ? "nvs1" : "nvs"; // nvs1 is on 16MBs
|
||||||
nvs_iterator_t it = nullptr;
|
nvs_iterator_t it = nullptr;
|
||||||
#if ESP_IDF_VERSION_MAJOR < 5
|
|
||||||
it = nvs_entry_find(nvs_part, "ems-esp", NVS_TYPE_ANY);
|
|
||||||
if (it == nullptr) {
|
|
||||||
#else
|
|
||||||
esp_err_t err = nvs_entry_find(nvs_part, "ems-esp", NVS_TYPE_ANY, &it);
|
esp_err_t err = nvs_entry_find(nvs_part, "ems-esp", NVS_TYPE_ANY, &it);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
#endif
|
|
||||||
LOG_ERROR("Failed to find NVS entry for %s", nvs_part);
|
LOG_ERROR("Failed to find NVS entry for %s", nvs_part);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonArray entries = node["nvs"].to<JsonArray>();
|
JsonArray entries = node["nvs"].to<JsonArray>();
|
||||||
#if ESP_IDF_VERSION_MAJOR < 5
|
|
||||||
while (it != nullptr) {
|
|
||||||
nvs_entry_info_t info;
|
|
||||||
nvs_entry_info(it, &info);
|
|
||||||
#else
|
|
||||||
while (err == ESP_OK) {
|
while (err == ESP_OK) {
|
||||||
nvs_entry_info_t info;
|
nvs_entry_info_t info;
|
||||||
nvs_entry_info(it, &info);
|
nvs_entry_info(it, &info);
|
||||||
#endif
|
|
||||||
JsonObject entry = entries.add<JsonObject>();
|
JsonObject entry = entries.add<JsonObject>();
|
||||||
entry["type"] = info.type;
|
entry["type"] = info.type;
|
||||||
entry["key"] = info.key;
|
entry["key"] = info.key;
|
||||||
@@ -1824,14 +1897,8 @@ void System::exportSystemBackup(JsonObject output) {
|
|||||||
entry["value"] = EMSESP::nvs_.getString(info.key);
|
entry["value"] = EMSESP::nvs_.getString(info.key);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ESP_IDF_VERSION_MAJOR < 5
|
|
||||||
it = nvs_entry_next(it);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
err = nvs_entry_next(&it);
|
err = nvs_entry_next(&it);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
if (it != nullptr) {
|
if (it != nullptr) {
|
||||||
nvs_release_iterator(it);
|
nvs_release_iterator(it);
|
||||||
@@ -3329,6 +3396,10 @@ void System::set_valid_system_gpios() {
|
|||||||
} else {
|
} else {
|
||||||
valid_system_gpios_ = string_range_to_vector("0-39", "6-11, 20, 24, 28-31");
|
valid_system_gpios_ = string_range_to_vector("0-39", "6-11, 20, 24, 28-31");
|
||||||
}
|
}
|
||||||
|
#elif CONFIG_IDF_TARGET_ESP32C6
|
||||||
|
// https://docs.espressif.com/projects/esp-idf/en/v5.5.3/esp32c6/api-reference/peripherals/gpio.html
|
||||||
|
// 24-30 used for flash, 12-13 USB, 16-17 uart0
|
||||||
|
valid_system_gpios_ = string_range_to_vector("0-30", "12-13, 16-17, 24-30");
|
||||||
#elif defined(EMSESP_STANDALONE)
|
#elif defined(EMSESP_STANDALONE)
|
||||||
valid_system_gpios_ = string_range_to_vector("0-39");
|
valid_system_gpios_ = string_range_to_vector("0-39");
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -37,11 +37,7 @@
|
|||||||
#include <uuid/log.h>
|
#include <uuid/log.h>
|
||||||
#include <PButton.h>
|
#include <PButton.h>
|
||||||
|
|
||||||
#if ESP_ARDUINO_VERSION_MAJOR < 3
|
|
||||||
#define EMSESP_RGB_WRITE neopixelWrite
|
|
||||||
#else
|
|
||||||
#define EMSESP_RGB_WRITE rgbLedWrite
|
#define EMSESP_RGB_WRITE rgbLedWrite
|
||||||
#endif
|
|
||||||
|
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
// there is no official API available on the original ESP32
|
// there is no official API available on the original ESP32
|
||||||
@@ -49,12 +45,8 @@ extern "C" {
|
|||||||
uint8_t temprature_sens_read();
|
uint8_t temprature_sens_read();
|
||||||
}
|
}
|
||||||
#elif CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2
|
#elif CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2
|
||||||
#if ESP_IDF_VERSION_MAJOR < 5
|
|
||||||
#include "driver/temp_sensor.h"
|
|
||||||
#else
|
|
||||||
#include "driver/temperature_sensor.h"
|
#include "driver/temperature_sensor.h"
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|
||||||
using uuid::console::Shell;
|
using uuid::console::Shell;
|
||||||
|
|
||||||
@@ -103,6 +95,7 @@ class System {
|
|||||||
static bool command_info(const char * value, const int8_t id, JsonObject output);
|
static bool command_info(const char * value, const int8_t id, JsonObject output);
|
||||||
static bool command_response(const char * value, const int8_t id, JsonObject output);
|
static bool command_response(const char * value, const int8_t id, JsonObject output);
|
||||||
static bool command_service(const char * cmd, const char * value);
|
static bool command_service(const char * cmd, const char * value);
|
||||||
|
static bool command_sendmail(const char * value, const int8_t id);
|
||||||
static bool command_txpause(const char * value, const int8_t id);
|
static bool command_txpause(const char * value, const int8_t id);
|
||||||
|
|
||||||
static bool get_value_info(JsonObject root, const char * cmd);
|
static bool get_value_info(JsonObject root, const char * cmd);
|
||||||
@@ -502,9 +495,7 @@ class System {
|
|||||||
uint32_t appfree_;
|
uint32_t appfree_;
|
||||||
|
|
||||||
#if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2
|
#if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2
|
||||||
#if ESP_IDF_VERSION_MAJOR >= 5
|
|
||||||
temperature_sensor_handle_t temperature_handle_ = NULL;
|
temperature_sensor_handle_t temperature_handle_ = NULL;
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
float temperature_ = 0;
|
float temperature_ = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -163,6 +163,7 @@ class EMSbus {
|
|||||||
static constexpr uint8_t EMS_MASK_HT3 = 0x80; // EMS bus type Junkers/HT3
|
static constexpr uint8_t EMS_MASK_HT3 = 0x80; // EMS bus type Junkers/HT3
|
||||||
static constexpr uint8_t EMS_MASK_BUDERUS = 0xFF; // EMS bus type Buderus
|
static constexpr uint8_t EMS_MASK_BUDERUS = 0xFF; // EMS bus type Buderus
|
||||||
static constexpr uint8_t EMS_TX_ERROR_LIMIT = 10; // % limit of failed Tx read/write attempts before showing a warning
|
static constexpr uint8_t EMS_TX_ERROR_LIMIT = 10; // % limit of failed Tx read/write attempts before showing a warning
|
||||||
|
static constexpr uint8_t EMS_POLL_MATCH_LIMIT = 3; // consecutive poll matches needed before declaring bus connected
|
||||||
|
|
||||||
static bool is_ht3() {
|
static bool is_ht3() {
|
||||||
return (ems_mask_ == EMS_MASK_HT3);
|
return (ems_mask_ == EMS_MASK_HT3);
|
||||||
@@ -210,7 +211,6 @@ class EMSbus {
|
|||||||
if (!last_bus_activity_) {
|
if (!last_bus_activity_) {
|
||||||
bus_uptime_start_ = timestamp;
|
bus_uptime_start_ = timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
last_bus_activity_ = timestamp;
|
last_bus_activity_ = timestamp;
|
||||||
bus_connected_ = true;
|
bus_connected_ = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
#define EMSESP_APP_VERSION "3.8.2-dev.18"
|
#define EMSESP_APP_VERSION "3.9.0-dev.0"
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ uint32_t inverse_mask = 0;
|
|||||||
// receive task, wait for break and call incoming_telegram
|
// receive task, wait for break and call incoming_telegram
|
||||||
void EMSuart::uart_event_task(void * pvParameters) {
|
void EMSuart::uart_event_task(void * pvParameters) {
|
||||||
uart_event_t event;
|
uart_event_t event;
|
||||||
uint8_t telegram[UART_FIFO_LEN + 1]; // same size as in driver_install
|
uint8_t telegram[UART_HW_FIFO_LEN(EMSUART_NUM) + 1]; // same size as in driver_install
|
||||||
uint8_t length = 0;
|
uint8_t length = 0;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
@@ -66,18 +66,23 @@ void EMSuart::uart_event_task(void * pvParameters) {
|
|||||||
// initialize UART driver
|
// initialize UART driver
|
||||||
void EMSuart::start(const uint8_t tx_mode, const uint8_t rx_gpio, const uint8_t tx_gpio) {
|
void EMSuart::start(const uint8_t tx_mode, const uint8_t rx_gpio, const uint8_t tx_gpio) {
|
||||||
if (tx_mode_ == EMS_TXMODE_INIT) {
|
if (tx_mode_ == EMS_TXMODE_INIT) {
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32C6
|
||||||
|
uart_config_t uart_config = {.baud_rate = EMSUART_BAUD,
|
||||||
|
.data_bits = UART_DATA_8_BITS,
|
||||||
|
.parity = UART_PARITY_DISABLE,
|
||||||
|
.stop_bits = UART_STOP_BITS_1,
|
||||||
|
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||||
|
.rx_flow_ctrl_thresh = 0};
|
||||||
|
#else
|
||||||
uart_config_t uart_config = {.baud_rate = EMSUART_BAUD,
|
uart_config_t uart_config = {.baud_rate = EMSUART_BAUD,
|
||||||
.data_bits = UART_DATA_8_BITS,
|
.data_bits = UART_DATA_8_BITS,
|
||||||
.parity = UART_PARITY_DISABLE,
|
.parity = UART_PARITY_DISABLE,
|
||||||
.stop_bits = UART_STOP_BITS_1,
|
.stop_bits = UART_STOP_BITS_1,
|
||||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||||
.rx_flow_ctrl_thresh = 0,
|
.rx_flow_ctrl_thresh = 0,
|
||||||
.source_clk = UART_SCLK_APB
|
.source_clk = UART_SCLK_APB,
|
||||||
#if ESP_ARDUINO_VERSION_MAJOR >= 3
|
.flags = {0}};
|
||||||
,
|
|
||||||
.flags = {0}
|
|
||||||
#endif
|
#endif
|
||||||
};
|
|
||||||
#if defined(EMSUART_RX_INVERT)
|
#if defined(EMSUART_RX_INVERT)
|
||||||
inverse_mask |= UART_SIGNAL_RXD_INV;
|
inverse_mask |= UART_SIGNAL_RXD_INV;
|
||||||
#endif
|
#endif
|
||||||
@@ -87,7 +92,12 @@ void EMSuart::start(const uint8_t tx_mode, const uint8_t rx_gpio, const uint8_t
|
|||||||
uart_param_config(EMSUART_NUM, &uart_config);
|
uart_param_config(EMSUART_NUM, &uart_config);
|
||||||
uart_set_pin(EMSUART_NUM, tx_gpio, rx_gpio, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
|
uart_set_pin(EMSUART_NUM, tx_gpio, rx_gpio, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
|
||||||
uart_set_line_inverse(EMSUART_NUM, inverse_mask);
|
uart_set_line_inverse(EMSUART_NUM, inverse_mask);
|
||||||
uart_driver_install(EMSUART_NUM, UART_FIFO_LEN + 1, 0, UART_FIFO_LEN + 3, &uart_queue, 0); // buffer must be > fifo, queue can hold data+break+overflow message
|
uart_driver_install(EMSUART_NUM,
|
||||||
|
UART_HW_FIFO_LEN(EMSUART_NUM) + 1,
|
||||||
|
0,
|
||||||
|
UART_HW_FIFO_LEN(EMSUART_NUM) + 3,
|
||||||
|
&uart_queue,
|
||||||
|
0); // buffer must be > fifo, queue can hold data+break+overflow message
|
||||||
uart_set_rx_full_threshold(EMSUART_NUM, 1);
|
uart_set_rx_full_threshold(EMSUART_NUM, 1);
|
||||||
uart_set_rx_timeout(EMSUART_NUM, 0); // disable
|
uart_set_rx_timeout(EMSUART_NUM, 0); // disable
|
||||||
|
|
||||||
|
|||||||
@@ -54,10 +54,10 @@ void WebCustomization::read(WebCustomization & customizations, JsonObject root)
|
|||||||
JsonArray sensorsJson = root["ts"].to<JsonArray>();
|
JsonArray sensorsJson = root["ts"].to<JsonArray>();
|
||||||
for (const SensorCustomization & sensor : customizations.sensorCustomizations) {
|
for (const SensorCustomization & sensor : customizations.sensorCustomizations) {
|
||||||
JsonObject sensorJson = sensorsJson.add<JsonObject>();
|
JsonObject sensorJson = sensorsJson.add<JsonObject>();
|
||||||
sensorJson["id"] = (const char *)sensor.id; // ID of chip
|
sensorJson["id"] = (const char *)sensor.id; // ID of dallas temperature sensor chip
|
||||||
sensorJson["name"] = (const char *)sensor.name; // n
|
sensorJson["name"] = (const char *)sensor.name; // n
|
||||||
sensorJson["offset"] = sensor.offset; // o
|
sensorJson["offset"] = sensor.offset; // o
|
||||||
sensorJson["is_system"] = sensor.is_system; // s for core_voltage, supply_voltage
|
sensorJson["is_system"] = sensor.is_system; // s for gateway_temperature
|
||||||
}
|
}
|
||||||
|
|
||||||
// Analog Sensor customization
|
// Analog Sensor customization
|
||||||
|
|||||||
@@ -352,7 +352,6 @@ bool WebSchedulerService::command(const char * name, const std::string & command
|
|||||||
// parse json
|
// parse json
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
if (deserializeJson(doc, cmd) == DeserializationError::Ok) {
|
if (deserializeJson(doc, cmd) == DeserializationError::Ok) {
|
||||||
HTTPClient * http = new HTTPClient;
|
|
||||||
std::string url = doc["url"] | "";
|
std::string url = doc["url"] | "";
|
||||||
// for a GET with parameters replace commands with values
|
// for a GET with parameters replace commands with values
|
||||||
// don't search the complete url, it may contain a devicename in path
|
// don't search the complete url, it may contain a devicename in path
|
||||||
@@ -363,40 +362,139 @@ bool WebSchedulerService::command(const char * name, const std::string & command
|
|||||||
commands(s, false);
|
commands(s, false);
|
||||||
url.replace(q + 1, l, s);
|
url.replace(q + 1, l, s);
|
||||||
}
|
}
|
||||||
if (http->begin(url.c_str())) {
|
std::string value = doc["value"] | data; // extract value if its in the command, or take the data
|
||||||
// add any given headers
|
|
||||||
for (JsonPair p : doc["header"].as<JsonObject>()) {
|
|
||||||
http->addHeader(p.key().c_str(), p.value().as<String>().c_str());
|
|
||||||
}
|
|
||||||
std::string value = doc["value"] | data.c_str(); // extract value if its in the command, or take the data
|
|
||||||
std::string method = doc["method"] | "GET"; // default GET
|
std::string method = doc["method"] | "GET"; // default GET
|
||||||
|
|
||||||
commands(value, false);
|
commands(value, false);
|
||||||
// if there is data, force a POST
|
if (value.length()) {
|
||||||
|
method = "POST";
|
||||||
|
}
|
||||||
|
std::string result;
|
||||||
int httpResult = 0;
|
int httpResult = 0;
|
||||||
if (value.length() || method == "post") { // we have all lowercase
|
#ifndef NO_TLS_SUPPORT
|
||||||
if (value.find_first_of('{') != std::string::npos) {
|
if (Helpers::toLower(url.c_str()).starts_with("https://")) {
|
||||||
|
WiFiClient * basic_client = new WiFiClient;
|
||||||
|
ESP_SSLClient * ssl_client = new ESP_SSLClient;
|
||||||
|
ssl_client->setInsecure(); // with root CA we should set here: ssl_client->setCACert(rootCACert);
|
||||||
|
ssl_client->setBufferSizes(1024, 1024);
|
||||||
|
ssl_client->setSessionTimeout(120); // Set the timeout in seconds (>=120 seconds)
|
||||||
|
url.replace(0, 8, "");
|
||||||
|
std::string host = url;
|
||||||
|
auto index = url.find_first_of('/');
|
||||||
|
if (index != std::string::npos) {
|
||||||
|
host = url.substr(0, index);
|
||||||
|
url.replace(0, index, "");
|
||||||
|
}
|
||||||
|
// EMSESP::logger().debug("Host: %s, URL: %s", host.c_str(), url.c_str());
|
||||||
|
ssl_client->setClient(basic_client);
|
||||||
|
if (ssl_client->connect(host.c_str(), 443)) {
|
||||||
|
if (value.length() || Helpers::toLower(method) == "post") {
|
||||||
|
// EMSESP::logger().debug("POST %s HTTP/1.1", url.c_str());
|
||||||
|
ssl_client->print("POST ");
|
||||||
|
ssl_client->print(url.c_str());
|
||||||
|
ssl_client->println(" HTTP/1.1");
|
||||||
|
ssl_client->print("Host: ");
|
||||||
|
ssl_client->println(host.c_str());
|
||||||
|
bool content_set = false;
|
||||||
|
for (JsonPair p : doc["header"].as<JsonObject>()) {
|
||||||
|
content_set |= (emsesp::Helpers::toLower(p.key().c_str()) == "content-type");
|
||||||
|
ssl_client->print(p.key().c_str());
|
||||||
|
ssl_client->print(": ");
|
||||||
|
ssl_client->println(p.value().as<std::string>().c_str());
|
||||||
|
}
|
||||||
|
if (!content_set) {
|
||||||
|
ssl_client->print("Content-Type: ");
|
||||||
|
if (value.starts_with('{')) {
|
||||||
|
ssl_client->println(asyncsrv::T_application_json);
|
||||||
|
} else {
|
||||||
|
ssl_client->println(asyncsrv::T_text_plain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ssl_client->print("Content-Length: ");
|
||||||
|
ssl_client->println(value.length());
|
||||||
|
ssl_client->println("Connection: close");
|
||||||
|
ssl_client->print("\r\n");
|
||||||
|
ssl_client->print(value.c_str());
|
||||||
|
} else {
|
||||||
|
// EMSESP::logger().debug("GET %s HTTP/1.1", url.c_str());
|
||||||
|
ssl_client->print("GET ");
|
||||||
|
ssl_client->print(url.c_str());
|
||||||
|
ssl_client->println(" HTTP/1.1");
|
||||||
|
ssl_client->print("Host: ");
|
||||||
|
ssl_client->println(host.c_str());
|
||||||
|
for (JsonPair p : doc["header"].as<JsonObject>()) {
|
||||||
|
ssl_client->print(p.key().c_str());
|
||||||
|
ssl_client->print(": ");
|
||||||
|
ssl_client->println(p.value().as<std::string>().c_str());
|
||||||
|
}
|
||||||
|
ssl_client->println("Connection: close");
|
||||||
|
}
|
||||||
|
auto ms = millis();
|
||||||
|
while (ssl_client->connected() && !ssl_client->available() && millis() - ms < 3000) {
|
||||||
|
delay(0);
|
||||||
|
}
|
||||||
|
while (ssl_client->available()) {
|
||||||
|
result += (char)ssl_client->read();
|
||||||
|
}
|
||||||
|
ssl_client->stop();
|
||||||
|
// EMSESP::logger().debug("HTTPS response: %s", result.c_str());
|
||||||
|
index = result.find_first_of(' ');
|
||||||
|
if (index != std::string::npos) {
|
||||||
|
httpResult = stoi(result.substr(index + 1, 3));
|
||||||
|
// EMSESP::logger().debug("HTTPS code: %i", httpResult);
|
||||||
|
}
|
||||||
|
index = result.find("\r\n\r\n");
|
||||||
|
if (index != std::string::npos) {
|
||||||
|
result.replace(0, index + 4, "");
|
||||||
|
// EMSESP::logger().debug("HTTPS response: %s", result.c_str());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
EMSESP::logger().warning("HTTPS connection failed");
|
||||||
|
}
|
||||||
|
delete ssl_client;
|
||||||
|
delete basic_client;
|
||||||
|
// check HTTP return code
|
||||||
|
if (httpResult != 200) {
|
||||||
|
EMSESP::logger().warning("Schedule '%s': URL command failed with http code %d", name, httpResult);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
if (Helpers::toLower(url.c_str()).starts_with("http://")) {
|
||||||
|
HTTPClient * http = new HTTPClient;
|
||||||
|
if (http->begin(url.c_str())) {
|
||||||
|
bool content_set = false;
|
||||||
|
for (JsonPair p : doc["header"].as<JsonObject>()) {
|
||||||
|
http->addHeader(p.key().c_str(), p.value().as<std::string>().c_str());
|
||||||
|
content_set |= p.key() == "content-type";
|
||||||
|
}
|
||||||
|
// if there is data, force a POST
|
||||||
|
if (Helpers::toLower(method) == "post") { // we have all lowercase
|
||||||
|
if (!content_set) {
|
||||||
|
// http->addHeader("Content-Type", value.find_first_of('{') != std::string::npos ? "application/json" : "text/plain");
|
||||||
|
if (value.starts_with('{')) {
|
||||||
http->addHeader(asyncsrv::T_Content_Type, asyncsrv::T_application_json, false); // auto-set to JSON
|
http->addHeader(asyncsrv::T_Content_Type, asyncsrv::T_application_json, false); // auto-set to JSON
|
||||||
|
} else {
|
||||||
|
http->addHeader(asyncsrv::T_Content_Type, asyncsrv::T_text_plain, false); // auto-set to JSON
|
||||||
|
}
|
||||||
}
|
}
|
||||||
httpResult = http->POST(value.c_str());
|
httpResult = http->POST(value.c_str());
|
||||||
} else {
|
} else {
|
||||||
httpResult = http->GET(); // normal GET
|
httpResult = http->GET(); // normal GET
|
||||||
|
if (httpResult > 0) {
|
||||||
|
result = http->getString().c_str();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
http->end();
|
http->end();
|
||||||
delete http;
|
delete http;
|
||||||
|
|
||||||
// check HTTP return code
|
// check HTTP return code
|
||||||
if (httpResult != 200) {
|
if (httpResult != 200) {
|
||||||
char error[100];
|
EMSESP::logger().warning("Schedule '%s': URL command failed with http code %d", name, httpResult);
|
||||||
snprintf(error, sizeof(error), "Schedule %s: URL command failed with http code %d", name, httpResult);
|
|
||||||
EMSESP::logger().warning(error);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#if defined(EMSESP_DEBUG)
|
#if defined(EMSESP_DEBUG)
|
||||||
char msg[100];
|
EMSESP::logger().debug("Schedule %s: URL '%s' command successful with http code %d", name, url.c_str(), httpResult);
|
||||||
snprintf(msg, sizeof(msg), "Schedule %s: URL command successful with http code %d", name, httpResult);
|
|
||||||
EMSESP::logger().debug(msg);
|
|
||||||
#endif
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,6 +83,20 @@ void WebSettings::read(WebSettings & settings, JsonObject root) {
|
|||||||
root["modbus_max_clients"] = settings.modbus_max_clients;
|
root["modbus_max_clients"] = settings.modbus_max_clients;
|
||||||
root["modbus_timeout"] = settings.modbus_timeout;
|
root["modbus_timeout"] = settings.modbus_timeout;
|
||||||
root["developer_mode"] = settings.developer_mode;
|
root["developer_mode"] = settings.developer_mode;
|
||||||
|
#ifndef NO_TLS_SUPPORT
|
||||||
|
root["email_enabled"] = settings.email_enabled;
|
||||||
|
#else
|
||||||
|
root["email_enabled"] = false;
|
||||||
|
#endif
|
||||||
|
root["email_ssl"] = settings.email_ssl;
|
||||||
|
root["email_starttls"] = settings.email_starttls;
|
||||||
|
root["email_server"] = settings.email_server;
|
||||||
|
root["email_port"] = settings.email_port;
|
||||||
|
root["email_login"] = settings.email_login;
|
||||||
|
root["email_pass"] = settings.email_pass;
|
||||||
|
root["email_sender"] = settings.email_sender;
|
||||||
|
root["email_recp"] = settings.email_recp;
|
||||||
|
root["email_subject"] = settings.email_subject;
|
||||||
}
|
}
|
||||||
|
|
||||||
// call on initialization and also when settings are updated/saved via web or console
|
// call on initialization and also when settings are updated/saved via web or console
|
||||||
@@ -243,13 +257,9 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) {
|
|||||||
|
|
||||||
// Modbus settings
|
// Modbus settings
|
||||||
settings.modbus_enabled = root["modbus_enabled"] | EMSESP_DEFAULT_MODBUS_ENABLED;
|
settings.modbus_enabled = root["modbus_enabled"] | EMSESP_DEFAULT_MODBUS_ENABLED;
|
||||||
check_flag(original_settings.modbus_enabled, settings.modbus_enabled, ChangeFlags::RESTART);
|
|
||||||
settings.modbus_port = root["modbus_port"] | EMSESP_DEFAULT_MODBUS_PORT;
|
settings.modbus_port = root["modbus_port"] | EMSESP_DEFAULT_MODBUS_PORT;
|
||||||
check_flag(original_settings.modbus_port, settings.modbus_port, ChangeFlags::RESTART);
|
|
||||||
settings.modbus_max_clients = root["modbus_max_clients"] | EMSESP_DEFAULT_MODBUS_MAX_CLIENTS;
|
settings.modbus_max_clients = root["modbus_max_clients"] | EMSESP_DEFAULT_MODBUS_MAX_CLIENTS;
|
||||||
check_flag(original_settings.modbus_max_clients, settings.modbus_max_clients, ChangeFlags::RESTART);
|
|
||||||
settings.modbus_timeout = root["modbus_timeout"] | EMSESP_DEFAULT_MODBUS_TIMEOUT;
|
settings.modbus_timeout = root["modbus_timeout"] | EMSESP_DEFAULT_MODBUS_TIMEOUT;
|
||||||
check_flag(original_settings.modbus_timeout, settings.modbus_timeout, ChangeFlags::RESTART);
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// these may need mqtt restart to rebuild HA discovery topics
|
// these may need mqtt restart to rebuild HA discovery topics
|
||||||
@@ -300,6 +310,20 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) {
|
|||||||
settings.weblog_level = root["weblog_level"] | EMSESP_DEFAULT_WEBLOG_LEVEL;
|
settings.weblog_level = root["weblog_level"] | EMSESP_DEFAULT_WEBLOG_LEVEL;
|
||||||
settings.weblog_compact = root["weblog_compact"] | EMSESP_DEFAULT_WEBLOG_COMPACT;
|
settings.weblog_compact = root["weblog_compact"] | EMSESP_DEFAULT_WEBLOG_COMPACT;
|
||||||
|
|
||||||
|
settings.email_enabled = root["email_enabled"] | FACTORY_EMAIL_ENABLE;
|
||||||
|
settings.email_ssl = root["email_ssl"] | FACTORY_EMAIL_SSL;
|
||||||
|
settings.email_starttls = root["email_starttls"] | FACTORY_EMAIL_STARTTLS;
|
||||||
|
settings.email_server = root["email_server"] | FACTORY_EMAIL_SERVER;
|
||||||
|
settings.email_port = root["email_port"] | FACTORY_EMAIL_PORT;
|
||||||
|
settings.email_login = root["email_login"] | FACTORY_EMAIL_LOGIN;
|
||||||
|
settings.email_pass = root["email_pass"] | FACTORY_EMAIL_PASSWORD;
|
||||||
|
settings.email_sender = root["email_sender"] | FACTORY_EMAIL_FROM;
|
||||||
|
settings.email_recp = root["email_recp"] | FACTORY_EMAIL_TO;
|
||||||
|
settings.email_subject = root["email_subject"] | FACTORY_EMAIL_SUBJECT;
|
||||||
|
|
||||||
|
if (settings.email_ssl && settings.email_starttls) {
|
||||||
|
settings.email_ssl = false;
|
||||||
|
}
|
||||||
// if no psram limit weblog buffer to 25 messages
|
// if no psram limit weblog buffer to 25 messages
|
||||||
if (EMSESP::system_.PSram() > 0) {
|
if (EMSESP::system_.PSram() > 0) {
|
||||||
settings.weblog_buffer = root["weblog_buffer"] | EMSESP_DEFAULT_WEBLOG_BUFFER;
|
settings.weblog_buffer = root["weblog_buffer"] | EMSESP_DEFAULT_WEBLOG_BUFFER;
|
||||||
@@ -458,23 +482,14 @@ void WebSettings::set_board_profile(WebSettings & settings) {
|
|||||||
#if CONFIG_IDF_TARGET_ESP32
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
// check for no PSRAM, could be a E32 or S32?
|
// check for no PSRAM, could be a E32 or S32?
|
||||||
if (!ESP.getPsramSize()) {
|
if (!ESP.getPsramSize()) {
|
||||||
#if ESP_ARDUINO_VERSION_MAJOR < 3
|
|
||||||
if (ETH.begin(1, 16, 23, 18, ETH_PHY_LAN8720, ETH_CLOCK_GPIO0_IN)) {
|
|
||||||
#else
|
|
||||||
if (ETH.begin(ETH_PHY_LAN8720, 1, 23, 18, 16, ETH_CLOCK_GPIO0_IN)) {
|
if (ETH.begin(ETH_PHY_LAN8720, 1, 23, 18, 16, ETH_CLOCK_GPIO0_IN)) {
|
||||||
#endif
|
|
||||||
settings.board_profile = "E32"; // Ethernet without PSRAM
|
settings.board_profile = "E32"; // Ethernet without PSRAM
|
||||||
} else {
|
} else {
|
||||||
settings.board_profile = "S32"; // ESP32 standard WiFi without PSRAM
|
settings.board_profile = "S32"; // ESP32 standard WiFi without PSRAM
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// check for boards with PSRAM, could be a E32V2 otherwise default back to the S32
|
// check for boards with PSRAM, could be a E32V2 otherwise default back to the S32
|
||||||
#if ESP_ARDUINO_VERSION_MAJOR < 3
|
|
||||||
if (ETH.begin(0, 15, 23, 18, ETH_PHY_LAN8720, ETH_CLOCK_GPIO0_OUT)) {
|
|
||||||
#else
|
|
||||||
if (ETH.begin(ETH_PHY_LAN8720, 0, 23, 18, 15, ETH_CLOCK_GPIO0_OUT)) {
|
if (ETH.begin(ETH_PHY_LAN8720, 0, 23, 18, 15, ETH_CLOCK_GPIO0_OUT)) {
|
||||||
#endif
|
|
||||||
|
|
||||||
if (analogReadMilliVolts(39) > 700) { // core voltage > 2.6V
|
if (analogReadMilliVolts(39) > 700) { // core voltage > 2.6V
|
||||||
settings.board_profile = "E32V2_2"; // Ethernet, PSRAM, internal sensors
|
settings.board_profile = "E32V2_2"; // Ethernet, PSRAM, internal sensors
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -26,6 +26,36 @@
|
|||||||
#define EMSESP_SETTINGS_SERVICE_PATH "/rest/settings"
|
#define EMSESP_SETTINGS_SERVICE_PATH "/rest/settings"
|
||||||
#define EMSESP_BOARD_PROFILE_SERVICE_PATH "/rest/boardProfile"
|
#define EMSESP_BOARD_PROFILE_SERVICE_PATH "/rest/boardProfile"
|
||||||
|
|
||||||
|
#ifndef FACTORY_EMAIL_ENABLE
|
||||||
|
#define FACTORY_EMAIL_ENABLE false
|
||||||
|
#endif
|
||||||
|
#ifndef FACTORY_EMAIL_SSL
|
||||||
|
#define FACTORY_EMAIL_SSL false
|
||||||
|
#endif
|
||||||
|
#ifndef FACTORY_EMAIL_STARTTLS
|
||||||
|
#define FACTORY_EMAIL_STARTTLS true
|
||||||
|
#endif
|
||||||
|
#ifndef FACTORY_EMAIL_PORT
|
||||||
|
#define FACTORY_EMAIL_PORT 587
|
||||||
|
#endif
|
||||||
|
#ifndef FACTORY_EMAIL_SERVER
|
||||||
|
#define FACTORY_EMAIL_SERVER "smtp.example.net"
|
||||||
|
#endif
|
||||||
|
#ifndef FACTORY_EMAIL_LOGIN
|
||||||
|
#define FACTORY_EMAIL_LOGIN ""
|
||||||
|
#endif
|
||||||
|
#ifndef FACTORY_EMAIL_PASSWORD
|
||||||
|
#define FACTORY_EMAIL_PASSWORD ""
|
||||||
|
#endif
|
||||||
|
#ifndef FACTORY_EMAIL_FROM
|
||||||
|
#define FACTORY_EMAIL_FROM "ems-esp@example.net"
|
||||||
|
#endif
|
||||||
|
#ifndef FACTORY_EMAIL_TO
|
||||||
|
#define FACTORY_EMAIL_TO ""
|
||||||
|
#endif
|
||||||
|
#ifndef FACTORY_EMAIL_SUBJECT
|
||||||
|
#define FACTORY_EMAIL_SUBJECT "ems-esp notification"
|
||||||
|
#endif
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
class WebSettings {
|
class WebSettings {
|
||||||
@@ -77,6 +107,16 @@ class WebSettings {
|
|||||||
uint16_t modbus_port;
|
uint16_t modbus_port;
|
||||||
uint8_t modbus_max_clients;
|
uint8_t modbus_max_clients;
|
||||||
uint32_t modbus_timeout;
|
uint32_t modbus_timeout;
|
||||||
|
bool email_enabled;
|
||||||
|
bool email_ssl;
|
||||||
|
bool email_starttls;
|
||||||
|
String email_server;
|
||||||
|
uint16_t email_port;
|
||||||
|
String email_login;
|
||||||
|
String email_pass;
|
||||||
|
String email_sender;
|
||||||
|
String email_recp;
|
||||||
|
String email_subject;
|
||||||
|
|
||||||
uint8_t phy_type;
|
uint8_t phy_type;
|
||||||
int8_t eth_power; // -1 means disabled
|
int8_t eth_power; // -1 means disabled
|
||||||
|
|||||||
Reference in New Issue
Block a user