├── .codespellrc
├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── dependabot.yml
├── stale.yml
└── workflows
│ ├── auto-github-actions.yml
│ ├── check-arduino.yml
│ ├── report-size-deltas.yml
│ └── spell-check.yml
├── .gitignore
├── CONTRIBUTING.md
├── Images
├── Configuration.png
├── Configuration_AIO_MQTT.png
├── Configuration_ESP32.png
├── Configuration_Standard.png
├── Info.png
├── Info_ESP32.png
├── Info_Short.png
├── Main.png
├── Main_ESP32.png
├── Saved.png
└── WiFiSave.png
├── LICENSE
├── README.md
├── changelog.md
├── esp32c3_ESPAsyncWebServer_Patch
├── AsyncWebSocket.cpp
└── WebAuthentication.cpp
├── esp32s2_WebServer_Patch
├── WebServer.cpp
└── WebServer.h
├── examples
├── Async_AutoConnect
│ └── Async_AutoConnect.ino
├── Async_AutoConnectWithFSParameters
│ └── Async_AutoConnectWithFSParameters.ino
├── Async_AutoConnectWithFSParametersAndCustomIP
│ └── Async_AutoConnectWithFSParametersAndCustomIP.ino
├── Async_AutoConnectWithFeedback
│ └── Async_AutoConnectWithFeedback.ino
├── Async_AutoConnectWithFeedbackLED
│ └── Async_AutoConnectWithFeedbackLED.ino
├── Async_ConfigOnDRD_FS_MQTT_Ptr
│ └── Async_ConfigOnDRD_FS_MQTT_Ptr.ino
├── Async_ConfigOnDRD_FS_MQTT_Ptr_Complex
│ └── Async_ConfigOnDRD_FS_MQTT_Ptr_Complex.ino
├── Async_ConfigOnDRD_FS_MQTT_Ptr_Medium
│ └── Async_ConfigOnDRD_FS_MQTT_Ptr_Medium.ino
├── Async_ConfigOnDoubleReset
│ └── Async_ConfigOnDoubleReset.ino
├── Async_ConfigOnDoubleReset_Multi
│ ├── Async_ConfigOnDoubleReset_Multi.cpp
│ ├── Async_ConfigOnDoubleReset_Multi.h
│ └── Async_ConfigOnDoubleReset_Multi.ino
├── Async_ConfigOnDoubleReset_TZ
│ └── Async_ConfigOnDoubleReset_TZ.ino
├── Async_ConfigOnStartup
│ └── Async_ConfigOnStartup.ino
├── Async_ConfigOnSwitch
│ ├── Async_ConfigOnSwitch.ino
│ └── README.md
├── Async_ConfigOnSwitchFS
│ └── Async_ConfigOnSwitchFS.ino
├── Async_ConfigOnSwitchFS_MQTT_Ptr
│ └── Async_ConfigOnSwitchFS_MQTT_Ptr.ino
├── Async_ConfigPortalParamsOnSwitch
│ └── Async_ConfigPortalParamsOnSwitch.ino
├── Async_ESP32_FSWebServer
│ ├── Async_ESP32_FSWebServer.ino
│ ├── README.md
│ ├── data
│ │ ├── CanadaFlag_1.png
│ │ ├── CanadaFlag_2.png
│ │ ├── CanadaFlag_3.jpg
│ │ ├── edit.htm.gz
│ │ ├── favicon.ico
│ │ ├── graphs.js.gz
│ │ └── index.htm
│ └── pics
│ │ ├── async-esp32fs.local.png
│ │ └── async-esp32fs.local_edit.png
├── Async_ESP32_FSWebServer_DRD
│ ├── Async_ESP32_FSWebServer_DRD.ino
│ ├── README.md
│ ├── data
│ │ ├── CanadaFlag_1.png
│ │ ├── CanadaFlag_2.png
│ │ ├── CanadaFlag_3.jpg
│ │ ├── edit.htm.gz
│ │ ├── favicon.ico
│ │ ├── graphs.js.gz
│ │ └── index.htm
│ └── pics
│ │ ├── async-esp32fs.local.png
│ │ └── async-esp32fs.local_edit.png
├── Async_ESP_FSWebServer
│ ├── Async_ESP_FSWebServer.ino
│ ├── README.md
│ ├── data
│ │ ├── CanadaFlag_1.png
│ │ ├── CanadaFlag_2.png
│ │ ├── CanadaFlag_3.jpg
│ │ ├── edit.htm.gz
│ │ ├── favicon.ico
│ │ ├── graphs.js.gz
│ │ └── index.htm
│ └── pics
│ │ ├── async-esp8266fs.local.png
│ │ └── async-esp8266fs.local_edit.png
└── Async_ESP_FSWebServer_DRD
│ ├── Async_ESP_FSWebServer_DRD.ino
│ ├── README.md
│ ├── data
│ ├── CanadaFlag_1.png
│ ├── CanadaFlag_2.png
│ ├── CanadaFlag_3.jpg
│ ├── edit.htm.gz
│ ├── favicon.ico
│ ├── graphs.js.gz
│ └── index.htm
│ └── pics
│ ├── async-esp8266fs.local.png
│ ├── async-esp8266fs.local_edit.png
│ ├── esp8266fs.local.png
│ └── esp8266fs.local_edit.png
├── keywords.txt
├── library.json
├── library.properties
├── platformio
└── platformio.ini
├── src
├── ESPAsync_WiFiManager-Impl.h
├── ESPAsync_WiFiManager.h
├── ESPAsync_WiFiManager.hpp
├── ESPAsync_WiFiManager_Debug.h
└── utils
│ └── TZ.h
├── travis
└── common.sh
└── utils
├── astyle_library.conf
└── restyle.sh
/.codespellrc:
--------------------------------------------------------------------------------
1 | # See: https://github.com/codespell-project/codespell#using-a-config-file
2 | [codespell]
3 | # In the event of a false positive, add the problematic word, in all lowercase, to a comma-separated list here:
4 | ignore-words-list = ,
5 | check-filenames =
6 | check-hidden =
7 | skip = ./.git,./src,./examples,./Packages_Patches,./LibraryPatches
8 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | ### Describe the bug
11 |
12 | A clear and concise description of what the bug is.
13 |
14 | ### Steps to Reproduce
15 |
16 | Steps to reproduce the behavior. Including the [MRE](https://stackoverflow.com/help/minimal-reproducible-example) sketches
17 |
18 | ### Expected behavior
19 |
20 | A clear and concise description of what you expected to happen.
21 |
22 | ### Actual behavior
23 |
24 | A clear and concise description of what you expected to happen.
25 |
26 | ### Debug and AT-command log (if applicable)
27 |
28 | A clear and concise description of what you expected to happen.
29 |
30 | ### Screenshots
31 |
32 | If applicable, add screenshots to help explain your problem.
33 |
34 | ### Information
35 |
36 | Please ensure to specify the following:
37 |
38 | * Arduino IDE version (e.g. 1.8.19) or Platform.io version
39 | * `ESP8266` or `ESP32` Core Version (e.g. ESP8266 core v3.0.2 or ESP32 v2.0.4)
40 | * Contextual information (e.g. what you were trying to achieve)
41 | * Simplest possible steps to reproduce
42 | * Anything that might be relevant in your opinion, such as:
43 | * Operating system (Windows, Ubuntu, etc.) and the output of `uname -a`
44 | * Network configuration
45 |
46 |
47 | ### Example
48 |
49 | ```
50 | Arduino IDE version: 1.8.19
51 | ESP8266 Core Version 3.0.2
52 | OS: Ubuntu 20.04 LTS
53 | Linux xy-Inspiron-3593 5.15.0-53-generic #59~20.04.1-Ubuntu SMP Thu Oct 20 15:10:22 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
54 |
55 | Context:
56 | I encountered an endless loop while trying to connect to Local WiFi.
57 |
58 | Steps to reproduce:
59 | 1. ...
60 | 2. ...
61 | 3. ...
62 | 4. ...
63 | ```
64 |
65 | ### Additional context
66 |
67 | Add any other context about the problem here
68 |
69 | ---
70 |
71 | ### Sending Feature Requests
72 |
73 | Feel free to post feature requests. It's helpful if you can explain exactly why the feature would be useful.
74 |
75 | There are usually some outstanding feature requests in the [existing issues list](https://github.com/khoih-prog/ESPAsync_WiFiManager/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement), feel free to add comments to them.
76 |
77 | ---
78 |
79 | ### Sending Pull Requests
80 |
81 | Pull Requests with changes and fixes are also welcome!
82 |
83 | Please use the `astyle` to reformat the updated library code as follows (demo for Ubuntu Linux)
84 |
85 | 1. Change directory to the library GitHub
86 |
87 | ```
88 | xy@xy-Inspiron-3593:~$ cd Arduino/xy/ESPAsync_WiFiManager_GitHub/
89 | xy@xy-Inspiron-3593:~/Arduino/xy/ESPAsync_WiFiManager_GitHub$
90 | ```
91 |
92 | 2. Issue astyle command
93 |
94 | ```
95 | xy@xy-Inspiron-3593:~/Arduino/xy/ESPAsync_WiFiManager_GitHub$ bash utils/restyle.sh
96 | ```
97 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | ### Is your feature request related to a problem? Please describe.
11 |
12 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
13 |
14 | ### Describe the solution you'd like
15 |
16 | A clear and concise description of what you want to happen.
17 |
18 | ### Describe alternatives you've considered
19 |
20 | A clear and concise description of any alternative solutions or features you've considered.
21 |
22 | ### Additional context
23 |
24 | Add any other context or screenshots about the feature request here.
25 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # See: https://docs.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates#about-the-dependabotyml-file
2 | version: 2
3 |
4 | updates:
5 | # Configure check for outdated GitHub Actions actions in workflows.
6 | # See: https://docs.github.com/en/github/administering-a-repository/keeping-your-actions-up-to-date-with-dependabot
7 | - package-ecosystem: github-actions
8 | directory: / # Check the repository's workflows under /.github/workflows/
9 | schedule:
10 | interval: daily
11 |
--------------------------------------------------------------------------------
/.github/stale.yml:
--------------------------------------------------------------------------------
1 | # Configuration for probot-stale - https://github.com/probot/stale
2 |
3 | daysUntilStale: 60
4 | daysUntilClose: 14
5 | limitPerRun: 30
6 | staleLabel: stale
7 | exemptLabels:
8 | - pinned
9 | - security
10 | - "to be implemented"
11 | - "for reference"
12 | - "move to PR"
13 | - "enhancement"
14 |
15 | only: issues
16 | onlyLabels: []
17 | exemptProjects: false
18 | exemptMilestones: false
19 | exemptAssignees: false
20 |
21 | markComment: >
22 | [STALE_SET] This issue has been automatically marked as stale because it has not had
23 | recent activity. It will be closed in 14 days if no further activity occurs. Thank you
24 | for your contributions.
25 |
26 | unmarkComment: >
27 | [STALE_CLR] This issue has been removed from the stale queue. Please ensure activity to keep it opening the future.
28 |
29 | closeComment: >
30 | [STALE_DEL] This stale issue has been automatically closed. Thank you for your contributions.
31 |
32 |
--------------------------------------------------------------------------------
/.github/workflows/auto-github-actions.yml:
--------------------------------------------------------------------------------
1 | name: auto-github-actions
2 | on: [push]
3 | jobs:
4 | check-bats-version:
5 | runs-on: ubuntu-latest
6 | steps:
7 | - uses: actions/checkout@v3
8 | - uses: actions/setup-node@v3
9 | with:
10 | node-version: '14'
11 | - run: npm install -g bats
12 | - run: bats -v
13 |
--------------------------------------------------------------------------------
/.github/workflows/check-arduino.yml:
--------------------------------------------------------------------------------
1 | name: Check Arduino
2 |
3 | # See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows
4 | on:
5 | push:
6 | pull_request:
7 | schedule:
8 | # Run every Tuesday at 8 AM UTC to catch breakage caused by new rules added to Arduino Lint.
9 | - cron: "0 8 * * TUE"
10 | workflow_dispatch:
11 | repository_dispatch:
12 |
13 | jobs:
14 | lint:
15 | runs-on: ubuntu-latest
16 |
17 | steps:
18 | - name: Checkout repository
19 | uses: actions/checkout@v3
20 |
21 | - name: Arduino Lint
22 | uses: arduino/arduino-lint-action@v1
23 | with:
24 | compliance: specification
25 | library-manager: update
26 | # Always use this setting for official repositories. Remove for 3rd party projects.
27 | official: true
28 | project-type: library
29 |
--------------------------------------------------------------------------------
/.github/workflows/report-size-deltas.yml:
--------------------------------------------------------------------------------
1 | name: Report Size Deltas
2 |
3 | on:
4 | schedule:
5 | - cron: '*/5 * * * *'
6 |
7 | jobs:
8 | report:
9 | runs-on: ubuntu-latest
10 |
11 | steps:
12 | - name: Comment size deltas reports to PRs
13 | uses: arduino/report-size-deltas@v1
14 | with:
15 | # The name of the workflow artifact created by the "Compile Examples" workflow
16 | sketches-reports-source: sketches-reports
17 |
--------------------------------------------------------------------------------
/.github/workflows/spell-check.yml:
--------------------------------------------------------------------------------
1 | name: Spell Check
2 |
3 | on:
4 | pull_request:
5 | push:
6 | schedule:
7 | # run every Tuesday at 3 AM UTC
8 | - cron: "0 3 * * 2"
9 | workflow_dispatch:
10 | repository_dispatch:
11 |
12 | jobs:
13 | spellcheck:
14 | runs-on: ubuntu-latest
15 |
16 | steps:
17 | - name: Checkout
18 | uses: actions/checkout@v3
19 |
20 | # See: https://github.com/codespell-project/actions-codespell/blob/master/README.md
21 | - name: Spell check
22 | uses: codespell-project/actions-codespell@master
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Prerequisites
2 | *.d
3 |
4 | # Compiled Object files
5 | *.slo
6 | *.lo
7 | *.o
8 | *.obj
9 |
10 | # Precompiled Headers
11 | *.gch
12 | *.pch
13 |
14 | # Compiled Dynamic libraries
15 | *.so
16 | *.dylib
17 | *.dll
18 |
19 | # Fortran module files
20 | *.mod
21 | *.smod
22 |
23 | # Compiled Static libraries
24 | *.lai
25 | *.la
26 | *.a
27 | *.lib
28 |
29 | # Executables
30 | *.exe
31 | *.out
32 | *.app
33 |
34 | # Visual Studio folder and files
35 | .vs
36 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ## Contributing to ESPAsync_WiFiManager
2 |
3 | ### Reporting Bugs
4 |
5 | Please report bugs in ESPAsync_WiFiManager if you find them.
6 |
7 | However, before reporting a bug please check through the following:
8 |
9 | * [Existing Open Issues](https://github.com/khoih-prog/ESPAsync_WiFiManager/issues) - someone might have already encountered this.
10 |
11 | If you don't find anything, please [open a new issue](https://github.com/khoih-prog/ESPAsync_WiFiManager/issues/new).
12 |
13 | ### How to submit a bug report
14 |
15 | Please ensure to specify the following, or your post will be ignored and deleted:
16 |
17 | * Arduino IDE version (e.g. 1.8.19) or Platform.io version
18 | * `ESP8266` or `ESP32` Core Version (e.g. ESP8266 core v3.0.2 or ESP32 v2.0.5)
19 | * Contextual information (e.g. what you were trying to achieve)
20 | * Simplest possible steps to reproduce
21 | * Anything that might be relevant in your opinion, such as:
22 | * Operating system (Windows, Ubuntu, etc.) and the output of `uname -a`
23 | * Network configuration
24 |
25 |
26 | ### Example
27 |
28 | ```
29 | Arduino IDE version: 1.8.19
30 | ESP8266 Core Version 3.0.2
31 | OS: Ubuntu 20.04 LTS
32 | Linux xy-Inspiron-3593 5.15.0-53-generic #59~20.04.1-Ubuntu SMP Thu Oct 20 15:10:22 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
33 |
34 | Context:
35 | I encountered a crash when using this library
36 |
37 | Steps to reproduce:
38 | 1. ...
39 | 2. ...
40 | 3. ...
41 | 4. ...
42 | ```
43 | ---
44 |
45 | ### Sending Feature Requests
46 |
47 | Feel free to post feature requests. It's helpful if you can explain exactly why the feature would be useful.
48 |
49 | There are usually some outstanding feature requests in the [existing issues list](https://github.com/khoih-prog/ESPAsync_WiFiManager/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement), feel free to add comments to them.
50 |
51 | ---
52 |
53 | ### Sending Pull Requests
54 |
55 | Pull Requests with changes and fixes are also welcome!
56 |
57 | Please use the `astyle` to reformat the updated library code as follows (demo for Ubuntu Linux)
58 |
59 | 1. Change directory to the library GitHub
60 |
61 | ```
62 | xy@xy-Inspiron-3593:~$ cd Arduino/xy/ESPAsync_WiFiManager_GitHub/
63 | xy@xy-Inspiron-3593:~/Arduino/xy/ESPAsync_WiFiManager_GitHub$
64 | ```
65 |
66 | 2. Issue astyle command
67 |
68 | ```
69 | xy@xy-Inspiron-3593:~/Arduino/xy/ESPAsync_WiFiManager_GitHub$ bash utils/restyle.sh
70 | ```
71 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/Images/Configuration.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoih-prog/ESPAsync_WiFiManager/e83343f4c2df14b504d284982152539692ac2078/Images/Configuration.png
--------------------------------------------------------------------------------
/Images/Configuration_AIO_MQTT.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoih-prog/ESPAsync_WiFiManager/e83343f4c2df14b504d284982152539692ac2078/Images/Configuration_AIO_MQTT.png
--------------------------------------------------------------------------------
/Images/Configuration_ESP32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoih-prog/ESPAsync_WiFiManager/e83343f4c2df14b504d284982152539692ac2078/Images/Configuration_ESP32.png
--------------------------------------------------------------------------------
/Images/Configuration_Standard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoih-prog/ESPAsync_WiFiManager/e83343f4c2df14b504d284982152539692ac2078/Images/Configuration_Standard.png
--------------------------------------------------------------------------------
/Images/Info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoih-prog/ESPAsync_WiFiManager/e83343f4c2df14b504d284982152539692ac2078/Images/Info.png
--------------------------------------------------------------------------------
/Images/Info_ESP32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoih-prog/ESPAsync_WiFiManager/e83343f4c2df14b504d284982152539692ac2078/Images/Info_ESP32.png
--------------------------------------------------------------------------------
/Images/Info_Short.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoih-prog/ESPAsync_WiFiManager/e83343f4c2df14b504d284982152539692ac2078/Images/Info_Short.png
--------------------------------------------------------------------------------
/Images/Main.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoih-prog/ESPAsync_WiFiManager/e83343f4c2df14b504d284982152539692ac2078/Images/Main.png
--------------------------------------------------------------------------------
/Images/Main_ESP32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoih-prog/ESPAsync_WiFiManager/e83343f4c2df14b504d284982152539692ac2078/Images/Main_ESP32.png
--------------------------------------------------------------------------------
/Images/Saved.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoih-prog/ESPAsync_WiFiManager/e83343f4c2df14b504d284982152539692ac2078/Images/Saved.png
--------------------------------------------------------------------------------
/Images/WiFiSave.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoih-prog/ESPAsync_WiFiManager/e83343f4c2df14b504d284982152539692ac2078/Images/WiFiSave.png
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Khoi Hoang
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/changelog.md:
--------------------------------------------------------------------------------
1 | # ESPAsync_WiFiManager Library
2 |
3 | [](https://www.ardu-badge.com/ESPAsync_WiFiManager)
4 | [](https://github.com/khoih-prog/ESPAsync_WiFiManager/releases)
5 | [](https://github.com/khoih-prog/ESPAsync_WiFiManager/blob/master/LICENSE)
6 | [](#Contributing)
7 | [](http://github.com/khoih-prog/ESPAsync_WiFiManager/issues)
8 |
9 |
10 |
11 |
12 |
13 | ---
14 | ---
15 |
16 | ## Table of Contents
17 |
18 | * [Changelog](#changelog)
19 | * [Releases v1.15.1](#releases-v1151)
20 | * [Releases v1.15.0](#releases-v1150)
21 | * [Releases v1.14.1](#releases-v1141)
22 | * [Releases v1.14.0](#releases-v1140)
23 | * [Releases v1.13.0](#releases-v1130)
24 | * [Releases v1.12.2](#releases-v1122)
25 | * [Releases v1.12.1](#releases-v1121)
26 | * [Releases v1.12.0](#releases-v1120)
27 | * [Releases v1.11.0](#releases-v1110)
28 | * [Releases v1.10.0](#releases-v1100)
29 | * [Releases v1.9.8](#releases-v198)
30 | * [Releases v1.9.7](#releases-v197)
31 | * [Releases v1.9.6](#releases-v196)
32 | * [Releases v1.9.5](#releases-v195)
33 | * [Releases v1.9.4](#releases-v194)
34 | * [Releases v1.9.3](#releases-v193)
35 | * [Releases v1.9.2](#releases-v192)
36 | * [Releases v1.9.1](#releases-v191)
37 | * [Releases v1.9.0](#releases-v190)
38 | * [Releases v1.8.1](#releases-v181)
39 | * [Major Releases v1.8.0](#major-releases-v180)
40 | * [Releases v1.7.1](#releases-v171)
41 | * [Releases v1.7.0](#releases-v170)
42 | * [Releases v1.6.3](#releases-v163)
43 | * [Releases v1.6.2](#releases-v162)
44 | * [Releases v1.6.1](#releases-v161)
45 | * [Releases v1.6.0](#releases-v160)
46 | * [Major Releases v1.5.0](#major-releases-v150)
47 | * [Releases v1.4.3](#releases-v143)
48 | * [Releases v1.4.2](#releases-v142)
49 | * [Releases v1.4.1](#releases-v141)
50 | * [Major Releases v1.4.0](#major-releases-v140)
51 | * [Releases v1.3.0](#releases-v130)
52 | * [Releases v1.2.0](#releases-v120)
53 | * [Releases v1.1.2](#releases-v112)
54 | * [Major Releases v1.1.1](#major-releases-v111)
55 | * [Releases v1.0.11](#releases-v1011)
56 |
57 | ---
58 | ---
59 |
60 | ## Changelog
61 |
62 | ### Releases v1.15.1
63 |
64 | 1. Using random channel for softAP without password. Check [fix: using random CH for non-password use too #118](https://github.com/khoih-prog/ESPAsync_WiFiManager/pull/118)
65 | 2. Fix bug. Check [fix: ending portal loop without processing its flags #119](https://github.com/khoih-prog/ESPAsync_WiFiManager/pull/119)
66 | 3. Add astyle using `allman` style. Restyle the library
67 |
68 |
69 | ### Releases v1.15.0
70 |
71 | 1. Optionally display Credentials (SSIDs, PWDs) in Config Portal. Check [Populate portal wifi with saved credentials #91](https://github.com/khoih-prog/ESP_WiFiManager/discussions/91) and [Prepopulating the configuration with SSID and Password from stored file #115](https://github.com/khoih-prog/ESPAsync_WiFiManager/discussions/115)
72 | 2. Display `Credentials` Hint on Config Portal
73 | 3. Periodic code clean-up
74 |
75 | ### Releases v1.14.1
76 |
77 | 1. Remove dependency on ESP_AsyncWebServer, ESPAsyncTCP and AsyncTCP in `library.properties`. Check ["no protocol" error #113](https://github.com/khoih-prog/ESPAsync_WiFiManager/issues/113)"
78 | 2. Add notes about manual installation of above-mentioned libraries for `Arduino IDE`
79 |
80 | ### Releases v1.14.0
81 |
82 | 1. Fix `ESP32 chipID`. Check [Help for storing variables in memory (non-volatile) #87](https://github.com/khoih-prog/ESP_WiFiManager/discussions/87#discussioncomment-3593028)
83 | 2. Add ESP32 `ESP_getChipOUI()` function
84 | 3. Display new info on Config Portal for ESP32
85 | 4. Remove dependency on `LittleFS_esp32` library to prevent PIO error when using new `ESP32 core v1.0.6+`
86 |
87 | ### Releases v1.13.0
88 |
89 | 1. Using AsyncDNSServer instead of DNSServer. Check [Captive Portal hanging depending on active core for AsyncTCP #100](https://github.com/khoih-prog/ESPAsync_WiFiManager/issues/100)
90 |
91 |
92 | ### Releases v1.12.2
93 |
94 | 1. Optimize code by using passing by `reference` instead of by `value`
95 | 2. Delete all confusing, function-lacking `minimal` examples
96 | 3. Delete all `Modeless` examples
97 | 4. Display informational warnings only when `_ESPASYNC_WIFIMGR_LOGLEVEL_ > 3`
98 |
99 | ### Releases v1.12.1
100 |
101 | 1. Add LittleFS support to `ESP32-C3`.
102 | 2. Use ESP32-core's LittleFS library instead of Lorol's LITTLEFS library for v2.0.0+
103 |
104 | ### Releases v1.12.0
105 |
106 | 1. Add support to `ESP32-S3` (`ESP32S3_DEV, ESP32_S3_BOX, UM TINYS3, UM PROS3, UM FEATHERS3`, etc.) using [ESP32 core, esp32-s3-support branch, v2.0.2+](https://github.com/espressif/arduino-esp32/tree/esp32-s3-support)
107 |
108 | ### Releases v1.11.0
109 |
110 | 1. Reduce the breaking effect of v1.10.0 by enabling compatibility with old code to include only `ESPAsync_WiFiManager.h`. Check [Important Breaking Change from v1.10.0](https://github.com/khoih-prog/ESPAsync_WiFiManager#Important-Breaking-Change-from-v1100)
111 |
112 | ### Releases v1.10.0
113 |
114 | 1. Fix `multiple-definitions` linker error and weird bug related to `src_cpp`. Check [Different behaviour using the src_cpp or src_h lib #80](https://github.com/khoih-prog/ESPAsync_WiFiManager/discussions/80)
115 | 2. Optimize library code by using `reference-passing` instead of `value-passing`
116 |
117 | ### Releases v1.9.8
118 |
119 | 1. Fix bug returning IP `255.255.255.255` in core v2.0.0+ when using `hostname`
120 |
121 | ### Releases v1.9.7
122 |
123 | 1. Fix bug to permit using HTTP port different from 80. Check [WiFiManager works only on port 80 #75](https://github.com/khoih-prog/ESPAsync_WiFiManager/issues/75)
124 |
125 | ### Releases v1.9.6
126 |
127 | 1. Fix compile error for ESP32 core v1.0.5-
128 |
129 | ### Releases v1.9.5
130 |
131 | 1. Auto detect ESP32 core and use either built-in LittleFS or [LITTLEFS](https://github.com/lorol/LITTLEFS) library
132 | 2. Update `library.json` to use new `headers` for PIO
133 |
134 |
135 | ### Releases v1.9.4
136 |
137 | 1. Update `platform.ini` and `library.json` to use original `khoih-prog` instead of `khoih.prog` after PIO fix
138 |
139 | ### Releases v1.9.3
140 |
141 | 1. Add WiFi scanning of hidden SSIDs. Check [Add support for Wifi hidden SSID scanning. #66](https://github.com/khoih-prog/ESP_WiFiManager/pull/66)
142 |
143 | ### Releases v1.9.2
144 |
145 | 1. Fix MultiWiFi connection issue with ESP32 core v2.0.0-rc1+
146 | 2. Fix AsyncWebServer library compile error with ESP32 core v2.0.0-rc1+. Check [Fix compiler error for ESP32-C3 and mbed TLS v2.7.0+ #970](https://github.com/me-no-dev/ESPAsyncWebServer/pull/970)
147 | 3. Verify compatibility with new ESP32 core v2.0.0-rc1+
148 | 4. Verify compatibility with new ESP8266 core v3.0.2
149 |
150 | ### Releases v1.9.1
151 |
152 | 1. Fix warnings and verify compatibility with new ESP8266 core v3.0.0
153 | 2. Autodetect ESP8266 core v1.7.4- or new ESP8266 core v3.0.0 to use the new breaking features
154 |
155 | ### Releases v1.9.0
156 |
157 | 1. Add WiFi `/scan` page.
158 | 2. Fix timezoneName not displayed in Info page.
159 | 3. Clean up.
160 |
161 | ### Releases v1.8.1
162 |
163 | 1. Fix bug.
164 | 2. Don't display invalid time when not synch yet.
165 |
166 | ### Major Releases v1.8.0
167 |
168 | 1. Add auto-Timezone feature with variable `_timezoneName` (e.g. `America/New_York`) and function to retrieve TZ (e.g. `EST5EDT,M3.2.0,M11.1.0`) to use directly to configure ESP32/ESP8266 timezone. Check [How to retrieve timezone? #51](https://github.com/khoih-prog/ESPAsync_WiFiManager/issues/51)
169 | 2. Store those `_timezoneName` and `TZ` in LittleFS or SPIFFS config file.
170 | 3. Using these new timezone feature is optional.
171 | 4. Add checksum in config file to validate data read from LittleFS or SPIFFS config file.
172 | 5. Update examples to show how to use the new TZ feature.
173 |
174 | ### Releases v1.7.1
175 |
176 | 1. Fix captive-portal bug if Config Portal AP address is not default 192.168.4.1. Check [In AP, DNS server always redirects to 192.168.4.1 no matter what APStaticIP is set to. #58](https://github.com/khoih-prog/ESP_WiFiManager/issues/58)
177 | 2. Fix MultiWiFi bug.
178 |
179 | ### Releases v1.7.0
180 |
181 | 1. Add **LittleFS and SPIFFS** support to new **ESP32-S2** boards (**Arduino ESP32C3_DEV**). Check [HOWTO Install esp32 core for ESP32-S2 (Saola, AI-Thinker ESP-12K) and ESP32-C3 boards into Arduino IDE](#howto-install-esp32-core-for-esp32-s2-saola-ai-thinker-esp-12k-and-esp32-c3-boards-into-arduino-ide).
182 | 2. Add **EEPROM and SPIFFS** support to new **ESP32-C3** boards (**Arduino ESP32C3_DEV**). Check [HOWTO Install esp32 core for ESP32-S2 (Saola, AI-Thinker ESP-12K) and ESP32-C3 boards into Arduino IDE](#howto-install-esp32-core-for-esp32-s2-saola-ai-thinker-esp-12k-and-esp32-c3-boards-into-arduino-ide).
183 |
184 | ### Releases v1.6.3
185 |
186 | 1. Fix dnsServer not closed to free up DNS port 53. Check [**Allow captive portal to run more than once by closing dnsServer cleanly.** #49](https://github.com/khoih-prog/ESPAsync_WiFiManager/pull/49)
187 | 2. Add `dnsServer can't start` error message.
188 |
189 | ### Releases v1.6.2
190 |
191 | 1. Fix example misleading messages. Check [**Minor: examples/Async_ESP32_FSWebServer/ wrongly uses FileFS.begin(true)** #47](https://github.com/khoih-prog/ESPAsync_WiFiManager/issues/47)
192 |
193 | ### Releases v1.6.1
194 |
195 | 1. Modify multiWiFi-related timings to work better with latest esp32 core v1.0.6
196 |
197 | ### Releases v1.6.0
198 |
199 | 1. Fix WiFi Scanning bug.
200 |
201 | ### Major Releases v1.5.0
202 |
203 | 1. Add support to **ESP32-S2 (ESP32-S2 Saola, AI-Thinker ESP-12K, ESP32S2 Dev Module, UM FeatherS2, UM ProS2, microS2, etc.)**
204 | 2. Add [**Instructions to install ESP32-S2 core**](#howto-install-esp32-s2-core-for-esp32-s2-saola-ai-thinker-esp-12k-boards-into-arduino-ide)
205 | 3. Rewrite library code to be more efficient and multitask friendly
206 |
207 | ### Releases v1.4.3
208 |
209 | 1. Fix examples' bug not saving Static IP in certain cases.
210 | 2. Add feature to warn if using examples with old library versions
211 |
212 | ### Releases v1.4.2
213 |
214 | 1. Fix examples' bug not using saved WiFi Credentials after losing all WiFi connections.
215 | 2. Fix compiler warnings.
216 |
217 | ### Releases v1.4.1
218 |
219 | 1. Fix bug.
220 | 2. Fix compiler warnings.
221 |
222 | ### Major Releases v1.4.0
223 |
224 | 1. Fix staticIP not saved in examples. See [ESP32 static IP not saved after restarting the device](https://github.com/khoih-prog/ESPAsync_WiFiManager/issues/19)
225 | 2. Add structures and functions to handle AP and STA IPs.
226 | 3. Add complex examples
227 | * [Async_ConfigOnDRD_FS_MQTT_Ptr_Complex](examples/Async_ConfigOnDRD_FS_MQTT_Ptr_Complex) to demo usage of std::map
228 | * [Async_ConfigOnDRD_FS_MQTT_Ptr_Medium](examples/Async_ConfigOnDRD_FS_MQTT_Ptr_Medium).
229 | 4. Add simple minimal examples
230 | * [Async_ConfigOnDRD_ESP32_minimal](examples/Async_ConfigOnDRD_ESP32_minimal)
231 | * [Async_ConfigOnDRD_ESP8266_minimal](examples/Async_ConfigOnDRD_ESP8266_minimal)
232 | * [Async_AutoConnect_ESP32_minimal](examples/Async_AutoConnect_ESP32_minimal)
233 | * [Async_AutoConnect_ESP8266_minimal](examples/Async_AutoConnect_ESP8266_minimal)
234 | 5. Modify Version String
235 | 6. Add Table of Contents
236 |
237 | ### Releases v1.3.0
238 |
239 | 1. Add LittleFS support to ESP32-related examples to use [**LittleFS_esp32 Library**](https://github.com/lorol/LITTLEFS)
240 | 2. Add Version String
241 |
242 | ### Releases v1.2.0
243 |
244 | 1. Restore cpp code besides Impl.h code to use in case of `multiple definition` linker error. See [`Change Implementation to separate *.h and *.cpp file instead of *.h and *-Impl.h`](https://github.com/khoih-prog/ESP_WiFiManager/issues/38) and [`Support building in PlatformIO PR`](https://github.com/khoih-prog/ESP_WiFiManager/pull/20). Also have a look at [**HOWTO Fix Multiple Definitions Linker Error**](https://github.com/khoih-prog/ESPAsync_WiFiManager#HOWTO-Fix-Multiple-Definitions-Linker-Error)
245 | 2. Fix bug [/close does not close the config portal](https://github.com/khoih-prog/ESPAsync_WiFiManager/issues/16).
246 |
247 | ### Releases v1.1.2
248 |
249 | 1. Fix bug in examples.
250 |
251 | ### Major Releases v1.1.1
252 |
253 | 1. Add **MultiWiFi feature to auto(Re)connect to the best WiFi at runtime**
254 | 2. Fix bug, typo and minor improvement.
255 | 3. Completely enhanced examples to use new MultiWiFi feature.
256 | 4. Add setCORSHeader function to allow **configurable CORS Header**. See [Using CORS feature](https://github.com/khoih-prog/ESPAsync_WiFiManager#15-using-cors-cross-origin-resource-sharing-feature)
257 | 5. Bump up to v1.1.1 to sync with [ESP_WiFiManager v1.1.1](https://github.com/khoih-prog/ESP_WiFiManager/releases/tag/v1.1.1).
258 |
259 | ### Releases 1.0.11
260 |
261 | 1. Initial coding to use ESPAsyncWebServer instead of (ESP8266)WebServer.
262 | 2. Add more features and error checking to many examples.
263 | 3. Add example [Async_ConfigOnDRD_FS_MQTT_Ptr](examples/Async_ConfigOnDRD_FS_MQTT_Ptr)
264 | 4. Bump up to v1.0.11 to sync with ESP_WiFiManager v1.0.11.
265 |
266 |
267 |
--------------------------------------------------------------------------------
/esp32c3_ESPAsyncWebServer_Patch/WebAuthentication.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Asynchronous WebServer library for Espressif MCUs
3 |
4 | Copyright (c) 2016 Hristo Gochkov. All rights reserved.
5 | This file is part of the esp8266 core for Arduino environment.
6 |
7 | This library is free software; you can redistribute it and/or
8 | modify it under the terms of the GNU Lesser General Public
9 | License as published by the Free Software Foundation; either
10 | version 2.1 of the License, or (at your option) any later version.
11 |
12 | This library is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 | Lesser General Public License for more details.
16 |
17 | You should have received a copy of the GNU Lesser General Public
18 | License along with this library; if not, write to the Free Software
19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 | */
21 | #include "WebAuthentication.h"
22 | #include
23 | #ifdef ESP32
24 | #include "mbedtls/md5.h"
25 | #include "mbedtls/version.h"
26 | #else
27 | #include "md5.h"
28 | #endif
29 |
30 |
31 | // Basic Auth hash = base64("username:password")
32 |
33 | bool checkBasicAuthentication(const char * hash, const char * username, const char * password)
34 | {
35 | if (username == NULL || password == NULL || hash == NULL)
36 | return false;
37 |
38 | size_t toencodeLen = strlen(username) + strlen(password) + 1;
39 | size_t encodedLen = base64_encode_expected_len(toencodeLen);
40 |
41 | if (strlen(hash) != encodedLen)
42 | return false;
43 |
44 | char *toencode = new char[toencodeLen + 1];
45 |
46 | if (toencode == NULL)
47 | {
48 | return false;
49 | }
50 |
51 | char *encoded = new char[base64_encode_expected_len(toencodeLen) + 1];
52 |
53 | if (encoded == NULL)
54 | {
55 | delete[] toencode;
56 | return false;
57 | }
58 |
59 | sprintf(toencode, "%s:%s", username, password);
60 |
61 | if (base64_encode_chars(toencode, toencodeLen, encoded) > 0 && memcmp(hash, encoded, encodedLen) == 0)
62 | {
63 | delete[] toencode;
64 | delete[] encoded;
65 | return true;
66 | }
67 |
68 | delete[] toencode;
69 | delete[] encoded;
70 | return false;
71 | }
72 |
73 | static bool getMD5(uint8_t * data, uint16_t len, char * output) //33 bytes or more
74 | {
75 | #ifdef ESP32
76 | mbedtls_md5_context _ctx;
77 | #else
78 | md5_context_t _ctx;
79 | #endif
80 | uint8_t i;
81 | uint8_t * _buf = (uint8_t*)malloc(16);
82 |
83 | if (_buf == NULL)
84 | return false;
85 |
86 | memset(_buf, 0x00, 16);
87 | #ifdef ESP32
88 | mbedtls_md5_init(&_ctx);
89 |
90 | // KH
91 | #if (MBEDTLS_VERSION_NUMBER < 0x02070000)
92 | #warning MBEDTLS_VERSION_NUMBER < 2.7.0
93 | // Superseded from v2.7.0
94 | mbedtls_md5_starts(&_ctx);
95 | mbedtls_md5_update(&_ctx, data, len);
96 | mbedtls_md5_finish(&_ctx, _buf);
97 | #else
98 | #warning MBEDTLS_VERSION_NUMBER >= 2.7.0
99 | mbedtls_md5_starts_ret(&_ctx);
100 | mbedtls_md5_update_ret(&_ctx, data, len);
101 | mbedtls_md5_finish_ret(&_ctx, _buf);
102 | #endif
103 | //////
104 |
105 | #else
106 | MD5Init(&_ctx);
107 | MD5Update(&_ctx, data, len);
108 | MD5Final(_buf, &_ctx);
109 | #endif
110 |
111 | for (i = 0; i < 16; i++)
112 | {
113 | sprintf(output + (i * 2), "%02x", _buf[i]);
114 | }
115 |
116 | free(_buf);
117 | return true;
118 | }
119 |
120 | static String genRandomMD5()
121 | {
122 | #ifdef ESP8266
123 | uint32_t r = RANDOM_REG32;
124 | #else
125 | uint32_t r = rand();
126 | #endif
127 | char * out = (char*)malloc(33);
128 |
129 | if (out == NULL || !getMD5((uint8_t*)(&r), 4, out))
130 | return "";
131 |
132 | String res = String(out);
133 | free(out);
134 | return res;
135 | }
136 |
137 | static String stringMD5(const String& in)
138 | {
139 | char * out = (char*)malloc(33);
140 |
141 | if (out == NULL || !getMD5((uint8_t*)(in.c_str()), in.length(), out))
142 | return "";
143 |
144 | String res = String(out);
145 | free(out);
146 | return res;
147 | }
148 |
149 | String generateDigestHash(const char * username, const char * password, const char * realm)
150 | {
151 | if (username == NULL || password == NULL || realm == NULL)
152 | {
153 | return "";
154 | }
155 |
156 | char * out = (char*)malloc(33);
157 | String res = String(username);
158 | res.concat(":");
159 | res.concat(realm);
160 | res.concat(":");
161 | String in = res;
162 | in.concat(password);
163 |
164 | if (out == NULL || !getMD5((uint8_t*)(in.c_str()), in.length(), out))
165 | return "";
166 |
167 | res.concat(out);
168 | free(out);
169 | return res;
170 | }
171 |
172 | String requestDigestAuthentication(const char * realm)
173 | {
174 | String header = "realm=\"";
175 |
176 | if (realm == NULL)
177 | header.concat("asyncesp");
178 | else
179 | header.concat(realm);
180 |
181 | header.concat( "\", qop=\"auth\", nonce=\"");
182 | header.concat(genRandomMD5());
183 | header.concat("\", opaque=\"");
184 | header.concat(genRandomMD5());
185 | header.concat("\"");
186 | return header;
187 | }
188 |
189 | bool checkDigestAuthentication(const char * header, const char * method, const char * username, const char * password,
190 | const char * realm, bool passwordIsHash, const char * nonce, const char * opaque, const char * uri)
191 | {
192 | if (username == NULL || password == NULL || header == NULL || method == NULL)
193 | {
194 | //os_printf("AUTH FAIL: missing required fields\n");
195 | return false;
196 | }
197 |
198 | String myHeader = String(header);
199 | int nextBreak = myHeader.indexOf(",");
200 |
201 | if (nextBreak < 0)
202 | {
203 | //os_printf("AUTH FAIL: no variables\n");
204 | return false;
205 | }
206 |
207 | String myUsername = String();
208 | String myRealm = String();
209 | String myNonce = String();
210 | String myUri = String();
211 | String myResponse = String();
212 | String myQop = String();
213 | String myNc = String();
214 | String myCnonce = String();
215 |
216 | myHeader += ", ";
217 |
218 | do
219 | {
220 | String avLine = myHeader.substring(0, nextBreak);
221 | avLine.trim();
222 | myHeader = myHeader.substring(nextBreak + 1);
223 | nextBreak = myHeader.indexOf(",");
224 |
225 | int eqSign = avLine.indexOf("=");
226 |
227 | if (eqSign < 0)
228 | {
229 | //os_printf("AUTH FAIL: no = sign\n");
230 | return false;
231 | }
232 |
233 | String varName = avLine.substring(0, eqSign);
234 | avLine = avLine.substring(eqSign + 1);
235 |
236 | if (avLine.startsWith("\""))
237 | {
238 | avLine = avLine.substring(1, avLine.length() - 1);
239 | }
240 |
241 | if (varName.equals("username"))
242 | {
243 | if (!avLine.equals(username))
244 | {
245 | //os_printf("AUTH FAIL: username\n");
246 | return false;
247 | }
248 |
249 | myUsername = avLine;
250 | }
251 | else if (varName.equals("realm"))
252 | {
253 | if (realm != NULL && !avLine.equals(realm))
254 | {
255 | //os_printf("AUTH FAIL: realm\n");
256 | return false;
257 | }
258 |
259 | myRealm = avLine;
260 | }
261 | else if (varName.equals("nonce"))
262 | {
263 | if (nonce != NULL && !avLine.equals(nonce))
264 | {
265 | //os_printf("AUTH FAIL: nonce\n");
266 | return false;
267 | }
268 |
269 | myNonce = avLine;
270 | }
271 | else if (varName.equals("opaque"))
272 | {
273 | if (opaque != NULL && !avLine.equals(opaque))
274 | {
275 | //os_printf("AUTH FAIL: opaque\n");
276 | return false;
277 | }
278 | }
279 | else if (varName.equals("uri"))
280 | {
281 | if (uri != NULL && !avLine.equals(uri))
282 | {
283 | //os_printf("AUTH FAIL: uri\n");
284 | return false;
285 | }
286 |
287 | myUri = avLine;
288 | }
289 | else if (varName.equals("response"))
290 | {
291 | myResponse = avLine;
292 | }
293 | else if (varName.equals("qop"))
294 | {
295 | myQop = avLine;
296 | }
297 | else if (varName.equals("nc"))
298 | {
299 | myNc = avLine;
300 | }
301 | else if (varName.equals("cnonce"))
302 | {
303 | myCnonce = avLine;
304 | }
305 | } while (nextBreak > 0);
306 |
307 | String ha1 = (passwordIsHash) ? String(password) : stringMD5(myUsername + ":" + myRealm + ":" + String(password));
308 | String ha2 = String(method) + ":" + myUri;
309 | String response = ha1 + ":" + myNonce + ":" + myNc + ":" + myCnonce + ":" + myQop + ":" + stringMD5(ha2);
310 |
311 | if (myResponse.equals(stringMD5(response)))
312 | {
313 | //os_printf("AUTH SUCCESS\n");
314 | return true;
315 | }
316 |
317 | //os_printf("AUTH FAIL: password\n");
318 | return false;
319 | }
320 |
--------------------------------------------------------------------------------
/esp32s2_WebServer_Patch/WebServer.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | WebServer.cpp - Dead simple web-server.
3 | Supports only one simultaneous client, knows how to handle GET and POST.
4 |
5 | Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
6 |
7 | This library is free software; you can redistribute it and/or
8 | modify it under the terms of the GNU Lesser General Public
9 | License as published by the Free Software Foundation; either
10 | version 2.1 of the License, or (at your option) any later version.
11 |
12 | This library is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 | Lesser General Public License for more details.
16 |
17 | You should have received a copy of the GNU Lesser General Public
18 | License along with this library; if not, write to the Free Software
19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 | Modified 8 May 2015 by Hristo Gochkov (proper post and file upload handling)
21 | */
22 |
23 | // KH, Using "WebServer.handleClient delay" (https://github.com/espressif/arduino-esp32/pull/4350)
24 |
25 | #include
26 | #include
27 | #include
28 | #include "WiFiServer.h"
29 | #include "WiFiClient.h"
30 | #include "WebServer.h"
31 | #include "FS.h"
32 | #include "detail/RequestHandlersImpl.h"
33 | #include "mbedtls/md5.h"
34 |
35 |
36 | static const char AUTHORIZATION_HEADER[] = "Authorization";
37 | static const char qop_auth[] = "qop=\"auth\"";
38 | static const char WWW_Authenticate[] = "WWW-Authenticate";
39 | static const char Content_Length[] = "Content-Length";
40 |
41 |
42 | WebServer::WebServer(IPAddress addr, int port)
43 | : _corsEnabled(false)
44 | , _server(addr, port)
45 | , _currentMethod(HTTP_ANY)
46 | , _currentVersion(0)
47 | , _currentStatus(HC_NONE)
48 | , _statusChange(0)
49 | , _nullDelay(true)
50 | , _currentHandler(nullptr)
51 | , _firstHandler(nullptr)
52 | , _lastHandler(nullptr)
53 | , _currentArgCount(0)
54 | , _currentArgs(nullptr)
55 | , _postArgsLen(0)
56 | , _postArgs(nullptr)
57 | , _headerKeysCount(0)
58 | , _currentHeaders(nullptr)
59 | , _contentLength(0)
60 | , _chunked(false)
61 | {
62 | }
63 |
64 | WebServer::WebServer(int port)
65 | : _corsEnabled(false)
66 | , _server(port)
67 | , _currentMethod(HTTP_ANY)
68 | , _currentVersion(0)
69 | , _currentStatus(HC_NONE)
70 | , _statusChange(0)
71 | , _nullDelay(true)
72 | , _currentHandler(nullptr)
73 | , _firstHandler(nullptr)
74 | , _lastHandler(nullptr)
75 | , _currentArgCount(0)
76 | , _currentArgs(nullptr)
77 | , _postArgsLen(0)
78 | , _postArgs(nullptr)
79 | , _headerKeysCount(0)
80 | , _currentHeaders(nullptr)
81 | , _contentLength(0)
82 | , _chunked(false)
83 | {
84 | }
85 |
86 | WebServer::~WebServer()
87 | {
88 | _server.close();
89 |
90 | if (_currentHeaders)
91 | delete[]_currentHeaders;
92 |
93 | RequestHandler* handler = _firstHandler;
94 |
95 | while (handler)
96 | {
97 | RequestHandler* next = handler->next();
98 | delete handler;
99 | handler = next;
100 | }
101 | }
102 |
103 | void WebServer::begin()
104 | {
105 | close();
106 | _server.begin();
107 | _server.setNoDelay(true);
108 | }
109 |
110 | void WebServer::begin(uint16_t port)
111 | {
112 | close();
113 | _server.begin(port);
114 | _server.setNoDelay(true);
115 | }
116 |
117 | String WebServer::_extractParam(String& authReq, const String& param, const char delimit)
118 | {
119 | int _begin = authReq.indexOf(param);
120 |
121 | if (_begin == -1)
122 | return "";
123 |
124 | return authReq.substring(_begin + param.length(), authReq.indexOf(delimit, _begin + param.length()));
125 | }
126 |
127 | static String md5str(String &in)
128 | {
129 | char out[33] = {0};
130 | mbedtls_md5_context _ctx;
131 | uint8_t i;
132 | uint8_t * _buf = (uint8_t*)malloc(16);
133 |
134 | if (_buf == NULL)
135 | return String(out);
136 |
137 | memset(_buf, 0x00, 16);
138 | mbedtls_md5_init(&_ctx);
139 | mbedtls_md5_starts(&_ctx);
140 | mbedtls_md5_update(&_ctx, (const uint8_t *)in.c_str(), in.length());
141 | mbedtls_md5_finish(&_ctx, _buf);
142 |
143 | for (i = 0; i < 16; i++)
144 | {
145 | sprintf(out + (i * 2), "%02x", _buf[i]);
146 | }
147 |
148 | out[32] = 0;
149 | free(_buf);
150 | return String(out);
151 | }
152 |
153 | bool WebServer::authenticate(const char * username, const char * password)
154 | {
155 | if (hasHeader(FPSTR(AUTHORIZATION_HEADER)))
156 | {
157 | String authReq = header(FPSTR(AUTHORIZATION_HEADER));
158 |
159 | if (authReq.startsWith(F("Basic")))
160 | {
161 | authReq = authReq.substring(6);
162 | authReq.trim();
163 | char toencodeLen = strlen(username) + strlen(password) + 1;
164 | char *toencode = new char[toencodeLen + 1];
165 |
166 | if (toencode == NULL)
167 | {
168 | authReq = "";
169 | return false;
170 | }
171 |
172 | char *encoded = new char[base64_encode_expected_len(toencodeLen) + 1];
173 |
174 | if (encoded == NULL)
175 | {
176 | authReq = "";
177 | delete[] toencode;
178 | return false;
179 | }
180 |
181 | sprintf(toencode, "%s:%s", username, password);
182 |
183 | if (base64_encode_chars(toencode, toencodeLen, encoded) > 0 && authReq.equalsConstantTime(encoded))
184 | {
185 | authReq = "";
186 | delete[] toencode;
187 | delete[] encoded;
188 | return true;
189 | }
190 |
191 | delete[] toencode;
192 | delete[] encoded;
193 | }
194 | else if (authReq.startsWith(F("Digest")))
195 | {
196 | authReq = authReq.substring(7);
197 | log_v("%s", authReq.c_str());
198 | String _username = _extractParam(authReq, F("username=\""), '\"');
199 |
200 | if (!_username.length() || _username != String(username))
201 | {
202 | authReq = "";
203 | return false;
204 | }
205 |
206 | // extracting required parameters for RFC 2069 simpler Digest
207 | String _realm = _extractParam(authReq, F("realm=\""), '\"');
208 | String _nonce = _extractParam(authReq, F("nonce=\""), '\"');
209 | String _uri = _extractParam(authReq, F("uri=\""), '\"');
210 | String _response = _extractParam(authReq, F("response=\""), '\"');
211 | String _opaque = _extractParam(authReq, F("opaque=\""), '\"');
212 |
213 | if ((!_realm.length()) || (!_nonce.length()) || (!_uri.length()) || (!_response.length()) || (!_opaque.length()))
214 | {
215 | authReq = "";
216 | return false;
217 | }
218 |
219 | if ((_opaque != _sopaque) || (_nonce != _snonce) || (_realm != _srealm))
220 | {
221 | authReq = "";
222 | return false;
223 | }
224 |
225 | // parameters for the RFC 2617 newer Digest
226 | String _nc, _cnonce;
227 |
228 | if (authReq.indexOf(FPSTR(qop_auth)) != -1)
229 | {
230 | _nc = _extractParam(authReq, F("nc="), ',');
231 | _cnonce = _extractParam(authReq, F("cnonce=\""), '\"');
232 | }
233 |
234 | String _H1 = md5str(String(username) + ':' + _realm + ':' + String(password));
235 | log_v("Hash of user:realm:pass=%s", _H1.c_str());
236 | String _H2 = "";
237 |
238 | if (_currentMethod == HTTP_GET)
239 | {
240 | _H2 = md5str(String(F("GET:")) + _uri);
241 | }
242 | else if (_currentMethod == HTTP_POST)
243 | {
244 | _H2 = md5str(String(F("POST:")) + _uri);
245 | }
246 | else if (_currentMethod == HTTP_PUT)
247 | {
248 | _H2 = md5str(String(F("PUT:")) + _uri);
249 | }
250 | else if (_currentMethod == HTTP_DELETE)
251 | {
252 | _H2 = md5str(String(F("DELETE:")) + _uri);
253 | }
254 | else
255 | {
256 | _H2 = md5str(String(F("GET:")) + _uri);
257 | }
258 |
259 | log_v("Hash of GET:uri=%s", _H2.c_str());
260 | String _responsecheck = "";
261 |
262 | if (authReq.indexOf(FPSTR(qop_auth)) != -1)
263 | {
264 | _responsecheck = md5str(_H1 + ':' + _nonce + ':' + _nc + ':' + _cnonce + F(":auth:") + _H2);
265 | }
266 | else
267 | {
268 | _responsecheck = md5str(_H1 + ':' + _nonce + ':' + _H2);
269 | }
270 |
271 | log_v("The Proper response=%s", _responsecheck.c_str());
272 |
273 | if (_response == _responsecheck)
274 | {
275 | authReq = "";
276 | return true;
277 | }
278 | }
279 |
280 | authReq = "";
281 | }
282 |
283 | return false;
284 | }
285 |
286 | String WebServer::_getRandomHexString()
287 | {
288 | char buffer[33]; // buffer to hold 32 Hex Digit + /0
289 | int i;
290 |
291 | for (i = 0; i < 4; i++)
292 | {
293 | sprintf (buffer + (i * 8), "%08x", esp_random());
294 | }
295 |
296 | return String(buffer);
297 | }
298 |
299 | void WebServer::requestAuthentication(HTTPAuthMethod mode, const char* realm, const String& authFailMsg)
300 | {
301 | if (realm == NULL)
302 | {
303 | _srealm = String(F("Login Required"));
304 | }
305 | else
306 | {
307 | _srealm = String(realm);
308 | }
309 |
310 | if (mode == BASIC_AUTH)
311 | {
312 | sendHeader(String(FPSTR(WWW_Authenticate)), String(F("Basic realm=\"")) + _srealm + String(F("\"")));
313 | }
314 | else
315 | {
316 | _snonce = _getRandomHexString();
317 | _sopaque = _getRandomHexString();
318 | sendHeader(String(FPSTR(WWW_Authenticate)),
319 | String(F("Digest realm=\"")) + _srealm + String(F("\", qop=\"auth\", nonce=\"")) + _snonce + String(
320 | F("\", opaque=\"")) + _sopaque + String(F("\"")));
321 | }
322 |
323 | using namespace mime;
324 | send(401, String(FPSTR(mimeTable[html].mimeType)), authFailMsg);
325 | }
326 |
327 | void WebServer::on(const Uri &uri, WebServer::THandlerFunction handler)
328 | {
329 | on(uri, HTTP_ANY, handler);
330 | }
331 |
332 | void WebServer::on(const Uri &uri, HTTPMethod method, WebServer::THandlerFunction fn)
333 | {
334 | on(uri, method, fn, _fileUploadHandler);
335 | }
336 |
337 | void WebServer::on(const Uri &uri, HTTPMethod method, WebServer::THandlerFunction fn, WebServer::THandlerFunction ufn)
338 | {
339 | _addRequestHandler(new FunctionRequestHandler(fn, ufn, uri, method));
340 | }
341 |
342 | void WebServer::addHandler(RequestHandler* handler)
343 | {
344 | _addRequestHandler(handler);
345 | }
346 |
347 | void WebServer::_addRequestHandler(RequestHandler* handler)
348 | {
349 | if (!_lastHandler)
350 | {
351 | _firstHandler = handler;
352 | _lastHandler = handler;
353 | }
354 | else
355 | {
356 | _lastHandler->next(handler);
357 | _lastHandler = handler;
358 | }
359 | }
360 |
361 | void WebServer::serveStatic(const char* uri, FS& fs, const char* path, const char* cache_header)
362 | {
363 | _addRequestHandler(new StaticRequestHandler(fs, path, uri, cache_header));
364 | }
365 |
366 | void WebServer::handleClient()
367 | {
368 | if (_currentStatus == HC_NONE)
369 | {
370 | WiFiClient client = _server.available();
371 |
372 | if (!client)
373 | {
374 | if (_nullDelay)
375 | {
376 | delay(1);
377 | }
378 |
379 | return;
380 | }
381 |
382 | log_v("New client");
383 |
384 | _currentClient = client;
385 | _currentStatus = HC_WAIT_READ;
386 | _statusChange = millis();
387 | }
388 |
389 | bool keepCurrentClient = false;
390 | bool callYield = false;
391 |
392 | if (_currentClient.connected())
393 | {
394 | switch (_currentStatus)
395 | {
396 | case HC_NONE:
397 | // No-op to avoid C++ compiler warning
398 | break;
399 |
400 | case HC_WAIT_READ:
401 |
402 | // Wait for data from client to become available
403 | if (_currentClient.available())
404 | {
405 | if (_parseRequest(_currentClient))
406 | {
407 | // because HTTP_MAX_SEND_WAIT is expressed in milliseconds,
408 | // it must be divided by 1000
409 | _currentClient.setTimeout(HTTP_MAX_SEND_WAIT / 1000);
410 | _contentLength = CONTENT_LENGTH_NOT_SET;
411 | _handleRequest();
412 |
413 | // Fix for issue with Chrome based browsers: https://github.com/espressif/arduino-esp32/issues/3652
414 | // if (_currentClient.connected()) {
415 | // _currentStatus = HC_WAIT_CLOSE;
416 | // _statusChange = millis();
417 | // keepCurrentClient = true;
418 | // }
419 | }
420 | }
421 | else // !_currentClient.available()
422 | {
423 | if (millis() - _statusChange <= HTTP_MAX_DATA_WAIT)
424 | {
425 | keepCurrentClient = true;
426 | }
427 |
428 | callYield = true;
429 | }
430 |
431 | break;
432 |
433 | case HC_WAIT_CLOSE:
434 |
435 | // Wait for client to close the connection
436 | if (millis() - _statusChange <= HTTP_MAX_CLOSE_WAIT)
437 | {
438 | keepCurrentClient = true;
439 | callYield = true;
440 | }
441 | }
442 | }
443 |
444 | if (!keepCurrentClient)
445 | {
446 | _currentClient = WiFiClient();
447 | _currentStatus = HC_NONE;
448 | _currentUpload.reset();
449 | }
450 |
451 | if (callYield)
452 | {
453 | yield();
454 | }
455 | }
456 |
457 | void WebServer::close()
458 | {
459 | _server.close();
460 | _currentStatus = HC_NONE;
461 |
462 | if (!_headerKeysCount)
463 | collectHeaders(0, 0);
464 | }
465 |
466 | void WebServer::stop()
467 | {
468 | close();
469 | }
470 |
471 | void WebServer::sendHeader(const String& name, const String& value, bool first)
472 | {
473 | String headerLine = name;
474 | headerLine += F(": ");
475 | headerLine += value;
476 | headerLine += "\r\n";
477 |
478 | if (first)
479 | {
480 | _responseHeaders = headerLine + _responseHeaders;
481 | }
482 | else
483 | {
484 | _responseHeaders += headerLine;
485 | }
486 | }
487 |
488 | void WebServer::setContentLength(const size_t contentLength)
489 | {
490 | _contentLength = contentLength;
491 | }
492 |
493 | void WebServer::enableDelay(boolean value)
494 | {
495 | _nullDelay = value;
496 | }
497 |
498 | void WebServer::enableCORS(boolean value)
499 | {
500 | _corsEnabled = value;
501 | }
502 |
503 | void WebServer::enableCrossOrigin(boolean value)
504 | {
505 | enableCORS(value);
506 | }
507 |
508 | void WebServer::_prepareHeader(String& response, int code, const char* content_type, size_t contentLength)
509 | {
510 | response = String(F("HTTP/1.")) + String(_currentVersion) + ' ';
511 | response += String(code);
512 | response += ' ';
513 | response += _responseCodeToString(code);
514 | response += "\r\n";
515 |
516 | using namespace mime;
517 |
518 | if (!content_type)
519 | content_type = mimeTable[html].mimeType;
520 |
521 | sendHeader(String(F("Content-Type")), String(FPSTR(content_type)), true);
522 |
523 | if (_contentLength == CONTENT_LENGTH_NOT_SET)
524 | {
525 | sendHeader(String(FPSTR(Content_Length)), String(contentLength));
526 | }
527 | else if (_contentLength != CONTENT_LENGTH_UNKNOWN)
528 | {
529 | sendHeader(String(FPSTR(Content_Length)), String(_contentLength));
530 | }
531 | else if (_contentLength == CONTENT_LENGTH_UNKNOWN && _currentVersion) //HTTP/1.1 or above client
532 | {
533 | //let's do chunked
534 | _chunked = true;
535 | sendHeader(String(F("Accept-Ranges")), String(F("none")));
536 | sendHeader(String(F("Transfer-Encoding")), String(F("chunked")));
537 | }
538 |
539 | if (_corsEnabled)
540 | {
541 | sendHeader(String(FPSTR("Access-Control-Allow-Origin")), String("*"));
542 | }
543 |
544 | sendHeader(String(F("Connection")), String(F("close")));
545 |
546 | response += _responseHeaders;
547 | response += "\r\n";
548 | _responseHeaders = "";
549 | }
550 |
551 | void WebServer::send(int code, const char* content_type, const String& content)
552 | {
553 | String header;
554 | // Can we assume the following?
555 | //if(code == 200 && content.length() == 0 && _contentLength == CONTENT_LENGTH_NOT_SET)
556 | // _contentLength = CONTENT_LENGTH_UNKNOWN;
557 | _prepareHeader(header, code, content_type, content.length());
558 | _currentClientWrite(header.c_str(), header.length());
559 |
560 | if (content.length())
561 | sendContent(content);
562 | }
563 |
564 | void WebServer::send_P(int code, PGM_P content_type, PGM_P content)
565 | {
566 | size_t contentLength = 0;
567 |
568 | if (content != NULL)
569 | {
570 | contentLength = strlen_P(content);
571 | }
572 |
573 | String header;
574 | char type[64];
575 | memccpy_P((void*)type, (PGM_VOID_P)content_type, 0, sizeof(type));
576 | _prepareHeader(header, code, (const char* )type, contentLength);
577 | _currentClientWrite(header.c_str(), header.length());
578 | sendContent_P(content);
579 | }
580 |
581 | void WebServer::send_P(int code, PGM_P content_type, PGM_P content, size_t contentLength)
582 | {
583 | String header;
584 | char type[64];
585 | memccpy_P((void*)type, (PGM_VOID_P)content_type, 0, sizeof(type));
586 | _prepareHeader(header, code, (const char* )type, contentLength);
587 | sendContent(header);
588 | sendContent_P(content, contentLength);
589 | }
590 |
591 | void WebServer::send(int code, char* content_type, const String& content)
592 | {
593 | send(code, (const char*)content_type, content);
594 | }
595 |
596 | void WebServer::send(int code, const String& content_type, const String& content)
597 | {
598 | send(code, (const char*)content_type.c_str(), content);
599 | }
600 |
601 | void WebServer::sendContent(const String& content)
602 | {
603 | sendContent(content.c_str(), content.length());
604 | }
605 |
606 | void WebServer::sendContent(const char* content, size_t contentLength)
607 | {
608 | const char * footer = "\r\n";
609 |
610 | if (_chunked)
611 | {
612 | char * chunkSize = (char *)malloc(11);
613 |
614 | if (chunkSize)
615 | {
616 | sprintf(chunkSize, "%x%s", contentLength, footer);
617 | _currentClientWrite(chunkSize, strlen(chunkSize));
618 | free(chunkSize);
619 | }
620 | }
621 |
622 | _currentClientWrite(content, contentLength);
623 |
624 | if (_chunked)
625 | {
626 | _currentClient.write(footer, 2);
627 |
628 | if (contentLength == 0)
629 | {
630 | _chunked = false;
631 | }
632 | }
633 | }
634 |
635 | void WebServer::sendContent_P(PGM_P content)
636 | {
637 | sendContent_P(content, strlen_P(content));
638 | }
639 |
640 | void WebServer::sendContent_P(PGM_P content, size_t size)
641 | {
642 | const char * footer = "\r\n";
643 |
644 | if (_chunked)
645 | {
646 | char * chunkSize = (char *)malloc(11);
647 |
648 | if (chunkSize)
649 | {
650 | sprintf(chunkSize, "%x%s", size, footer);
651 | _currentClientWrite(chunkSize, strlen(chunkSize));
652 | free(chunkSize);
653 | }
654 | }
655 |
656 | _currentClientWrite_P(content, size);
657 |
658 | if (_chunked)
659 | {
660 | _currentClient.write(footer, 2);
661 |
662 | if (size == 0)
663 | {
664 | _chunked = false;
665 | }
666 | }
667 | }
668 |
669 |
670 | void WebServer::_streamFileCore(const size_t fileSize, const String & fileName, const String & contentType)
671 | {
672 | using namespace mime;
673 | setContentLength(fileSize);
674 |
675 | if (fileName.endsWith(String(FPSTR(mimeTable[gz].endsWith))) &&
676 | contentType != String(FPSTR(mimeTable[gz].mimeType)) &&
677 | contentType != String(FPSTR(mimeTable[none].mimeType)))
678 | {
679 | sendHeader(F("Content-Encoding"), F("gzip"));
680 | }
681 |
682 | send(200, contentType, "");
683 | }
684 |
685 | String WebServer::pathArg(unsigned int i)
686 | {
687 | if (_currentHandler != nullptr)
688 | return _currentHandler->pathArg(i);
689 |
690 | return "";
691 | }
692 |
693 | String WebServer::arg(String name)
694 | {
695 | for (int j = 0; j < _postArgsLen; ++j)
696 | {
697 | if ( _postArgs[j].key == name )
698 | return _postArgs[j].value;
699 | }
700 |
701 | for (int i = 0; i < _currentArgCount; ++i)
702 | {
703 | if ( _currentArgs[i].key == name )
704 | return _currentArgs[i].value;
705 | }
706 |
707 | return "";
708 | }
709 |
710 | String WebServer::arg(int i)
711 | {
712 | if (i < _currentArgCount)
713 | return _currentArgs[i].value;
714 |
715 | return "";
716 | }
717 |
718 | String WebServer::argName(int i)
719 | {
720 | if (i < _currentArgCount)
721 | return _currentArgs[i].key;
722 |
723 | return "";
724 | }
725 |
726 | int WebServer::args()
727 | {
728 | return _currentArgCount;
729 | }
730 |
731 | bool WebServer::hasArg(String name)
732 | {
733 | for (int j = 0; j < _postArgsLen; ++j)
734 | {
735 | if (_postArgs[j].key == name)
736 | return true;
737 | }
738 |
739 | for (int i = 0; i < _currentArgCount; ++i)
740 | {
741 | if (_currentArgs[i].key == name)
742 | return true;
743 | }
744 |
745 | return false;
746 | }
747 |
748 |
749 | String WebServer::header(String name)
750 | {
751 | for (int i = 0; i < _headerKeysCount; ++i)
752 | {
753 | if (_currentHeaders[i].key.equalsIgnoreCase(name))
754 | return _currentHeaders[i].value;
755 | }
756 |
757 | return "";
758 | }
759 |
760 | void WebServer::collectHeaders(const char* headerKeys[], const size_t headerKeysCount)
761 | {
762 | _headerKeysCount = headerKeysCount + 1;
763 |
764 | if (_currentHeaders)
765 | delete[]_currentHeaders;
766 |
767 | _currentHeaders = new RequestArgument[_headerKeysCount];
768 | _currentHeaders[0].key = FPSTR(AUTHORIZATION_HEADER);
769 |
770 | for (int i = 1; i < _headerKeysCount; i++)
771 | {
772 | _currentHeaders[i].key = headerKeys[i - 1];
773 | }
774 | }
775 |
776 | String WebServer::header(int i)
777 | {
778 | if (i < _headerKeysCount)
779 | return _currentHeaders[i].value;
780 |
781 | return "";
782 | }
783 |
784 | String WebServer::headerName(int i)
785 | {
786 | if (i < _headerKeysCount)
787 | return _currentHeaders[i].key;
788 |
789 | return "";
790 | }
791 |
792 | int WebServer::headers()
793 | {
794 | return _headerKeysCount;
795 | }
796 |
797 | bool WebServer::hasHeader(String name)
798 | {
799 | for (int i = 0; i < _headerKeysCount; ++i)
800 | {
801 | if ((_currentHeaders[i].key.equalsIgnoreCase(name)) && (_currentHeaders[i].value.length() > 0))
802 | return true;
803 | }
804 |
805 | return false;
806 | }
807 |
808 | String WebServer::hostHeader()
809 | {
810 | return _hostHeader;
811 | }
812 |
813 | void WebServer::onFileUpload(THandlerFunction fn)
814 | {
815 | _fileUploadHandler = fn;
816 | }
817 |
818 | void WebServer::onNotFound(THandlerFunction fn)
819 | {
820 | _notFoundHandler = fn;
821 | }
822 |
823 | void WebServer::_handleRequest()
824 | {
825 | bool handled = false;
826 |
827 | if (!_currentHandler)
828 | {
829 | log_e("request handler not found");
830 | }
831 | else
832 | {
833 | handled = _currentHandler->handle(*this, _currentMethod, _currentUri);
834 |
835 | if (!handled)
836 | {
837 | log_e("request handler failed to handle request");
838 | }
839 | }
840 |
841 | if (!handled && _notFoundHandler)
842 | {
843 | _notFoundHandler();
844 | handled = true;
845 | }
846 |
847 | if (!handled)
848 | {
849 | using namespace mime;
850 | send(404, String(FPSTR(mimeTable[html].mimeType)), String(F("Not found: ")) + _currentUri);
851 | handled = true;
852 | }
853 |
854 | if (handled)
855 | {
856 | _finalizeResponse();
857 | }
858 |
859 | _currentUri = "";
860 | }
861 |
862 |
863 | void WebServer::_finalizeResponse()
864 | {
865 | if (_chunked)
866 | {
867 | sendContent("");
868 | }
869 | }
870 |
871 | String WebServer::_responseCodeToString(int code)
872 | {
873 | switch (code)
874 | {
875 | case 100:
876 | return F("Continue");
877 |
878 | case 101:
879 | return F("Switching Protocols");
880 |
881 | case 200:
882 | return F("OK");
883 |
884 | case 201:
885 | return F("Created");
886 |
887 | case 202:
888 | return F("Accepted");
889 |
890 | case 203:
891 | return F("Non-Authoritative Information");
892 |
893 | case 204:
894 | return F("No Content");
895 |
896 | case 205:
897 | return F("Reset Content");
898 |
899 | case 206:
900 | return F("Partial Content");
901 |
902 | case 300:
903 | return F("Multiple Choices");
904 |
905 | case 301:
906 | return F("Moved Permanently");
907 |
908 | case 302:
909 | return F("Found");
910 |
911 | case 303:
912 | return F("See Other");
913 |
914 | case 304:
915 | return F("Not Modified");
916 |
917 | case 305:
918 | return F("Use Proxy");
919 |
920 | case 307:
921 | return F("Temporary Redirect");
922 |
923 | case 400:
924 | return F("Bad Request");
925 |
926 | case 401:
927 | return F("Unauthorized");
928 |
929 | case 402:
930 | return F("Payment Required");
931 |
932 | case 403:
933 | return F("Forbidden");
934 |
935 | case 404:
936 | return F("Not Found");
937 |
938 | case 405:
939 | return F("Method Not Allowed");
940 |
941 | case 406:
942 | return F("Not Acceptable");
943 |
944 | case 407:
945 | return F("Proxy Authentication Required");
946 |
947 | case 408:
948 | return F("Request Time-out");
949 |
950 | case 409:
951 | return F("Conflict");
952 |
953 | case 410:
954 | return F("Gone");
955 |
956 | case 411:
957 | return F("Length Required");
958 |
959 | case 412:
960 | return F("Precondition Failed");
961 |
962 | case 413:
963 | return F("Request Entity Too Large");
964 |
965 | case 414:
966 | return F("Request-URI Too Large");
967 |
968 | case 415:
969 | return F("Unsupported Media Type");
970 |
971 | case 416:
972 | return F("Requested range not satisfiable");
973 |
974 | case 417:
975 | return F("Expectation Failed");
976 |
977 | case 500:
978 | return F("Internal Server Error");
979 |
980 | case 501:
981 | return F("Not Implemented");
982 |
983 | case 502:
984 | return F("Bad Gateway");
985 |
986 | case 503:
987 | return F("Service Unavailable");
988 |
989 | case 504:
990 | return F("Gateway Time-out");
991 |
992 | case 505:
993 | return F("HTTP Version not supported");
994 |
995 | default:
996 | return F("");
997 | }
998 | }
999 |
--------------------------------------------------------------------------------
/esp32s2_WebServer_Patch/WebServer.h:
--------------------------------------------------------------------------------
1 | /*
2 | WebServer.h - Dead simple web-server.
3 | Supports only one simultaneous client, knows how to handle GET and POST.
4 |
5 | Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
6 |
7 | This library is free software; you can redistribute it and/or
8 | modify it under the terms of the GNU Lesser General Public
9 | License as published by the Free Software Foundation; either
10 | version 2.1 of the License, or (at your option) any later version.
11 |
12 | This library is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 | Lesser General Public License for more details.
16 |
17 | You should have received a copy of the GNU Lesser General Public
18 | License along with this library; if not, write to the Free Software
19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 | Modified 8 May 2015 by Hristo Gochkov (proper post and file upload handling)
21 | */
22 |
23 |
24 | #ifndef WEBSERVER_H
25 | #define WEBSERVER_H
26 |
27 | #include
28 | #include
29 | #include
30 | #include "HTTP_Method.h"
31 | #include "Uri.h"
32 |
33 | enum HTTPUploadStatus { UPLOAD_FILE_START, UPLOAD_FILE_WRITE, UPLOAD_FILE_END,
34 | UPLOAD_FILE_ABORTED
35 | };
36 | enum HTTPClientStatus { HC_NONE, HC_WAIT_READ, HC_WAIT_CLOSE };
37 | enum HTTPAuthMethod { BASIC_AUTH, DIGEST_AUTH };
38 |
39 | #define HTTP_DOWNLOAD_UNIT_SIZE 1436
40 |
41 | #ifndef HTTP_UPLOAD_BUFLEN
42 | #define HTTP_UPLOAD_BUFLEN 1436
43 | #endif
44 |
45 | #define HTTP_MAX_DATA_WAIT 5000 //ms to wait for the client to send the request
46 | #define HTTP_MAX_POST_WAIT 5000 //ms to wait for POST data to arrive
47 | #define HTTP_MAX_SEND_WAIT 5000 //ms to wait for data chunk to be ACKed
48 | #define HTTP_MAX_CLOSE_WAIT 2000 //ms to wait for the client to close the connection
49 |
50 | #define CONTENT_LENGTH_UNKNOWN ((size_t) -1)
51 | #define CONTENT_LENGTH_NOT_SET ((size_t) -2)
52 |
53 | class WebServer;
54 |
55 | typedef struct
56 | {
57 | HTTPUploadStatus status;
58 | String filename;
59 | String name;
60 | String type;
61 | size_t totalSize; // file size
62 | size_t currentSize; // size of data currently in buf
63 | uint8_t buf[HTTP_UPLOAD_BUFLEN];
64 | } HTTPUpload;
65 |
66 | #include "detail/RequestHandler.h"
67 |
68 | namespace fs
69 | {
70 | class FS;
71 | }
72 |
73 | class WebServer
74 | {
75 | public:
76 | WebServer(IPAddress addr, int port = 80);
77 | WebServer(int port = 80);
78 | virtual ~WebServer();
79 |
80 | virtual void begin();
81 | virtual void begin(uint16_t port);
82 | virtual void handleClient();
83 |
84 | virtual void close();
85 | void stop();
86 |
87 | bool authenticate(const char * username, const char * password);
88 | void requestAuthentication(HTTPAuthMethod mode = BASIC_AUTH, const char* realm = NULL,
89 | const String& authFailMsg = String("") );
90 |
91 | typedef std::function THandlerFunction;
92 | void on(const Uri &uri, THandlerFunction handler);
93 | void on(const Uri &uri, HTTPMethod method, THandlerFunction fn);
94 | void on(const Uri &uri, HTTPMethod method, THandlerFunction fn, THandlerFunction ufn);
95 | void addHandler(RequestHandler* handler);
96 | void serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_header = NULL );
97 | void onNotFound(THandlerFunction fn); //called when handler is not assigned
98 | void onFileUpload(THandlerFunction fn); //handle file uploads
99 |
100 | String uri()
101 | {
102 | return _currentUri;
103 | }
104 | HTTPMethod method()
105 | {
106 | return _currentMethod;
107 | }
108 | virtual WiFiClient client()
109 | {
110 | return _currentClient;
111 | }
112 | HTTPUpload& upload()
113 | {
114 | return *_currentUpload;
115 | }
116 |
117 | String pathArg(unsigned int i); // get request path argument by number
118 | String arg(String name); // get request argument value by name
119 | String arg(int i); // get request argument value by number
120 | String argName(int i); // get request argument name by number
121 | int args(); // get arguments count
122 | bool hasArg(String name); // check if argument exists
123 | void collectHeaders(const char* headerKeys[], const size_t headerKeysCount); // set the request headers to collect
124 | String header(String name); // get request header value by name
125 | String header(int i); // get request header value by number
126 | String headerName(int i); // get request header name by number
127 | int headers(); // get header count
128 | bool hasHeader(String name); // check if header exists
129 |
130 | String hostHeader(); // get request host header if available or empty String if not
131 |
132 | // send response to the client
133 | // code - HTTP response code, can be 200 or 404
134 | // content_type - HTTP content type, like "text/plain" or "image/png"
135 | // content - actual content body
136 | void send(int code, const char* content_type = NULL, const String& content = String(""));
137 | void send(int code, char* content_type, const String& content);
138 | void send(int code, const String& content_type, const String& content);
139 | void send_P(int code, PGM_P content_type, PGM_P content);
140 | void send_P(int code, PGM_P content_type, PGM_P content, size_t contentLength);
141 |
142 | void enableDelay(boolean value);
143 | void enableCORS(boolean value = true);
144 | void enableCrossOrigin(boolean value = true);
145 |
146 | void setContentLength(const size_t contentLength);
147 | void sendHeader(const String& name, const String& value, bool first = false);
148 | void sendContent(const String& content);
149 | void sendContent(const char* content, size_t contentLength);
150 | void sendContent_P(PGM_P content);
151 | void sendContent_P(PGM_P content, size_t size);
152 |
153 | static String urlDecode(const String& text);
154 |
155 | template
156 | size_t streamFile(T &file, const String& contentType)
157 | {
158 | _streamFileCore(file.size(), file.name(), contentType);
159 | return _currentClient.write(file);
160 | }
161 |
162 | protected:
163 | virtual size_t _currentClientWrite(const char* b, size_t l)
164 | {
165 | return _currentClient.write( b, l );
166 | }
167 | virtual size_t _currentClientWrite_P(PGM_P b, size_t l)
168 | {
169 | return _currentClient.write_P( b, l );
170 | }
171 | void _addRequestHandler(RequestHandler* handler);
172 | void _handleRequest();
173 | void _finalizeResponse();
174 | bool _parseRequest(WiFiClient& client);
175 | void _parseArguments(String data);
176 | static String _responseCodeToString(int code);
177 | bool _parseForm(WiFiClient& client, String boundary, uint32_t len);
178 | bool _parseFormUploadAborted();
179 | void _uploadWriteByte(uint8_t b);
180 | int _uploadReadByte(WiFiClient& client);
181 | void _prepareHeader(String& response, int code, const char* content_type, size_t contentLength);
182 | bool _collectHeader(const char* headerName, const char* headerValue);
183 |
184 | void _streamFileCore(const size_t fileSize, const String & fileName, const String & contentType);
185 |
186 | String _getRandomHexString();
187 | // for extracting Auth parameters
188 | String _extractParam(String& authReq, const String& param, const char delimit = '"');
189 |
190 | struct RequestArgument
191 | {
192 | String key;
193 | String value;
194 | };
195 |
196 | boolean _corsEnabled;
197 | WiFiServer _server;
198 |
199 | WiFiClient _currentClient;
200 | HTTPMethod _currentMethod;
201 | String _currentUri;
202 | uint8_t _currentVersion;
203 | HTTPClientStatus _currentStatus;
204 | unsigned long _statusChange;
205 | bool _nullDelay;
206 |
207 | RequestHandler* _currentHandler;
208 | RequestHandler* _firstHandler;
209 | RequestHandler* _lastHandler;
210 | THandlerFunction _notFoundHandler;
211 | THandlerFunction _fileUploadHandler;
212 |
213 | int _currentArgCount;
214 | RequestArgument* _currentArgs;
215 | int _postArgsLen;
216 | RequestArgument* _postArgs;
217 |
218 | std::unique_ptr _currentUpload;
219 |
220 | int _headerKeysCount;
221 | RequestArgument* _currentHeaders;
222 | size_t _contentLength;
223 | String _responseHeaders;
224 |
225 | String _hostHeader;
226 | bool _chunked;
227 |
228 | String _snonce; // Store noance and opaque for future comparison
229 | String _sopaque;
230 | String _srealm; // Store the Auth realm between Calls
231 |
232 | };
233 |
234 |
235 | #endif //ESP8266WEBSERVER_H
236 |
--------------------------------------------------------------------------------
/examples/Async_AutoConnect/Async_AutoConnect.ino:
--------------------------------------------------------------------------------
1 | /****************************************************************************************************************************
2 | Async_AutoConnect.ino
3 | For ESP8266 / ESP32 boards
4 |
5 | ESPAsync_WiFiManager is a library for the ESP8266/Arduino platform, using (ESP)AsyncWebServer to enable easy
6 | configuration and reconfiguration of WiFi credentials using a Captive Portal.
7 |
8 | Modified from
9 | 1. Tzapu (https://github.com/tzapu/WiFiManager)
10 | 2. Ken Taylor (https://github.com/kentaylor)
11 | 3. Alan Steremberg (https://github.com/alanswx/ESPAsyncWiFiManager)
12 | 4. Khoi Hoang (https://github.com/khoih-prog/ESP_WiFiManager)
13 |
14 | Built by Khoi Hoang https://github.com/khoih-prog/ESPAsync_WiFiManager
15 | Licensed under MIT license
16 | *****************************************************************************************************************************/
17 | #if !( defined(ESP8266) || defined(ESP32) )
18 | #error This code is intended to run on the ESP8266 or ESP32 platform! Please check your Tools->Board setting.
19 | #endif
20 |
21 | #define ESP_ASYNC_WIFIMANAGER_VERSION_MIN_TARGET "ESPAsync_WiFiManager v1.15.0"
22 | #define ESP_ASYNC_WIFIMANAGER_VERSION_MIN 1015000
23 |
24 | // Use from 0 to 4. Higher number, more debugging messages and memory usage.
25 | #define _ESPASYNC_WIFIMGR_LOGLEVEL_ 3
26 |
27 | // To not display stored SSIDs and PWDs on Config Portal, select false. Default is true
28 | // Even the stored Credentials are not display, just leave them all blank to reconnect and reuse the stored Credentials
29 | //#define DISPLAY_STORED_CREDENTIALS_IN_CP false
30 |
31 | //Ported to ESP32
32 | #ifdef ESP32
33 | #include
34 | #include
35 | #include
36 |
37 | // From v1.1.1
38 | #include
39 | WiFiMulti wifiMulti;
40 |
41 | // LittleFS has higher priority than SPIFFS
42 | #if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 2) )
43 | #define USE_LITTLEFS true
44 | #define USE_SPIFFS false
45 | #elif defined(ARDUINO_ESP32C3_DEV)
46 | // For core v1.0.6-, ESP32-C3 only supporting SPIFFS and EEPROM. To use v2.0.0+ for LittleFS
47 | #define USE_LITTLEFS false
48 | #define USE_SPIFFS true
49 | #endif
50 |
51 | #if USE_LITTLEFS
52 | // Use LittleFS
53 | #include "FS.h"
54 |
55 | // Check cores/esp32/esp_arduino_version.h and cores/esp32/core_version.h
56 | //#if ( ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(2, 0, 0) ) //(ESP_ARDUINO_VERSION_MAJOR >= 2)
57 | #if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 2) )
58 | #if (_ESPASYNC_WIFIMGR_LOGLEVEL_ > 3)
59 | #warning Using ESP32 Core 1.0.6 or 2.0.0+
60 | #endif
61 |
62 | // The library has been merged into esp32 core from release 1.0.6
63 | #include // https://github.com/espressif/arduino-esp32/tree/master/libraries/LittleFS
64 |
65 | FS* filesystem = &LittleFS;
66 | #define FileFS LittleFS
67 | #define FS_Name "LittleFS"
68 | #else
69 | #if (_ESPASYNC_WIFIMGR_LOGLEVEL_ > 3)
70 | #warning Using ESP32 Core 1.0.5-. You must install LITTLEFS library
71 | #endif
72 |
73 | // The library has been merged into esp32 core from release 1.0.6
74 | #include // https://github.com/lorol/LITTLEFS
75 |
76 | FS* filesystem = &LITTLEFS;
77 | #define FileFS LITTLEFS
78 | #define FS_Name "LittleFS"
79 | #endif
80 |
81 | #elif USE_SPIFFS
82 | #include
83 | FS* filesystem = &SPIFFS;
84 | #define FileFS SPIFFS
85 | #define FS_Name "SPIFFS"
86 | #else
87 | // +Use FFat
88 | #include
89 | FS* filesystem = &FFat;
90 | #define FileFS FFat
91 | #define FS_Name "FFat"
92 | #endif
93 | //////
94 |
95 | #define LED_BUILTIN 2
96 | #define LED_ON HIGH
97 | #define LED_OFF LOW
98 |
99 | #else
100 |
101 | #include //https://github.com/esp8266/Arduino
102 | //needed for library
103 | #include
104 |
105 | // From v1.1.1
106 | #include
107 | ESP8266WiFiMulti wifiMulti;
108 |
109 | #define USE_LITTLEFS true
110 |
111 | #if USE_LITTLEFS
112 | #include
113 | FS* filesystem = &LittleFS;
114 | #define FileFS LittleFS
115 | #define FS_Name "LittleFS"
116 | #else
117 | FS* filesystem = &SPIFFS;
118 | #define FileFS SPIFFS
119 | #define FS_Name "SPIFFS"
120 | #endif
121 | //////
122 |
123 | #define ESP_getChipId() (ESP.getChipId())
124 |
125 | #define LED_ON LOW
126 | #define LED_OFF HIGH
127 | #endif
128 |
129 | // SSID and PW for your Router
130 | String Router_SSID;
131 | String Router_Pass;
132 |
133 | // From v1.1.1
134 | // You only need to format the filesystem once
135 | //#define FORMAT_FILESYSTEM true
136 | #define FORMAT_FILESYSTEM false
137 |
138 | #define MIN_AP_PASSWORD_SIZE 8
139 |
140 | #define SSID_MAX_LEN 32
141 | //From v1.0.10, WPA2 passwords can be up to 63 characters long.
142 | #define PASS_MAX_LEN 64
143 |
144 | typedef struct
145 | {
146 | char wifi_ssid[SSID_MAX_LEN];
147 | char wifi_pw [PASS_MAX_LEN];
148 | } WiFi_Credentials;
149 |
150 | typedef struct
151 | {
152 | String wifi_ssid;
153 | String wifi_pw;
154 | } WiFi_Credentials_String;
155 |
156 | #define NUM_WIFI_CREDENTIALS 2
157 |
158 | // Assuming max 49 chars
159 | #define TZNAME_MAX_LEN 50
160 | #define TIMEZONE_MAX_LEN 50
161 |
162 | typedef struct
163 | {
164 | WiFi_Credentials WiFi_Creds [NUM_WIFI_CREDENTIALS];
165 | char TZ_Name[TZNAME_MAX_LEN]; // "America/Toronto"
166 | char TZ[TIMEZONE_MAX_LEN]; // "EST5EDT,M3.2.0,M11.1.0"
167 | uint16_t checksum;
168 | } WM_Config;
169 |
170 | WM_Config WM_config;
171 |
172 | #define CONFIG_FILENAME F("/wifi_cred.dat")
173 | //////
174 |
175 | // Indicates whether ESP has WiFi credentials saved from previous session, or double reset detected
176 | bool initialConfig = false;
177 |
178 | // Use false if you don't like to display Available Pages in Information Page of Config Portal
179 | // Comment out or use true to display Available Pages in Information Page of Config Portal
180 | // Must be placed before #include
181 | #define USE_AVAILABLE_PAGES true
182 |
183 | // From v1.0.10 to permit disable/enable StaticIP configuration in Config Portal from sketch. Valid only if DHCP is used.
184 | // You'll loose the feature of dynamically changing from DHCP to static IP, or vice versa
185 | // You have to explicitly specify false to disable the feature.
186 | //#define USE_STATIC_IP_CONFIG_IN_CP false
187 |
188 | // Use false to disable NTP config. Advisable when using Cellphone, Tablet to access Config Portal.
189 | // See Issue 23: On Android phone ConfigPortal is unresponsive (https://github.com/khoih-prog/ESP_WiFiManager/issues/23)
190 | #define USE_ESP_WIFIMANAGER_NTP true
191 |
192 | // Just use enough to save memory. On ESP8266, can cause blank ConfigPortal screen
193 | // if using too much memory
194 | #define USING_AFRICA false
195 | #define USING_AMERICA true
196 | #define USING_ANTARCTICA false
197 | #define USING_ASIA false
198 | #define USING_ATLANTIC false
199 | #define USING_AUSTRALIA false
200 | #define USING_EUROPE false
201 | #define USING_INDIAN false
202 | #define USING_PACIFIC false
203 | #define USING_ETC_GMT false
204 |
205 | // Use true to enable CloudFlare NTP service. System can hang if you don't have Internet access while accessing CloudFlare
206 | // See Issue #21: CloudFlare link in the default portal (https://github.com/khoih-prog/ESP_WiFiManager/issues/21)
207 | #define USE_CLOUDFLARE_NTP false
208 |
209 | // New in v1.0.11
210 | #define USING_CORS_FEATURE true
211 |
212 | ////////////////////////////////////////////
213 |
214 | // Use USE_DHCP_IP == true for dynamic DHCP IP, false to use static IP which you have to change accordingly to your network
215 | #if (defined(USE_STATIC_IP_CONFIG_IN_CP) && !USE_STATIC_IP_CONFIG_IN_CP)
216 | // Force DHCP to be true
217 | #if defined(USE_DHCP_IP)
218 | #undef USE_DHCP_IP
219 | #endif
220 | #define USE_DHCP_IP true
221 | #else
222 | // You can select DHCP or Static IP here
223 | #define USE_DHCP_IP true
224 | //#define USE_DHCP_IP false
225 | #endif
226 |
227 | #if ( USE_DHCP_IP )
228 | // Use DHCP
229 |
230 | #if (_ESPASYNC_WIFIMGR_LOGLEVEL_ > 3)
231 | #warning Using DHCP IP
232 | #endif
233 |
234 | IPAddress stationIP = IPAddress(0, 0, 0, 0);
235 | IPAddress gatewayIP = IPAddress(192, 168, 2, 1);
236 | IPAddress netMask = IPAddress(255, 255, 255, 0);
237 |
238 | #else
239 | // Use static IP
240 |
241 | #if (_ESPASYNC_WIFIMGR_LOGLEVEL_ > 3)
242 | #warning Using static IP
243 | #endif
244 |
245 | #ifdef ESP32
246 | IPAddress stationIP = IPAddress(192, 168, 2, 232);
247 | #else
248 | IPAddress stationIP = IPAddress(192, 168, 2, 186);
249 | #endif
250 |
251 | IPAddress gatewayIP = IPAddress(192, 168, 2, 1);
252 | IPAddress netMask = IPAddress(255, 255, 255, 0);
253 | #endif
254 |
255 | ////////////////////////////////////////////
256 |
257 |
258 | #define USE_CONFIGURABLE_DNS true
259 |
260 | IPAddress dns1IP = gatewayIP;
261 | IPAddress dns2IP = IPAddress(8, 8, 8, 8);
262 |
263 | #define USE_CUSTOM_AP_IP false
264 |
265 | IPAddress APStaticIP = IPAddress(192, 168, 100, 1);
266 | IPAddress APStaticGW = IPAddress(192, 168, 100, 1);
267 | IPAddress APStaticSN = IPAddress(255, 255, 255, 0);
268 |
269 | #include //https://github.com/khoih-prog/ESPAsync_WiFiManager
270 |
271 | // Redundant, for v1.10.0 only
272 | //#include //https://github.com/khoih-prog/ESPAsync_WiFiManager
273 |
274 | #define HTTP_PORT 80
275 |
276 | ///////////////////////////////////////////
277 | // New in v1.4.0
278 | /******************************************
279 | // Defined in ESPAsync_WiFiManager.h
280 | typedef struct
281 | {
282 | IPAddress _ap_static_ip;
283 | IPAddress _ap_static_gw;
284 | IPAddress _ap_static_sn;
285 |
286 | } WiFi_AP_IPConfig;
287 |
288 | typedef struct
289 | {
290 | IPAddress _sta_static_ip;
291 | IPAddress _sta_static_gw;
292 | IPAddress _sta_static_sn;
293 | #if USE_CONFIGURABLE_DNS
294 | IPAddress _sta_static_dns1;
295 | IPAddress _sta_static_dns2;
296 | #endif
297 | } WiFi_STA_IPConfig;
298 | ******************************************/
299 |
300 | WiFi_AP_IPConfig WM_AP_IPconfig;
301 | WiFi_STA_IPConfig WM_STA_IPconfig;
302 |
303 | void initAPIPConfigStruct(WiFi_AP_IPConfig &in_WM_AP_IPconfig)
304 | {
305 | in_WM_AP_IPconfig._ap_static_ip = APStaticIP;
306 | in_WM_AP_IPconfig._ap_static_gw = APStaticGW;
307 | in_WM_AP_IPconfig._ap_static_sn = APStaticSN;
308 | }
309 |
310 | void initSTAIPConfigStruct(WiFi_STA_IPConfig &in_WM_STA_IPconfig)
311 | {
312 | in_WM_STA_IPconfig._sta_static_ip = stationIP;
313 | in_WM_STA_IPconfig._sta_static_gw = gatewayIP;
314 | in_WM_STA_IPconfig._sta_static_sn = netMask;
315 | #if USE_CONFIGURABLE_DNS
316 | in_WM_STA_IPconfig._sta_static_dns1 = dns1IP;
317 | in_WM_STA_IPconfig._sta_static_dns2 = dns2IP;
318 | #endif
319 | }
320 |
321 | void displayIPConfigStruct(WiFi_STA_IPConfig in_WM_STA_IPconfig)
322 | {
323 | LOGERROR3(F("stationIP ="), in_WM_STA_IPconfig._sta_static_ip, ", gatewayIP =", in_WM_STA_IPconfig._sta_static_gw);
324 | LOGERROR1(F("netMask ="), in_WM_STA_IPconfig._sta_static_sn);
325 | #if USE_CONFIGURABLE_DNS
326 | LOGERROR3(F("dns1IP ="), in_WM_STA_IPconfig._sta_static_dns1, ", dns2IP =", in_WM_STA_IPconfig._sta_static_dns2);
327 | #endif
328 | }
329 |
330 | void configWiFi(WiFi_STA_IPConfig in_WM_STA_IPconfig)
331 | {
332 | #if USE_CONFIGURABLE_DNS
333 | // Set static IP, Gateway, Subnetmask, DNS1 and DNS2. New in v1.0.5
334 | WiFi.config(in_WM_STA_IPconfig._sta_static_ip, in_WM_STA_IPconfig._sta_static_gw, in_WM_STA_IPconfig._sta_static_sn,
335 | in_WM_STA_IPconfig._sta_static_dns1, in_WM_STA_IPconfig._sta_static_dns2);
336 | #else
337 | // Set static IP, Gateway, Subnetmask, Use auto DNS1 and DNS2.
338 | WiFi.config(in_WM_STA_IPconfig._sta_static_ip, in_WM_STA_IPconfig._sta_static_gw, in_WM_STA_IPconfig._sta_static_sn);
339 | #endif
340 | }
341 |
342 | ///////////////////////////////////////////
343 |
344 | uint8_t connectMultiWiFi()
345 | {
346 | #if ESP32
347 | // For ESP32, this better be 0 to shorten the connect time.
348 | // For ESP32-S2/C3, must be > 500
349 | #if ( USING_ESP32_S2 || USING_ESP32_C3 )
350 | #define WIFI_MULTI_1ST_CONNECT_WAITING_MS 500L
351 | #else
352 | // For ESP32 core v1.0.6, must be >= 500
353 | #define WIFI_MULTI_1ST_CONNECT_WAITING_MS 800L
354 | #endif
355 | #else
356 | // For ESP8266, this better be 2200 to enable connect the 1st time
357 | #define WIFI_MULTI_1ST_CONNECT_WAITING_MS 2200L
358 | #endif
359 |
360 | #define WIFI_MULTI_CONNECT_WAITING_MS 500L
361 |
362 | uint8_t status;
363 |
364 | //WiFi.mode(WIFI_STA);
365 |
366 | LOGERROR(F("ConnectMultiWiFi with :"));
367 |
368 | if ( (Router_SSID != "") && (Router_Pass != "") )
369 | {
370 | LOGERROR3(F("* Flash-stored Router_SSID = "), Router_SSID, F(", Router_Pass = "), Router_Pass );
371 | LOGERROR3(F("* Add SSID = "), Router_SSID, F(", PW = "), Router_Pass );
372 | wifiMulti.addAP(Router_SSID.c_str(), Router_Pass.c_str());
373 | }
374 |
375 | for (uint8_t i = 0; i < NUM_WIFI_CREDENTIALS; i++)
376 | {
377 | // Don't permit NULL SSID and password len < MIN_AP_PASSWORD_SIZE (8)
378 | if ( (String(WM_config.WiFi_Creds[i].wifi_ssid) != "")
379 | && (strlen(WM_config.WiFi_Creds[i].wifi_pw) >= MIN_AP_PASSWORD_SIZE) )
380 | {
381 | LOGERROR3(F("* Additional SSID = "), WM_config.WiFi_Creds[i].wifi_ssid, F(", PW = "), WM_config.WiFi_Creds[i].wifi_pw );
382 | }
383 | }
384 |
385 | LOGERROR(F("Connecting MultiWifi..."));
386 |
387 | //WiFi.mode(WIFI_STA);
388 |
389 | #if !USE_DHCP_IP
390 | // New in v1.4.0
391 | configWiFi(WM_STA_IPconfig);
392 | //////
393 | #endif
394 |
395 | int i = 0;
396 | status = wifiMulti.run();
397 | delay(WIFI_MULTI_1ST_CONNECT_WAITING_MS);
398 |
399 | while ( ( i++ < 20 ) && ( status != WL_CONNECTED ) )
400 | {
401 | status = WiFi.status();
402 |
403 | if ( status == WL_CONNECTED )
404 | break;
405 | else
406 | delay(WIFI_MULTI_CONNECT_WAITING_MS);
407 | }
408 |
409 | if ( status == WL_CONNECTED )
410 | {
411 | LOGERROR1(F("WiFi connected after time: "), i);
412 | LOGERROR3(F("SSID:"), WiFi.SSID(), F(",RSSI="), WiFi.RSSI());
413 | LOGERROR3(F("Channel:"), WiFi.channel(), F(",IP address:"), WiFi.localIP() );
414 | }
415 | else
416 | {
417 | LOGERROR(F("WiFi not connected"));
418 |
419 | #if ESP8266
420 | ESP.reset();
421 | #else
422 | ESP.restart();
423 | #endif
424 | }
425 |
426 | return status;
427 | }
428 |
429 | #if USE_ESP_WIFIMANAGER_NTP
430 |
431 | void printLocalTime()
432 | {
433 | #if ESP8266
434 | static time_t now;
435 |
436 | now = time(nullptr);
437 |
438 | if ( now > 1451602800 )
439 | {
440 | Serial.print("Local Date/Time: ");
441 | Serial.print(ctime(&now));
442 | }
443 |
444 | #else
445 | struct tm timeinfo;
446 |
447 | getLocalTime( &timeinfo );
448 |
449 | // Valid only if year > 2000.
450 | // You can get from timeinfo : tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec
451 | if (timeinfo.tm_year > 100 )
452 | {
453 | Serial.print("Local Date/Time: ");
454 | Serial.print( asctime( &timeinfo ) );
455 | }
456 |
457 | #endif
458 | }
459 |
460 | #endif
461 |
462 | void heartBeatPrint()
463 | {
464 | #if USE_ESP_WIFIMANAGER_NTP
465 | printLocalTime();
466 | #else
467 | static int num = 1;
468 |
469 | if (WiFi.status() == WL_CONNECTED)
470 | Serial.print(F("H")); // H means connected to WiFi
471 | else
472 | Serial.print(F("F")); // F means not connected to WiFi
473 |
474 | if (num == 80)
475 | {
476 | Serial.println();
477 | num = 1;
478 | }
479 | else if (num++ % 10 == 0)
480 | {
481 | Serial.print(F(" "));
482 | }
483 |
484 | #endif
485 | }
486 |
487 | void check_WiFi()
488 | {
489 | if ( (WiFi.status() != WL_CONNECTED) )
490 | {
491 | Serial.println(F("\nWiFi lost. Call connectMultiWiFi in loop"));
492 | connectMultiWiFi();
493 | }
494 | }
495 |
496 | void check_status()
497 | {
498 | static ulong checkstatus_timeout = 0;
499 | static ulong checkwifi_timeout = 0;
500 |
501 | static ulong current_millis;
502 |
503 | #define WIFICHECK_INTERVAL 1000L
504 |
505 | #if USE_ESP_WIFIMANAGER_NTP
506 | #define HEARTBEAT_INTERVAL 60000L
507 | #else
508 | #define HEARTBEAT_INTERVAL 10000L
509 | #endif
510 |
511 | current_millis = millis();
512 |
513 | // Check WiFi every WIFICHECK_INTERVAL (1) seconds.
514 | if ((current_millis > checkwifi_timeout) || (checkwifi_timeout == 0))
515 | {
516 | check_WiFi();
517 | checkwifi_timeout = current_millis + WIFICHECK_INTERVAL;
518 | }
519 |
520 | // Print hearbeat every HEARTBEAT_INTERVAL (10) seconds.
521 | if ((current_millis > checkstatus_timeout) || (checkstatus_timeout == 0))
522 | {
523 | heartBeatPrint();
524 | checkstatus_timeout = current_millis + HEARTBEAT_INTERVAL;
525 | }
526 | }
527 |
528 | int calcChecksum(uint8_t* address, uint16_t sizeToCalc)
529 | {
530 | uint16_t checkSum = 0;
531 |
532 | for (uint16_t index = 0; index < sizeToCalc; index++)
533 | {
534 | checkSum += * ( ( (byte*) address ) + index);
535 | }
536 |
537 | return checkSum;
538 | }
539 |
540 | bool loadConfigData()
541 | {
542 | File file = FileFS.open(CONFIG_FILENAME, "r");
543 | LOGERROR(F("LoadWiFiCfgFile "));
544 |
545 | memset((void *) &WM_config, 0, sizeof(WM_config));
546 |
547 | // New in v1.4.0
548 | memset((void *) &WM_STA_IPconfig, 0, sizeof(WM_STA_IPconfig));
549 | //////
550 |
551 | if (file)
552 | {
553 | file.readBytes((char *) &WM_config, sizeof(WM_config));
554 |
555 | // New in v1.4.0
556 | file.readBytes((char *) &WM_STA_IPconfig, sizeof(WM_STA_IPconfig));
557 | //////
558 |
559 | file.close();
560 | LOGERROR(F("OK"));
561 |
562 | if ( WM_config.checksum != calcChecksum( (uint8_t*) &WM_config, sizeof(WM_config) - sizeof(WM_config.checksum) ) )
563 | {
564 | LOGERROR(F("WM_config checksum wrong"));
565 |
566 | return false;
567 | }
568 |
569 | // New in v1.4.0
570 | displayIPConfigStruct(WM_STA_IPconfig);
571 | //////
572 |
573 | return true;
574 | }
575 | else
576 | {
577 | LOGERROR(F("failed"));
578 |
579 | return false;
580 | }
581 | }
582 |
583 | void saveConfigData()
584 | {
585 | File file = FileFS.open(CONFIG_FILENAME, "w");
586 | LOGERROR(F("SaveWiFiCfgFile "));
587 |
588 | if (file)
589 | {
590 | WM_config.checksum = calcChecksum( (uint8_t*) &WM_config, sizeof(WM_config) - sizeof(WM_config.checksum) );
591 |
592 | file.write((uint8_t*) &WM_config, sizeof(WM_config));
593 |
594 | displayIPConfigStruct(WM_STA_IPconfig);
595 |
596 | // New in v1.4.0
597 | file.write((uint8_t*) &WM_STA_IPconfig, sizeof(WM_STA_IPconfig));
598 | //////
599 |
600 | file.close();
601 | LOGERROR(F("OK"));
602 | }
603 | else
604 | {
605 | LOGERROR(F("failed"));
606 | }
607 | }
608 |
609 | void setup()
610 | {
611 | // put your setup code here, to run once:
612 | Serial.begin(115200);
613 |
614 | while (!Serial);
615 |
616 | delay(200);
617 |
618 | Serial.print("\nStarting Async_AutoConnectAP using " + String(FS_Name));
619 | Serial.println(" on " + String(ARDUINO_BOARD));
620 | Serial.println(ESP_ASYNC_WIFIMANAGER_VERSION);
621 |
622 | #if defined(ESP_ASYNC_WIFIMANAGER_VERSION_INT)
623 |
624 | if (ESP_ASYNC_WIFIMANAGER_VERSION_INT < ESP_ASYNC_WIFIMANAGER_VERSION_MIN)
625 | {
626 | Serial.print("Warning. Must use this example on Version later than : ");
627 | Serial.println(ESP_ASYNC_WIFIMANAGER_VERSION_MIN_TARGET);
628 | }
629 |
630 | #endif
631 |
632 | if (FORMAT_FILESYSTEM)
633 | FileFS.format();
634 |
635 | // Format FileFS if not yet
636 | #ifdef ESP32
637 |
638 | if (!FileFS.begin(true))
639 | #else
640 | if (!FileFS.begin())
641 | #endif
642 | {
643 | #ifdef ESP8266
644 | FileFS.format();
645 | #endif
646 |
647 | Serial.println(F("SPIFFS/LittleFS failed! Already tried formatting."));
648 |
649 | if (!FileFS.begin())
650 | {
651 | // prevents debug info from the library to hide err message.
652 | delay(100);
653 |
654 | #if USE_LITTLEFS
655 | Serial.println(F("LittleFS failed!. Please use SPIFFS or EEPROM. Stay forever"));
656 | #else
657 | Serial.println(F("SPIFFS failed!. Please use LittleFS or EEPROM. Stay forever"));
658 | #endif
659 |
660 | while (true)
661 | {
662 | delay(1);
663 | }
664 | }
665 | }
666 |
667 | unsigned long startedAt = millis();
668 |
669 | // New in v1.4.0
670 | initAPIPConfigStruct(WM_AP_IPconfig);
671 | initSTAIPConfigStruct(WM_STA_IPconfig);
672 | //////
673 |
674 | //Local intialization. Once its business is done, there is no need to keep it around
675 | // Use this to default DHCP hostname to ESP8266-XXXXXX or ESP32-XXXXXX
676 | //ESPAsync_WiFiManager ESPAsync_wifiManager(&webServer, &dnsServer);
677 | // Use this to personalize DHCP hostname (RFC952 conformed)
678 | AsyncWebServer webServer(HTTP_PORT);
679 |
680 | #if ( USING_ESP32_S2 || USING_ESP32_C3 )
681 | ESPAsync_WiFiManager ESPAsync_wifiManager(&webServer, NULL, "AutoConnectAP");
682 | #else
683 | AsyncDNSServer dnsServer;
684 |
685 | ESPAsync_WiFiManager ESPAsync_wifiManager(&webServer, &dnsServer, "AutoConnectAP");
686 | #endif
687 |
688 | ESPAsync_wifiManager.setDebugOutput(true);
689 |
690 | //reset settings - for testing
691 | //ESPAsync_wifiManager.resetSettings();
692 |
693 | #if USE_CUSTOM_AP_IP
694 | //set custom ip for portal
695 | // New in v1.4.0
696 | ESPAsync_wifiManager.setAPStaticIPConfig(WM_AP_IPconfig);
697 | //////
698 | #endif
699 |
700 | ESPAsync_wifiManager.setMinimumSignalQuality(-1);
701 |
702 | // From v1.0.10 only
703 | // Set config portal channel, default = 1. Use 0 => random channel from 1-13
704 | ESPAsync_wifiManager.setConfigPortalChannel(0);
705 | //////
706 |
707 | #if !USE_DHCP_IP
708 | // Set (static IP, Gateway, Subnetmask, DNS1 and DNS2) or (IP, Gateway, Subnetmask). New in v1.0.5
709 | // New in v1.4.0
710 | ESPAsync_wifiManager.setSTAStaticIPConfig(WM_STA_IPconfig);
711 | //////
712 | #endif
713 |
714 | // New from v1.1.1
715 | #if USING_CORS_FEATURE
716 | ESPAsync_wifiManager.setCORSHeader("Your Access-Control-Allow-Origin");
717 | #endif
718 |
719 | // We can't use WiFi.SSID() in ESP32 as it's only valid after connected.
720 | // SSID and Password stored in ESP32 wifi_ap_record_t and wifi_config_t are also cleared in reboot
721 | // Have to create a new function to store in EEPROM/SPIFFS for this purpose
722 | Router_SSID = ESPAsync_wifiManager.WiFi_SSID();
723 | Router_Pass = ESPAsync_wifiManager.WiFi_Pass();
724 |
725 | //Remove this line if you do not want to see WiFi password printed
726 | Serial.println("ESP Self-Stored: SSID = " + Router_SSID + ", Pass = " + Router_Pass);
727 |
728 | bool configDataLoaded = false;
729 |
730 | // From v1.1.0, Don't permit NULL password
731 | if ( (Router_SSID != "") && (Router_Pass != "") )
732 | {
733 | LOGERROR3(F("* Add SSID = "), Router_SSID, F(", PW = "), Router_Pass);
734 | wifiMulti.addAP(Router_SSID.c_str(), Router_Pass.c_str());
735 |
736 | ESPAsync_wifiManager.setConfigPortalTimeout(120); //If no access point name has been previously entered disable timeout.
737 | Serial.println(F("Got ESP Self-Stored Credentials. Timeout 120s for Config Portal"));
738 | }
739 |
740 | if (loadConfigData())
741 | {
742 | configDataLoaded = true;
743 |
744 | ESPAsync_wifiManager.setConfigPortalTimeout(120); //If no access point name has been previously entered disable timeout.
745 | Serial.println(F("Got stored Credentials. Timeout 120s for Config Portal"));
746 |
747 | #if USE_ESP_WIFIMANAGER_NTP
748 |
749 | if ( strlen(WM_config.TZ_Name) > 0 )
750 | {
751 | LOGERROR3(F("Current TZ_Name ="), WM_config.TZ_Name, F(", TZ = "), WM_config.TZ);
752 |
753 | #if ESP8266
754 | configTime(WM_config.TZ, "pool.ntp.org");
755 | #else
756 | //configTzTime(WM_config.TZ, "pool.ntp.org" );
757 | configTzTime(WM_config.TZ, "time.nist.gov", "0.pool.ntp.org", "1.pool.ntp.org");
758 | #endif
759 | }
760 | else
761 | {
762 | Serial.println(F("Current Timezone is not set. Enter Config Portal to set."));
763 | }
764 |
765 | #endif
766 | }
767 | else
768 | {
769 | // Enter CP only if no stored SSID on flash and file
770 | Serial.println(F("Open Config Portal without Timeout: No stored Credentials."));
771 | initialConfig = true;
772 | }
773 |
774 | String chipID = String(ESP_getChipId(), HEX);
775 | chipID.toUpperCase();
776 |
777 | // SSID and PW for Config Portal
778 | String AP_SSID = "ESP_" + chipID + "_AutoConnectAP";
779 | String AP_PASS = "MyESP_" + chipID;
780 |
781 | if (initialConfig)
782 | {
783 | Serial.println(F("We haven't got any access point credentials, so get them now"));
784 |
785 | Serial.print(F("Starting configuration portal @ "));
786 |
787 | #if USE_CUSTOM_AP_IP
788 | Serial.print(APStaticIP);
789 | #else
790 | Serial.print(F("192.168.4.1"));
791 | #endif
792 |
793 | Serial.print(F(", SSID = "));
794 | Serial.print(AP_SSID);
795 | Serial.print(F(", PWD = "));
796 | Serial.println(AP_PASS);
797 |
798 | #if DISPLAY_STORED_CREDENTIALS_IN_CP
799 | // New. Update Credentials, got from loadConfigData(), to display on CP
800 | ESPAsync_wifiManager.setCredentials(WM_config.WiFi_Creds[0].wifi_ssid, WM_config.WiFi_Creds[0].wifi_pw,
801 | WM_config.WiFi_Creds[1].wifi_ssid, WM_config.WiFi_Creds[1].wifi_pw);
802 | #endif
803 |
804 | // Starts an access point
805 | //if (!ESPAsync_wifiManager.startConfigPortal((const char *) ssid.c_str(), password))
806 | if ( !ESPAsync_wifiManager.startConfigPortal(AP_SSID.c_str(), AP_PASS.c_str()) )
807 | Serial.println(F("Not connected to WiFi but continuing anyway."));
808 | else
809 | Serial.println(F("WiFi connected...yeey :)"));
810 |
811 | // Stored for later usage, from v1.1.0, but clear first
812 | memset(&WM_config, 0, sizeof(WM_config));
813 |
814 | for (uint8_t i = 0; i < NUM_WIFI_CREDENTIALS; i++)
815 | {
816 | String tempSSID = ESPAsync_wifiManager.getSSID(i);
817 | String tempPW = ESPAsync_wifiManager.getPW(i);
818 |
819 | if (strlen(tempSSID.c_str()) < sizeof(WM_config.WiFi_Creds[i].wifi_ssid) - 1)
820 | strcpy(WM_config.WiFi_Creds[i].wifi_ssid, tempSSID.c_str());
821 | else
822 | strncpy(WM_config.WiFi_Creds[i].wifi_ssid, tempSSID.c_str(), sizeof(WM_config.WiFi_Creds[i].wifi_ssid) - 1);
823 |
824 | if (strlen(tempPW.c_str()) < sizeof(WM_config.WiFi_Creds[i].wifi_pw) - 1)
825 | strcpy(WM_config.WiFi_Creds[i].wifi_pw, tempPW.c_str());
826 | else
827 | strncpy(WM_config.WiFi_Creds[i].wifi_pw, tempPW.c_str(), sizeof(WM_config.WiFi_Creds[i].wifi_pw) - 1);
828 |
829 | // Don't permit NULL SSID and password len < MIN_AP_PASSWORD_SIZE (8)
830 | if ( (String(WM_config.WiFi_Creds[i].wifi_ssid) != "")
831 | && (strlen(WM_config.WiFi_Creds[i].wifi_pw) >= MIN_AP_PASSWORD_SIZE) )
832 | {
833 | LOGERROR3(F("* Add SSID = "), WM_config.WiFi_Creds[i].wifi_ssid, F(", PW = "), WM_config.WiFi_Creds[i].wifi_pw );
834 | wifiMulti.addAP(WM_config.WiFi_Creds[i].wifi_ssid, WM_config.WiFi_Creds[i].wifi_pw);
835 | }
836 | }
837 |
838 | #if USE_ESP_WIFIMANAGER_NTP
839 | String tempTZ = ESPAsync_wifiManager.getTimezoneName();
840 |
841 | if (strlen(tempTZ.c_str()) < sizeof(WM_config.TZ_Name) - 1)
842 | strcpy(WM_config.TZ_Name, tempTZ.c_str());
843 | else
844 | strncpy(WM_config.TZ_Name, tempTZ.c_str(), sizeof(WM_config.TZ_Name) - 1);
845 |
846 | const char * TZ_Result = ESPAsync_wifiManager.getTZ(WM_config.TZ_Name);
847 |
848 | if (strlen(TZ_Result) < sizeof(WM_config.TZ) - 1)
849 | strcpy(WM_config.TZ, TZ_Result);
850 | else
851 | strncpy(WM_config.TZ, TZ_Result, sizeof(WM_config.TZ_Name) - 1);
852 |
853 | if ( strlen(WM_config.TZ_Name) > 0 )
854 | {
855 | LOGERROR3(F("Saving current TZ_Name ="), WM_config.TZ_Name, F(", TZ = "), WM_config.TZ);
856 |
857 | #if ESP8266
858 | configTime(WM_config.TZ, "pool.ntp.org");
859 | #else
860 | //configTzTime(WM_config.TZ, "pool.ntp.org" );
861 | configTzTime(WM_config.TZ, "time.nist.gov", "0.pool.ntp.org", "1.pool.ntp.org");
862 | #endif
863 | }
864 | else
865 | {
866 | LOGERROR(F("Current Timezone Name is not set. Enter Config Portal to set."));
867 | }
868 |
869 | #endif
870 |
871 | // New in v1.4.0
872 | ESPAsync_wifiManager.getSTAStaticIPConfig(WM_STA_IPconfig);
873 | //////
874 |
875 | saveConfigData();
876 | }
877 | else
878 | {
879 | wifiMulti.addAP(Router_SSID.c_str(), Router_Pass.c_str());
880 | }
881 |
882 | startedAt = millis();
883 |
884 | if (!initialConfig)
885 | {
886 | // Load stored data, the addAP ready for MultiWiFi reconnection
887 | if (!configDataLoaded)
888 | loadConfigData();
889 |
890 | for (uint8_t i = 0; i < NUM_WIFI_CREDENTIALS; i++)
891 | {
892 | // Don't permit NULL SSID and password len < MIN_AP_PASSWORD_SIZE (8)
893 | if ( (String(WM_config.WiFi_Creds[i].wifi_ssid) != "")
894 | && (strlen(WM_config.WiFi_Creds[i].wifi_pw) >= MIN_AP_PASSWORD_SIZE) )
895 | {
896 | LOGERROR3(F("* Add SSID = "), WM_config.WiFi_Creds[i].wifi_ssid, F(", PW = "), WM_config.WiFi_Creds[i].wifi_pw );
897 | wifiMulti.addAP(WM_config.WiFi_Creds[i].wifi_ssid, WM_config.WiFi_Creds[i].wifi_pw);
898 | }
899 | }
900 |
901 | if ( WiFi.status() != WL_CONNECTED )
902 | {
903 | Serial.println(F("ConnectMultiWiFi in setup"));
904 |
905 | connectMultiWiFi();
906 | }
907 | }
908 |
909 | Serial.print(F("After waiting "));
910 | Serial.print((float) (millis() - startedAt) / 1000L);
911 | Serial.print(F(" secs more in setup(), connection result is "));
912 |
913 | if (WiFi.status() == WL_CONNECTED)
914 | {
915 | Serial.print(F("connected. Local IP: "));
916 | Serial.println(WiFi.localIP());
917 | }
918 | else
919 | Serial.println(ESPAsync_wifiManager.getStatus(WiFi.status()));
920 | }
921 |
922 | void loop()
923 | {
924 | // put your main code here, to run repeatedly
925 | check_status();
926 | }
927 |
--------------------------------------------------------------------------------
/examples/Async_ConfigOnDoubleReset_Multi/Async_ConfigOnDoubleReset_Multi.cpp:
--------------------------------------------------------------------------------
1 | /****************************************************************************************************************************
2 | Async_ConfigOnDoubleReset_Multi.cpp
3 | For ESP8266 / ESP32 boards
4 |
5 | ESPAsync_WiFiManager is a library for the ESP8266/Arduino platform, using (ESP)AsyncWebServer to enable easy
6 | configuration and reconfiguration of WiFi credentials using a Captive Portal.
7 |
8 | Modified from
9 | 1. Tzapu (https://github.com/tzapu/WiFiManager)
10 | 2. Ken Taylor (https://github.com/kentaylor)
11 | 3. Alan Steremberg (https://github.com/alanswx/ESPAsyncWiFiManager)
12 | 4. Khoi Hoang (https://github.com/khoih-prog/ESP_WiFiManager)
13 |
14 | Built by Khoi Hoang https://github.com/khoih-prog/ESPAsync_WiFiManager
15 | Licensed under MIT license
16 | *****************************************************************************************************************************/
17 | /****************************************************************************************************************************
18 | This example will open a configuration portal when the reset button is pressed twice.
19 | This method works well on Wemos boards which have a single reset button on board. It avoids using a pin for launching the configuration portal.
20 |
21 | How It Works
22 | 1) ESP8266
23 | Save data in RTC memory
24 | 2) ESP32
25 | Save data in EEPROM from address 256, size 512 bytes (both configurable)
26 |
27 | So when the device starts up it checks this region of ram for a flag to see if it has been recently reset.
28 | If so it launches a configuration portal, if not it sets the reset flag. After running for a while this flag is cleared so that
29 | it will only launch the configuration portal in response to closely spaced resets.
30 |
31 | Settings
32 | There are two values to be set in the sketch.
33 |
34 | DRD_TIMEOUT - Number of seconds to wait for the second reset. Set to 10 in the example.
35 | DRD_ADDRESS - The address in ESP8266 RTC RAM to store the flag. This memory must not be used for other purposes in the same sketch. Set to 0 in the example.
36 |
37 | This example, originally relied on the Double Reset Detector library from https://github.com/datacute/DoubleResetDetector
38 | To support ESP32, use ESP_DoubleResetDetector library from //https://github.com/khoih-prog/ESP_DoubleResetDetector
39 | *****************************************************************************************************************************/
40 |
41 | #if !( defined(ESP8266) || defined(ESP32) )
42 | #error This code is intended to run on the ESP8266 or ESP32 platform! Please check your Tools->Board setting.
43 | #endif
44 |
45 | #include "Async_ConfigOnDoubleReset_Multi.h"
46 |
47 | //Ported to ESP32
48 | #ifdef ESP32
49 | WiFiMulti wifiMulti;
50 |
51 | #if USE_LITTLEFS
52 | #if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 2) )
53 | FS* filesystem = &LittleFS;
54 | #else
55 | FS* filesystem = &LITTLEFS;
56 | #endif
57 |
58 | #elif USE_SPIFFS
59 | FS* filesystem = &SPIFFS;
60 | #else
61 | FS* filesystem = &FFat;
62 | #endif
63 | //////
64 |
65 | #else
66 |
67 | ESP8266WiFiMulti wifiMulti;
68 |
69 | #if USE_LITTLEFS
70 | FS* filesystem = &LittleFS;
71 | #else
72 | FS* filesystem = &SPIFFS;
73 | #endif
74 | //////
75 |
76 | #endif
77 |
78 | DoubleResetDetector* drd;
79 |
80 | // Onboard LED I/O pin on NodeMCU board
81 | const int PIN_LED = 2; // D4 on NodeMCU and WeMos. GPIO2/ADC12 of ESP32. Controls the onboard LED.
82 |
83 | // SSID and PW for Config Portal
84 | String ssid = "ESP_" + String(ESP_getChipId(), HEX);
85 | String password;
86 | //extern const char* password; // = "your_password";
87 |
88 | // SSID and PW for your Router
89 | String Router_SSID;
90 | String Router_Pass;
91 |
92 | WM_Config WM_config;
93 |
94 | // Indicates whether ESP has WiFi credentials saved from previous session, or double reset detected
95 | bool initialConfig; // = false;
96 |
97 | #if ( USE_DHCP_IP )
98 | // Use DHCP
99 | #if (_ESPASYNC_WIFIMGR_LOGLEVEL_ > 3)
100 | #warning Using DHCP IP
101 | #endif
102 |
103 | IPAddress stationIP = IPAddress(0, 0, 0, 0);
104 | IPAddress gatewayIP = IPAddress(192, 168, 1, 1);
105 | IPAddress netMask = IPAddress(255, 255, 255, 0);
106 | #else
107 | // Use static IP
108 | #if (_ESPASYNC_WIFIMGR_LOGLEVEL_ > 3)
109 | #warning Using static IP
110 | #endif
111 |
112 | #ifdef ESP32
113 | IPAddress stationIP = IPAddress(192, 168, 2, 232);
114 | #else
115 | IPAddress stationIP = IPAddress(192, 168, 2, 186);
116 | #endif
117 |
118 | IPAddress gatewayIP = IPAddress(192, 168, 2, 1);
119 | IPAddress netMask = IPAddress(255, 255, 255, 0);
120 | #endif
121 |
122 | IPAddress dns1IP = gatewayIP;
123 | IPAddress dns2IP = IPAddress(8, 8, 8, 8);
124 |
125 | IPAddress APStaticIP = IPAddress(192, 168, 100, 1);
126 | IPAddress APStaticGW = IPAddress(192, 168, 100, 1);
127 | IPAddress APStaticSN = IPAddress(255, 255, 255, 0);
128 |
129 |
130 | WiFi_AP_IPConfig WM_AP_IPconfig;
131 | WiFi_STA_IPConfig WM_STA_IPconfig;
132 |
133 | void initAPIPConfigStruct(WiFi_AP_IPConfig &in_WM_AP_IPconfig)
134 | {
135 | in_WM_AP_IPconfig._ap_static_ip = APStaticIP;
136 | in_WM_AP_IPconfig._ap_static_gw = APStaticGW;
137 | in_WM_AP_IPconfig._ap_static_sn = APStaticSN;
138 | }
139 |
140 | void initSTAIPConfigStruct(WiFi_STA_IPConfig &in_WM_STA_IPconfig)
141 | {
142 | in_WM_STA_IPconfig._sta_static_ip = stationIP;
143 | in_WM_STA_IPconfig._sta_static_gw = gatewayIP;
144 | in_WM_STA_IPconfig._sta_static_sn = netMask;
145 | #if USE_CONFIGURABLE_DNS
146 | in_WM_STA_IPconfig._sta_static_dns1 = dns1IP;
147 | in_WM_STA_IPconfig._sta_static_dns2 = dns2IP;
148 | #endif
149 | }
150 |
151 | void displayIPConfigStruct(WiFi_STA_IPConfig in_WM_STA_IPconfig)
152 | {
153 | LOGERROR3(F("stationIP ="), in_WM_STA_IPconfig._sta_static_ip, ", gatewayIP =", in_WM_STA_IPconfig._sta_static_gw);
154 | LOGERROR1(F("netMask ="), in_WM_STA_IPconfig._sta_static_sn);
155 | #if USE_CONFIGURABLE_DNS
156 | LOGERROR3(F("dns1IP ="), in_WM_STA_IPconfig._sta_static_dns1, ", dns2IP =", in_WM_STA_IPconfig._sta_static_dns2);
157 | #endif
158 | }
159 |
160 | void configWiFi(WiFi_STA_IPConfig in_WM_STA_IPconfig)
161 | {
162 | #if USE_CONFIGURABLE_DNS
163 | // Set static IP, Gateway, Subnetmask, DNS1 and DNS2. New in v1.0.5
164 | WiFi.config(in_WM_STA_IPconfig._sta_static_ip, in_WM_STA_IPconfig._sta_static_gw, in_WM_STA_IPconfig._sta_static_sn,
165 | in_WM_STA_IPconfig._sta_static_dns1, in_WM_STA_IPconfig._sta_static_dns2);
166 | #else
167 | // Set static IP, Gateway, Subnetmask, Use auto DNS1 and DNS2.
168 | WiFi.config(in_WM_STA_IPconfig._sta_static_ip, in_WM_STA_IPconfig._sta_static_gw, in_WM_STA_IPconfig._sta_static_sn);
169 | #endif
170 | }
171 |
172 | ///////////////////////////////////////////
173 |
174 | uint8_t connectMultiWiFi()
175 | {
176 | #if ESP32
177 | // For ESP32, this better be 0 to shorten the connect time.
178 | // For ESP32-S2/C3, must be > 500
179 | #if ( USING_ESP32_S2 || USING_ESP32_C3 )
180 | #define WIFI_MULTI_1ST_CONNECT_WAITING_MS 500L
181 | #else
182 | // For ESP32 core v1.0.6, must be >= 500
183 | #define WIFI_MULTI_1ST_CONNECT_WAITING_MS 800L
184 | #endif
185 | #else
186 | // For ESP8266, this better be 2200 to enable connect the 1st time
187 | #define WIFI_MULTI_1ST_CONNECT_WAITING_MS 2200L
188 | #endif
189 |
190 | #define WIFI_MULTI_CONNECT_WAITING_MS 500L
191 |
192 | uint8_t status;
193 |
194 | //WiFi.mode(WIFI_STA);
195 |
196 | LOGERROR(F("ConnectMultiWiFi with :"));
197 |
198 | if ( (Router_SSID != "") && (Router_Pass != "") )
199 | {
200 | LOGERROR3(F("* Flash-stored Router_SSID = "), Router_SSID, F(", Router_Pass = "), Router_Pass );
201 | LOGERROR3(F("* Add SSID = "), Router_SSID, F(", PW = "), Router_Pass );
202 | wifiMulti.addAP(Router_SSID.c_str(), Router_Pass.c_str());
203 | }
204 |
205 | for (uint8_t i = 0; i < NUM_WIFI_CREDENTIALS; i++)
206 | {
207 | // Don't permit NULL SSID and password len < MIN_AP_PASSWORD_SIZE (8)
208 | if ( (String(WM_config.WiFi_Creds[i].wifi_ssid) != "")
209 | && (strlen(WM_config.WiFi_Creds[i].wifi_pw) >= MIN_AP_PASSWORD_SIZE) )
210 | {
211 | LOGERROR3(F("* Additional SSID = "), WM_config.WiFi_Creds[i].wifi_ssid, F(", PW = "), WM_config.WiFi_Creds[i].wifi_pw );
212 | }
213 | }
214 |
215 | LOGERROR(F("Connecting MultiWifi..."));
216 |
217 | //WiFi.mode(WIFI_STA);
218 |
219 | #if !USE_DHCP_IP
220 | // New in v1.4.0
221 | configWiFi(WM_STA_IPconfig);
222 | //////
223 | #endif
224 |
225 | int i = 0;
226 |
227 | status = wifiMulti.run();
228 | delay(WIFI_MULTI_1ST_CONNECT_WAITING_MS);
229 |
230 | while ( ( i++ < 20 ) && ( status != WL_CONNECTED ) )
231 | {
232 | status = WiFi.status();
233 |
234 | if ( status == WL_CONNECTED )
235 | break;
236 | else
237 | delay(WIFI_MULTI_CONNECT_WAITING_MS);
238 | }
239 |
240 | if ( status == WL_CONNECTED )
241 | {
242 | LOGERROR1(F("WiFi connected after time: "), i);
243 | LOGERROR3(F("SSID:"), WiFi.SSID(), F(",RSSI="), WiFi.RSSI());
244 | LOGERROR3(F("Channel:"), WiFi.channel(), F(",IP address:"), WiFi.localIP() );
245 | }
246 | else
247 | {
248 | LOGERROR(F("WiFi not connected"));
249 |
250 | // To avoid unnecessary DRD
251 | drd->loop();
252 |
253 | #if ESP8266
254 | ESP.reset();
255 | #else
256 | ESP.restart();
257 | #endif
258 | }
259 |
260 | return status;
261 | }
262 |
263 | #if USE_ESP_WIFIMANAGER_NTP
264 |
265 | void printLocalTime()
266 | {
267 | #if ESP8266
268 | static time_t now;
269 |
270 | now = time(nullptr);
271 |
272 | if ( now > 1451602800 )
273 | {
274 | Serial.print("Local Date/Time: ");
275 | Serial.print(ctime(&now));
276 | }
277 |
278 | #else
279 | struct tm timeinfo;
280 |
281 | getLocalTime( &timeinfo );
282 |
283 | // Valid only if year > 2000.
284 | // You can get from timeinfo : tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec
285 | if (timeinfo.tm_year > 100 )
286 | {
287 | Serial.print("Local Date/Time: ");
288 | Serial.print( asctime( &timeinfo ) );
289 | }
290 |
291 | #endif
292 | }
293 |
294 | #endif
295 |
296 | void heartBeatPrint()
297 | {
298 | #if USE_ESP_WIFIMANAGER_NTP
299 | printLocalTime();
300 | #else
301 | static int num = 1;
302 |
303 | if (WiFi.status() == WL_CONNECTED)
304 | Serial.print(F("H")); // H means connected to WiFi
305 | else
306 | Serial.print(F("F")); // F means not connected to WiFi
307 |
308 | if (num == 80)
309 | {
310 | Serial.println();
311 | num = 1;
312 | }
313 | else if (num++ % 10 == 0)
314 | {
315 | Serial.print(F(" "));
316 | }
317 |
318 | #endif
319 | }
320 |
321 | void check_WiFi()
322 | {
323 | if ( (WiFi.status() != WL_CONNECTED) )
324 | {
325 | Serial.println(F("\nWiFi lost. Call connectMultiWiFi in loop"));
326 | connectMultiWiFi();
327 | }
328 | }
329 |
330 | void check_status()
331 | {
332 | static ulong checkstatus_timeout = 0;
333 | static ulong checkwifi_timeout = 0;
334 |
335 | static ulong current_millis;
336 |
337 | #define WIFICHECK_INTERVAL 1000L
338 |
339 | #if USE_ESP_WIFIMANAGER_NTP
340 | #define HEARTBEAT_INTERVAL 60000L
341 | #else
342 | #define HEARTBEAT_INTERVAL 10000L
343 | #endif
344 |
345 | current_millis = millis();
346 |
347 | // Check WiFi every WIFICHECK_INTERVAL (1) seconds.
348 | if ((current_millis > checkwifi_timeout) || (checkwifi_timeout == 0))
349 | {
350 | check_WiFi();
351 | checkwifi_timeout = current_millis + WIFICHECK_INTERVAL;
352 | }
353 |
354 | // Print hearbeat every HEARTBEAT_INTERVAL (10) seconds.
355 | if ((current_millis > checkstatus_timeout) || (checkstatus_timeout == 0))
356 | {
357 | heartBeatPrint();
358 | checkstatus_timeout = current_millis + HEARTBEAT_INTERVAL;
359 | }
360 | }
361 |
362 | int calcChecksum(uint8_t* address, uint16_t sizeToCalc)
363 | {
364 | uint16_t checkSum = 0;
365 |
366 | for (uint16_t index = 0; index < sizeToCalc; index++)
367 | {
368 | checkSum += * ( ( (byte*) address ) + index);
369 | }
370 |
371 | return checkSum;
372 | }
373 |
374 | bool loadConfigData()
375 | {
376 | File file = FileFS.open(CONFIG_FILENAME, "r");
377 | LOGERROR(F("LoadWiFiCfgFile "));
378 |
379 | memset((void *) &WM_config, 0, sizeof(WM_config));
380 |
381 | // New in v1.4.0
382 | memset((void *) &WM_STA_IPconfig, 0, sizeof(WM_STA_IPconfig));
383 | //////
384 |
385 | if (file)
386 | {
387 | file.readBytes((char *) &WM_config, sizeof(WM_config));
388 |
389 | // New in v1.4.0
390 | file.readBytes((char *) &WM_STA_IPconfig, sizeof(WM_STA_IPconfig));
391 | //////
392 |
393 | file.close();
394 | LOGERROR(F("OK"));
395 |
396 | if ( WM_config.checksum != calcChecksum( (uint8_t*) &WM_config, sizeof(WM_config) - sizeof(WM_config.checksum) ) )
397 | {
398 | LOGERROR(F("WM_config checksum wrong"));
399 |
400 | return false;
401 | }
402 |
403 | // New in v1.4.0
404 | displayIPConfigStruct(WM_STA_IPconfig);
405 | //////
406 |
407 | return true;
408 | }
409 | else
410 | {
411 | LOGERROR(F("failed"));
412 |
413 | return false;
414 | }
415 | }
416 |
417 | void saveConfigData()
418 | {
419 | File file = FileFS.open(CONFIG_FILENAME, "w");
420 | LOGERROR(F("SaveWiFiCfgFile "));
421 |
422 | if (file)
423 | {
424 | WM_config.checksum = calcChecksum( (uint8_t*) &WM_config, sizeof(WM_config) - sizeof(WM_config.checksum) );
425 |
426 | file.write((uint8_t*) &WM_config, sizeof(WM_config));
427 |
428 | displayIPConfigStruct(WM_STA_IPconfig);
429 |
430 | // New in v1.4.0
431 | file.write((uint8_t*) &WM_STA_IPconfig, sizeof(WM_STA_IPconfig));
432 | //////
433 |
434 | file.close();
435 | LOGERROR(F("OK"));
436 | }
437 | else
438 | {
439 | LOGERROR(F("failed"));
440 | }
441 | }
442 |
--------------------------------------------------------------------------------
/examples/Async_ConfigOnDoubleReset_Multi/Async_ConfigOnDoubleReset_Multi.h:
--------------------------------------------------------------------------------
1 | /****************************************************************************************************************************
2 | Async_ConfigOnDoubleReset_Multi.h
3 | For ESP8266 / ESP32 boards
4 |
5 | ESPAsync_WiFiManager is a library for the ESP8266/Arduino platform, using (ESP)AsyncWebServer to enable easy
6 | configuration and reconfiguration of WiFi credentials using a Captive Portal.
7 |
8 | Modified from
9 | 1. Tzapu (https://github.com/tzapu/WiFiManager)
10 | 2. Ken Taylor (https://github.com/kentaylor)
11 | 3. Alan Steremberg (https://github.com/alanswx/ESPAsyncWiFiManager)
12 | 4. Khoi Hoang (https://github.com/khoih-prog/ESP_WiFiManager)
13 |
14 | Built by Khoi Hoang https://github.com/khoih-prog/ESPAsync_WiFiManager
15 | Licensed under MIT license
16 | *****************************************************************************************************************************/
17 | /****************************************************************************************************************************
18 | This example will open a configuration portal when the reset button is pressed twice.
19 | This method works well on Wemos boards which have a single reset button on board. It avoids using a pin for launching the configuration portal.
20 |
21 | How It Works
22 | 1) ESP8266
23 | Save data in RTC memory
24 | 2) ESP32
25 | Save data in EEPROM from address 256, size 512 bytes (both configurable)
26 |
27 | So when the device starts up it checks this region of ram for a flag to see if it has been recently reset.
28 | If so it launches a configuration portal, if not it sets the reset flag. After running for a while this flag is cleared so that
29 | it will only launch the configuration portal in response to closely spaced resets.
30 |
31 | Settings
32 | There are two values to be set in the sketch.
33 |
34 | DRD_TIMEOUT - Number of seconds to wait for the second reset. Set to 10 in the example.
35 | DRD_ADDRESS - The address in ESP8266 RTC RAM to store the flag. This memory must not be used for other purposes in the same sketch. Set to 0 in the example.
36 |
37 | This example, originally relied on the Double Reset Detector library from https://github.com/datacute/DoubleResetDetector
38 | To support ESP32, use ESP_DoubleResetDetector library from //https://github.com/khoih-prog/ESP_DoubleResetDetector
39 | *****************************************************************************************************************************/
40 |
41 | #if !( defined(ESP8266) || defined(ESP32) )
42 | #error This code is intended to run on the ESP8266 or ESP32 platform! Please check your Tools->Board setting.
43 | #endif
44 |
45 | #define ESP_ASYNC_WIFIMANAGER_VERSION_MIN_TARGET "ESPAsync_WiFiManager v1.14.0"
46 | #define ESP_ASYNC_WIFIMANAGER_VERSION_MIN 1014000
47 |
48 | // Use from 0 to 4. Higher number, more debugging messages and memory usage.
49 | #define _ESPASYNC_WIFIMGR_LOGLEVEL_ 1
50 |
51 | #include
52 |
53 | //Ported to ESP32
54 | #ifdef ESP32
55 | #include
56 | #include
57 | #include
58 |
59 | // From v1.1.1
60 | #include
61 | extern WiFiMulti wifiMulti;
62 |
63 | // LittleFS has higher priority than SPIFFS
64 | #if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 2) )
65 | #define USE_LITTLEFS true
66 | #define USE_SPIFFS false
67 | #elif defined(ARDUINO_ESP32C3_DEV)
68 | // For core v1.0.6-, ESP32-C3 only supporting SPIFFS and EEPROM. To use v2.0.0+ for LittleFS
69 | #define USE_LITTLEFS false
70 | #define USE_SPIFFS true
71 | #endif
72 |
73 | #if USE_LITTLEFS
74 | // Use LittleFS
75 | #include "FS.h"
76 |
77 | // Check cores/esp32/esp_arduino_version.h and cores/esp32/core_version.h
78 | //#if ( ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(2, 0, 0) ) //(ESP_ARDUINO_VERSION_MAJOR >= 2)
79 | #if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 2) )
80 | #if (_ESPASYNC_WIFIMGR_LOGLEVEL_ > 3)
81 | #warning Using ESP32 Core 1.0.6 or 2.0.0+
82 | #endif
83 |
84 | // The library has been merged into esp32 core from release 1.0.6
85 | #include // https://github.com/espressif/arduino-esp32/tree/master/libraries/LittleFS
86 |
87 | extern FS* filesystem; // = &LittleFS;
88 | #define FileFS LittleFS
89 | #define FS_Name "LittleFS"
90 | #else
91 | #if (_ESPASYNC_WIFIMGR_LOGLEVEL_ > 3)
92 | #warning Using ESP32 Core 1.0.5-. You must install LITTLEFS library
93 | #endif
94 |
95 | // The library has been merged into esp32 core from release 1.0.6
96 | #include // https://github.com/lorol/LITTLEFS
97 |
98 | extern FS* filesystem; // = &LITTLEFS;
99 | #define FileFS LITTLEFS
100 | #define FS_Name "LittleFS"
101 | #endif
102 |
103 | #elif USE_SPIFFS
104 | #include
105 | extern FS* filesystem; // = &SPIFFS;
106 | #define FileFS SPIFFS
107 | #define FS_Name "SPIFFS"
108 | #else
109 | // +Use FFat
110 | #include
111 | extern FS* filesystem; // = &FFat;
112 | #define FileFS FFat
113 | #define FS_Name "FFat"
114 | #endif
115 | //////
116 |
117 | #define LED_BUILTIN 2
118 | #define LED_ON HIGH
119 | #define LED_OFF LOW
120 |
121 | #else
122 |
123 | #include //https://github.com/esp8266/Arduino
124 | //needed for library
125 | #include
126 |
127 | // From v1.1.1
128 | #include
129 | extern ESP8266WiFiMulti wifiMulti;
130 |
131 | #define USE_LITTLEFS true
132 |
133 | #if USE_LITTLEFS
134 | #include
135 | extern FS* filesystem; // = &LittleFS;
136 | #define FileFS LittleFS
137 | #define FS_Name "LittleFS"
138 | #else
139 | extern FS* filesystem; // = &SPIFFS;
140 | #define FileFS SPIFFS
141 | #define FS_Name "SPIFFS"
142 | #endif
143 | //////
144 |
145 | #define ESP_getChipId() (ESP.getChipId())
146 |
147 | #define LED_ON LOW
148 | #define LED_OFF HIGH
149 | #endif
150 |
151 | // These defines must be put before #include
152 | // to select where to store DoubleResetDetector's variable.
153 | // For ESP32, You must select one to be true (EEPROM or SPIFFS)
154 | // For ESP8266, You must select one to be true (RTC, EEPROM, SPIFFS or LITTLEFS)
155 | // Otherwise, library will use default EEPROM storage
156 | #ifdef ESP32
157 |
158 | // These defines must be put before #include
159 | // to select where to store DoubleResetDetector's variable.
160 | // For ESP32, You must select one to be true (EEPROM or SPIFFS)
161 | // Otherwise, library will use default EEPROM storage
162 | #if USE_LITTLEFS
163 | #define ESP_DRD_USE_LITTLEFS true
164 | #define ESP_DRD_USE_SPIFFS false
165 | #define ESP_DRD_USE_EEPROM false
166 | #elif USE_SPIFFS
167 | #define ESP_DRD_USE_LITTLEFS false
168 | #define ESP_DRD_USE_SPIFFS true
169 | #define ESP_DRD_USE_EEPROM false
170 | #else
171 | #define ESP_DRD_USE_LITTLEFS false
172 | #define ESP_DRD_USE_SPIFFS false
173 | #define ESP_DRD_USE_EEPROM true
174 | #endif
175 |
176 | #else //ESP8266
177 |
178 | // For DRD
179 | // These defines must be put before #include
180 | // to select where to store DoubleResetDetector's variable.
181 | // For ESP8266, You must select one to be true (RTC, EEPROM, SPIFFS or LITTLEFS)
182 | // Otherwise, library will use default EEPROM storage
183 | #if USE_LITTLEFS
184 | #define ESP_DRD_USE_LITTLEFS true
185 | #define ESP_DRD_USE_SPIFFS false
186 | #else
187 | #define ESP_DRD_USE_LITTLEFS false
188 | #define ESP_DRD_USE_SPIFFS true
189 | #endif
190 |
191 | #define ESP_DRD_USE_EEPROM false
192 | #define ESP8266_DRD_USE_RTC false
193 | #endif
194 |
195 | #define DOUBLERESETDETECTOR_DEBUG true //false
196 |
197 | #include //https://github.com/khoih-prog/ESP_DoubleResetDetector
198 |
199 | // Number of seconds after reset during which a
200 | // subseqent reset will be considered a double reset.
201 | #define DRD_TIMEOUT 10
202 |
203 | // RTC Memory Address for the DoubleResetDetector to use
204 | #define DRD_ADDRESS 0
205 |
206 | //DoubleResetDetector drd(DRD_TIMEOUT, DRD_ADDRESS);
207 | extern DoubleResetDetector* drd;//////
208 |
209 | // Onboard LED I/O pin on NodeMCU board
210 | extern const int PIN_LED; // = 2; // D4 on NodeMCU and WeMos. GPIO2/ADC12 of ESP32. Controls the onboard LED.
211 |
212 | // SSID and PW for Config Portal
213 | //String ssid = "ESP_" + String(ESP_getChipId(), HEX);
214 | extern String ssid;
215 | extern String password;
216 | //extern const char* password; // = "your_password";
217 |
218 | // SSID and PW for your Router
219 | extern String Router_SSID;
220 | extern String Router_Pass;
221 |
222 | // From v1.1.1
223 | // You only need to format the filesystem once
224 | //#define FORMAT_FILESYSTEM true
225 | #define FORMAT_FILESYSTEM false
226 |
227 | #define MIN_AP_PASSWORD_SIZE 8
228 |
229 | #define SSID_MAX_LEN 32
230 | //From v1.0.10, WPA2 passwords can be up to 63 characters long.
231 | #define PASS_MAX_LEN 64
232 |
233 | typedef struct
234 | {
235 | char wifi_ssid[SSID_MAX_LEN];
236 | char wifi_pw [PASS_MAX_LEN];
237 | } WiFi_Credentials;
238 |
239 | typedef struct
240 | {
241 | String wifi_ssid;
242 | String wifi_pw;
243 | } WiFi_Credentials_String;
244 |
245 | #define NUM_WIFI_CREDENTIALS 2
246 |
247 | // Assuming max 49 chars
248 | #define TZNAME_MAX_LEN 50
249 | #define TIMEZONE_MAX_LEN 50
250 |
251 | typedef struct
252 | {
253 | WiFi_Credentials WiFi_Creds [NUM_WIFI_CREDENTIALS];
254 | char TZ_Name[TZNAME_MAX_LEN]; // "America/Toronto"
255 | char TZ[TIMEZONE_MAX_LEN]; // "EST5EDT,M3.2.0,M11.1.0"
256 | uint16_t checksum;
257 | } WM_Config;
258 |
259 | extern WM_Config WM_config;
260 |
261 | #define CONFIG_FILENAME F("/wifi_cred.dat")
262 | //////
263 |
264 | // Indicates whether ESP has WiFi credentials saved from previous session, or double reset detected
265 | extern bool initialConfig; // = false;
266 |
267 | // Use false if you don't like to display Available Pages in Information Page of Config Portal
268 | // Comment out or use true to display Available Pages in Information Page of Config Portal
269 | // Must be placed before #include
270 | #define USE_AVAILABLE_PAGES true //false
271 |
272 | // From v1.0.10 to permit disable/enable StaticIP configuration in Config Portal from sketch. Valid only if DHCP is used.
273 | // You'll loose the feature of dynamically changing from DHCP to static IP, or vice versa
274 | // You have to explicitly specify false to disable the feature.
275 | //#define USE_STATIC_IP_CONFIG_IN_CP false
276 |
277 | // Use false to disable NTP config. Advisable when using Cellphone, Tablet to access Config Portal.
278 | // See Issue 23: On Android phone ConfigPortal is unresponsive (https://github.com/khoih-prog/ESP_WiFiManager/issues/23)
279 | #define USE_ESP_WIFIMANAGER_NTP false
280 |
281 | // Just use enough to save memory. On ESP8266, can cause blank ConfigPortal screen
282 | // if using too much memory
283 | #define USING_AFRICA false
284 | #define USING_AMERICA true
285 | #define USING_ANTARCTICA false
286 | #define USING_ASIA false
287 | #define USING_ATLANTIC false
288 | #define USING_AUSTRALIA false
289 | #define USING_EUROPE false
290 | #define USING_INDIAN false
291 | #define USING_PACIFIC false
292 | #define USING_ETC_GMT false
293 |
294 | // Use true to enable CloudFlare NTP service. System can hang if you don't have Internet access while accessing CloudFlare
295 | // See Issue #21: CloudFlare link in the default portal (https://github.com/khoih-prog/ESP_WiFiManager/issues/21)
296 | #define USE_CLOUDFLARE_NTP false
297 |
298 | // New in v1.0.11
299 | #define USING_CORS_FEATURE true
300 | //////
301 |
302 | // Use USE_DHCP_IP == true for dynamic DHCP IP, false to use static IP which you have to change accordingly to your network
303 | #if (defined(USE_STATIC_IP_CONFIG_IN_CP) && !USE_STATIC_IP_CONFIG_IN_CP)
304 | // Force DHCP to be true
305 | #if defined(USE_DHCP_IP)
306 | #undef USE_DHCP_IP
307 | #endif
308 | #define USE_DHCP_IP true
309 | #else
310 | // You can select DHCP or Static IP here
311 | //#define USE_DHCP_IP true
312 | #define USE_DHCP_IP false
313 | #endif
314 |
315 | #if ( USE_DHCP_IP )
316 | // Use DHCP
317 | #if (_ESPASYNC_WIFIMGR_LOGLEVEL_ > 3)
318 | #warning Using DHCP IP
319 | #endif
320 |
321 | extern IPAddress stationIP; // = IPAddress(0, 0, 0, 0);
322 | extern IPAddress gatewayIP; // = IPAddress(192, 168, 1, 1);
323 | extern IPAddress netMask; // = IPAddress(255, 255, 255, 0);
324 | #else
325 | // Use static IP
326 | #if (_ESPASYNC_WIFIMGR_LOGLEVEL_ > 3)
327 | #warning Using static IP
328 | #endif
329 |
330 | #ifdef ESP32
331 | extern IPAddress stationIP; // = IPAddress(192, 168, 2, 232);
332 | #else
333 | extern IPAddress stationIP; // = IPAddress(192, 168, 2, 186);
334 | #endif
335 |
336 | extern IPAddress gatewayIP; // = IPAddress(192, 168, 2, 1);
337 | extern IPAddress netMask; // = IPAddress(255, 255, 255, 0);
338 | #endif
339 |
340 | #define USE_CONFIGURABLE_DNS true
341 |
342 | extern IPAddress dns1IP; // = gatewayIP;
343 | extern IPAddress dns2IP; // = IPAddress(8, 8, 8, 8);
344 |
345 | #define USE_CUSTOM_AP_IP false
346 |
347 | extern IPAddress APStaticIP; // = IPAddress(192, 168, 100, 1);
348 | extern IPAddress APStaticGW; // = IPAddress(192, 168, 100, 1);
349 | extern IPAddress APStaticSN; // = IPAddress(255, 255, 255, 0);
350 |
351 | #include //https://github.com/khoih-prog/ESPAsync_WiFiManager
352 |
353 | #define HTTP_PORT 80
354 |
355 | extern WiFi_AP_IPConfig WM_AP_IPconfig;
356 | extern WiFi_STA_IPConfig WM_STA_IPconfig;
357 |
358 | void initAPIPConfigStruct(WiFi_AP_IPConfig &in_WM_AP_IPconfig);
359 | void initSTAIPConfigStruct(WiFi_STA_IPConfig &in_WM_STA_IPconfig);
360 | void displayIPConfigStruct(WiFi_STA_IPConfig in_WM_STA_IPconfig);
361 | void configWiFi(WiFi_STA_IPConfig in_WM_STA_IPconfig);
362 |
363 | uint8_t connectMultiWiFi();
364 |
365 |
366 | #if USE_ESP_WIFIMANAGER_NTP
367 | void printLocalTime();
368 | #endif
369 |
370 | void heartBeatPrint();
371 |
372 | void check_WiFi();
373 | void check_status();
374 | int calcChecksum(uint8_t* address, uint16_t sizeToCalc);
375 | bool loadConfigData();
376 | void saveConfigData();
377 |
--------------------------------------------------------------------------------
/examples/Async_ConfigOnDoubleReset_Multi/Async_ConfigOnDoubleReset_Multi.ino:
--------------------------------------------------------------------------------
1 | /****************************************************************************************************************************
2 | Async_ConfigOnDoubleReset_Multi.ino
3 | For ESP8266 / ESP32 boards
4 |
5 | ESPAsync_WiFiManager is a library for the ESP8266/Arduino platform, using (ESP)AsyncWebServer to enable easy
6 | configuration and reconfiguration of WiFi credentials using a Captive Portal.
7 |
8 | Modified from
9 | 1. Tzapu (https://github.com/tzapu/WiFiManager)
10 | 2. Ken Taylor (https://github.com/kentaylor)
11 | 3. Alan Steremberg (https://github.com/alanswx/ESPAsyncWiFiManager)
12 | 4. Khoi Hoang (https://github.com/khoih-prog/ESP_WiFiManager)
13 |
14 | Built by Khoi Hoang https://github.com/khoih-prog/ESPAsync_WiFiManager
15 | Licensed under MIT license
16 | *****************************************************************************************************************************/
17 | /****************************************************************************************************************************
18 | This example will open a configuration portal when the reset button is pressed twice.
19 | This method works well on Wemos boards which have a single reset button on board. It avoids using a pin for launching the configuration portal.
20 |
21 | How It Works
22 | 1) ESP8266
23 | Save data in RTC memory
24 | 2) ESP32
25 | Save data in EEPROM from address 256, size 512 bytes (both configurable)
26 |
27 | So when the device starts up it checks this region of ram for a flag to see if it has been recently reset.
28 | If so it launches a configuration portal, if not it sets the reset flag. After running for a while this flag is cleared so that
29 | it will only launch the configuration portal in response to closely spaced resets.
30 |
31 | Settings
32 | There are two values to be set in the sketch.
33 |
34 | DRD_TIMEOUT - Number of seconds to wait for the second reset. Set to 10 in the example.
35 | DRD_ADDRESS - The address in ESP8266 RTC RAM to store the flag. This memory must not be used for other purposes in the same sketch. Set to 0 in the example.
36 |
37 | This example, originally relied on the Double Reset Detector library from https://github.com/datacute/DoubleResetDetector
38 | To support ESP32, use ESP_DoubleResetDetector library from //https://github.com/khoih-prog/ESP_DoubleResetDetector
39 | *****************************************************************************************************************************/
40 |
41 | #if !( defined(ESP8266) || defined(ESP32) )
42 | #error This code is intended to run on the ESP8266 or ESP32 platform! Please check your Tools->Board setting.
43 | #endif
44 |
45 | // These definitions must be placed before #include
46 | #include "Async_ConfigOnDoubleReset_Multi.h"
47 |
48 | #include //https://github.com/khoih-prog/ESPAsync_WiFiManager
49 |
50 | // Redundant, for v1.10.0 only
51 | //#include //https://github.com/khoih-prog/ESPAsync_WiFiManager
52 |
53 | void setup()
54 | {
55 | // put your setup code here, to run once:
56 | // initialize the LED digital pin as an output.
57 | pinMode(PIN_LED, OUTPUT);
58 |
59 | Serial.begin(115200);
60 |
61 | while (!Serial);
62 |
63 | delay(200);
64 |
65 | Serial.print(F("\nStarting Async_ConfigOnDoubleReset_Multi using "));
66 | Serial.print(FS_Name);
67 | Serial.print(F(" on "));
68 | Serial.println(ARDUINO_BOARD);
69 | Serial.println(ESP_ASYNC_WIFIMANAGER_VERSION);
70 | Serial.println(ESP_DOUBLE_RESET_DETECTOR_VERSION);
71 |
72 | #if defined(ESP_ASYNC_WIFIMANAGER_VERSION_INT)
73 |
74 | if (ESP_ASYNC_WIFIMANAGER_VERSION_INT < ESP_ASYNC_WIFIMANAGER_VERSION_MIN)
75 | {
76 | Serial.print("Warning. Must use this example on Version later than : ");
77 | Serial.println(ESP_ASYNC_WIFIMANAGER_VERSION_MIN_TARGET);
78 | }
79 |
80 | #endif
81 |
82 | Serial.setDebugOutput(false);
83 |
84 | if (FORMAT_FILESYSTEM)
85 | FileFS.format();
86 |
87 | // Format FileFS if not yet
88 | #ifdef ESP32
89 |
90 | if (!FileFS.begin(true))
91 | #else
92 | if (!FileFS.begin())
93 | #endif
94 | {
95 | #ifdef ESP8266
96 | FileFS.format();
97 | #endif
98 |
99 | Serial.println(F("SPIFFS/LittleFS failed! Already tried formatting."));
100 |
101 | if (!FileFS.begin())
102 | {
103 | // prevents debug info from the library to hide err message.
104 | delay(100);
105 |
106 | #if USE_LITTLEFS
107 | Serial.println(F("LittleFS failed!. Please use SPIFFS or EEPROM. Stay forever"));
108 | #else
109 | Serial.println(F("SPIFFS failed!. Please use LittleFS or EEPROM. Stay forever"));
110 | #endif
111 |
112 | while (true)
113 | {
114 | delay(1);
115 | }
116 | }
117 | }
118 |
119 | drd = new DoubleResetDetector(DRD_TIMEOUT, DRD_ADDRESS);
120 |
121 | unsigned long startedAt = millis();
122 |
123 | // New in v1.4.0
124 | initAPIPConfigStruct(WM_AP_IPconfig);
125 | initSTAIPConfigStruct(WM_STA_IPconfig);
126 | //////
127 |
128 | //Local intialization. Once its business is done, there is no need to keep it around
129 | // Use this to default DHCP hostname to ESP8266-XXXXXX or ESP32-XXXXXX
130 | //ESPAsync_WiFiManager ESPAsync_wifiManager(&webServer, &dnsServer);
131 | // Use this to personalize DHCP hostname (RFC952 conformed)
132 | AsyncWebServer webServer(HTTP_PORT);
133 |
134 | #if ( USING_ESP32_S2 || USING_ESP32_C3 )
135 | ESPAsync_WiFiManager ESPAsync_wifiManager(&webServer, NULL, "AsyncConfigOnDoubleReset");
136 | #else
137 | AsyncDNSServer dnsServer;
138 |
139 | ESPAsync_WiFiManager ESPAsync_wifiManager(&webServer, &dnsServer, "AsyncConfigOnDoubleReset");
140 | #endif
141 |
142 | #if USE_CUSTOM_AP_IP
143 | //set custom ip for portal
144 | // New in v1.4.0
145 | ESPAsync_wifiManager.setAPStaticIPConfig(WM_AP_IPconfig);
146 | //////
147 | #endif
148 |
149 | ESPAsync_wifiManager.setMinimumSignalQuality(-1);
150 |
151 | // From v1.0.10 only
152 | // Set config portal channel, default = 1. Use 0 => random channel from 1-11
153 | ESPAsync_wifiManager.setConfigPortalChannel(0);
154 | //////
155 |
156 | #if !USE_DHCP_IP
157 | // Set (static IP, Gateway, Subnetmask, DNS1 and DNS2) or (IP, Gateway, Subnetmask). New in v1.0.5
158 | // New in v1.4.0
159 | ESPAsync_wifiManager.setSTAStaticIPConfig(WM_STA_IPconfig);
160 | //////
161 | #endif
162 |
163 | // New from v1.1.1
164 | #if USING_CORS_FEATURE
165 | ESPAsync_wifiManager.setCORSHeader("Your Access-Control-Allow-Origin");
166 | #endif
167 |
168 | // We can't use WiFi.SSID() in ESP32 as it's only valid after connected.
169 | // SSID and Password stored in ESP32 wifi_ap_record_t and wifi_config_t are also cleared in reboot
170 | // Have to create a new function to store in EEPROM/SPIFFS for this purpose
171 | Router_SSID = ESPAsync_wifiManager.WiFi_SSID();
172 | Router_Pass = ESPAsync_wifiManager.WiFi_Pass();
173 |
174 | //Remove this line if you do not want to see WiFi password printed
175 | Serial.println("ESP Self-Stored: SSID = " + Router_SSID + ", Pass = " + Router_Pass);
176 |
177 | // SSID to uppercase
178 | ssid.toUpperCase();
179 | password = "My" + ssid;
180 |
181 | bool configDataLoaded = false;
182 |
183 | // From v1.1.0, Don't permit NULL password
184 | if ( (Router_SSID != "") && (Router_Pass != "") )
185 | {
186 | LOGERROR3(F("* Add SSID = "), Router_SSID, F(", PW = "), Router_Pass);
187 | wifiMulti.addAP(Router_SSID.c_str(), Router_Pass.c_str());
188 |
189 | ESPAsync_wifiManager.setConfigPortalTimeout(120); //If no access point name has been previously entered disable timeout.
190 | Serial.println(F("Got ESP Self-Stored Credentials. Timeout 120s for Config Portal"));
191 | }
192 |
193 | if (loadConfigData())
194 | {
195 | configDataLoaded = true;
196 |
197 | ESPAsync_wifiManager.setConfigPortalTimeout(120); //If no access point name has been previously entered disable timeout.
198 | Serial.println(F("Got stored Credentials. Timeout 120s for Config Portal"));
199 |
200 | #if USE_ESP_WIFIMANAGER_NTP
201 |
202 | if ( strlen(WM_config.TZ_Name) > 0 )
203 | {
204 | LOGERROR3(F("Current TZ_Name ="), WM_config.TZ_Name, F(", TZ = "), WM_config.TZ);
205 |
206 | #if ESP8266
207 | configTime(WM_config.TZ, "pool.ntp.org");
208 | #else
209 | //configTzTime(WM_config.TZ, "pool.ntp.org" );
210 | configTzTime(WM_config.TZ, "time.nist.gov", "0.pool.ntp.org", "1.pool.ntp.org");
211 | #endif
212 | }
213 | else
214 | {
215 | Serial.println(F("Current Timezone is not set. Enter Config Portal to set."));
216 | }
217 |
218 | #endif
219 | }
220 | else
221 | {
222 | // Enter CP only if no stored SSID on flash and file
223 | Serial.println(F("Open Config Portal without Timeout: No stored Credentials."));
224 | initialConfig = true;
225 | }
226 |
227 | if (drd->detectDoubleReset())
228 | {
229 | // DRD, disable timeout.
230 | ESPAsync_wifiManager.setConfigPortalTimeout(0);
231 |
232 | Serial.println(F("Open Config Portal without Timeout: Double Reset Detected"));
233 | initialConfig = true;
234 | }
235 |
236 | if (initialConfig)
237 | {
238 | Serial.print(F("Starting configuration portal @ "));
239 |
240 | #if USE_CUSTOM_AP_IP
241 | Serial.print(APStaticIP);
242 | #else
243 | Serial.print(F("192.168.4.1"));
244 | #endif
245 |
246 | Serial.print(F(", SSID = "));
247 | Serial.print(ssid);
248 | Serial.print(F(", PWD = "));
249 | Serial.println(password);
250 |
251 | digitalWrite(PIN_LED, LED_ON); // turn the LED on by making the voltage LOW to tell us we are in configuration mode.
252 |
253 | //sets timeout in seconds until configuration portal gets turned off.
254 | //If not specified device will remain in configuration mode until
255 | //switched off via webserver or device is restarted.
256 | //ESPAsync_wifiManager.setConfigPortalTimeout(600);
257 |
258 | #if DISPLAY_STORED_CREDENTIALS_IN_CP
259 | // New. Update Credentials, got from loadConfigData(), to display on CP
260 | ESPAsync_wifiManager.setCredentials(WM_config.WiFi_Creds[0].wifi_ssid, WM_config.WiFi_Creds[0].wifi_pw,
261 | WM_config.WiFi_Creds[1].wifi_ssid, WM_config.WiFi_Creds[1].wifi_pw);
262 | #endif
263 |
264 | // Starts an access point
265 | if (!ESPAsync_wifiManager.startConfigPortal((const char *) ssid.c_str(), password.c_str()))
266 | Serial.println(F("Not connected to WiFi but continuing anyway."));
267 | else
268 | {
269 | Serial.println(F("WiFi connected...yeey :)"));
270 | }
271 |
272 | // Stored for later usage, from v1.1.0, but clear first
273 | memset(&WM_config, 0, sizeof(WM_config));
274 |
275 | for (uint8_t i = 0; i < NUM_WIFI_CREDENTIALS; i++)
276 | {
277 | String tempSSID = ESPAsync_wifiManager.getSSID(i);
278 | String tempPW = ESPAsync_wifiManager.getPW(i);
279 |
280 | if (strlen(tempSSID.c_str()) < sizeof(WM_config.WiFi_Creds[i].wifi_ssid) - 1)
281 | strcpy(WM_config.WiFi_Creds[i].wifi_ssid, tempSSID.c_str());
282 | else
283 | strncpy(WM_config.WiFi_Creds[i].wifi_ssid, tempSSID.c_str(), sizeof(WM_config.WiFi_Creds[i].wifi_ssid) - 1);
284 |
285 | if (strlen(tempPW.c_str()) < sizeof(WM_config.WiFi_Creds[i].wifi_pw) - 1)
286 | strcpy(WM_config.WiFi_Creds[i].wifi_pw, tempPW.c_str());
287 | else
288 | strncpy(WM_config.WiFi_Creds[i].wifi_pw, tempPW.c_str(), sizeof(WM_config.WiFi_Creds[i].wifi_pw) - 1);
289 |
290 | // Don't permit NULL SSID and password len < MIN_AP_PASSWORD_SIZE (8)
291 | if ( (String(WM_config.WiFi_Creds[i].wifi_ssid) != "")
292 | && (strlen(WM_config.WiFi_Creds[i].wifi_pw) >= MIN_AP_PASSWORD_SIZE) )
293 | {
294 | LOGERROR3(F("* Add SSID = "), WM_config.WiFi_Creds[i].wifi_ssid, F(", PW = "), WM_config.WiFi_Creds[i].wifi_pw );
295 | wifiMulti.addAP(WM_config.WiFi_Creds[i].wifi_ssid, WM_config.WiFi_Creds[i].wifi_pw);
296 | }
297 | }
298 |
299 | #if USE_ESP_WIFIMANAGER_NTP
300 | String tempTZ = ESPAsync_wifiManager.getTimezoneName();
301 |
302 | if (strlen(tempTZ.c_str()) < sizeof(WM_config.TZ_Name) - 1)
303 | strcpy(WM_config.TZ_Name, tempTZ.c_str());
304 | else
305 | strncpy(WM_config.TZ_Name, tempTZ.c_str(), sizeof(WM_config.TZ_Name) - 1);
306 |
307 | const char * TZ_Result = ESPAsync_wifiManager.getTZ(WM_config.TZ_Name);
308 |
309 | if (strlen(TZ_Result) < sizeof(WM_config.TZ) - 1)
310 | strcpy(WM_config.TZ, TZ_Result);
311 | else
312 | strncpy(WM_config.TZ, TZ_Result, sizeof(WM_config.TZ_Name) - 1);
313 |
314 | if ( strlen(WM_config.TZ_Name) > 0 )
315 | {
316 | LOGERROR3(F("Saving current TZ_Name ="), WM_config.TZ_Name, F(", TZ = "), WM_config.TZ);
317 |
318 | #if ESP8266
319 | configTime(WM_config.TZ, "pool.ntp.org");
320 | #else
321 | //configTzTime(WM_config.TZ, "pool.ntp.org" );
322 | configTzTime(WM_config.TZ, "time.nist.gov", "0.pool.ntp.org", "1.pool.ntp.org");
323 | #endif
324 | }
325 | else
326 | {
327 | LOGERROR(F("Current Timezone Name is not set. Enter Config Portal to set."));
328 | }
329 |
330 | #endif
331 |
332 | // New in v1.4.0
333 | ESPAsync_wifiManager.getSTAStaticIPConfig(WM_STA_IPconfig);
334 | //////
335 |
336 | saveConfigData();
337 | }
338 |
339 | digitalWrite(PIN_LED, LED_OFF); // Turn led off as we are not in configuration mode.
340 |
341 | startedAt = millis();
342 |
343 | if (!initialConfig)
344 | {
345 | // Load stored data, the addAP ready for MultiWiFi reconnection
346 | if (!configDataLoaded)
347 | loadConfigData();
348 |
349 | for (uint8_t i = 0; i < NUM_WIFI_CREDENTIALS; i++)
350 | {
351 | // Don't permit NULL SSID and password len < MIN_AP_PASSWORD_SIZE (8)
352 | if ( (String(WM_config.WiFi_Creds[i].wifi_ssid) != "")
353 | && (strlen(WM_config.WiFi_Creds[i].wifi_pw) >= MIN_AP_PASSWORD_SIZE) )
354 | {
355 | LOGERROR3(F("* Add SSID = "), WM_config.WiFi_Creds[i].wifi_ssid, F(", PW = "), WM_config.WiFi_Creds[i].wifi_pw );
356 | wifiMulti.addAP(WM_config.WiFi_Creds[i].wifi_ssid, WM_config.WiFi_Creds[i].wifi_pw);
357 | }
358 | }
359 |
360 | if ( WiFi.status() != WL_CONNECTED )
361 | {
362 | Serial.println(F("ConnectMultiWiFi in setup"));
363 |
364 | connectMultiWiFi();
365 | }
366 | }
367 |
368 | Serial.print(F("After waiting "));
369 | Serial.print((float) (millis() - startedAt) / 1000);
370 | Serial.print(F(" secs more in setup(), connection result is "));
371 |
372 | if (WiFi.status() == WL_CONNECTED)
373 | {
374 | Serial.print(F("connected. Local IP: "));
375 | Serial.println(WiFi.localIP());
376 | }
377 | else
378 | Serial.println(ESPAsync_wifiManager.getStatus(WiFi.status()));
379 | }
380 |
381 | void loop()
382 | {
383 | // Call the double reset detector loop method every so often,
384 | // so that it can recognise when the timeout expires.
385 | // You can also call drd.stop() when you wish to no longer
386 | // consider the next reset as a double reset.
387 | drd->loop();
388 |
389 | // put your main code here, to run repeatedly
390 | check_status();
391 | }
392 |
--------------------------------------------------------------------------------
/examples/Async_ConfigOnSwitch/README.md:
--------------------------------------------------------------------------------
1 | # The Config On Switch Example
2 | In this example we initiate the configuration portal to connect an ESP8266 to WiFi by pushing a button. The example requires this version of WiFi Manager. It will not work with the tzapu version.
3 |
4 | ## Why Have A Button To Initiate Configuration?
5 | Once the ESP device contains network credentials it will always try to connect to that network in the background and succeed whenever that network becomes visible. The application continues to function and because WiFi networks tend to be flaky only a human has the knowledge of whether a new network is required or it is better to wait for the network to become visible again. Therefore, providing a configuration portal must be human initiated and requiring a button push is a good way to get human input.
6 |
7 | The alternative of automatically going into configuration mode every time a WiFi network becomes invisible will cause the application to stop and the device will sit in configuration mode forever. This is undesirable when a network is temporarily unavailable.
8 |
9 | ## Issues With Automatically Going Into Configuration Mode
10 | Providing a timeout on configuration mode is one way to get the application running again when a network becomes temporarily unavailable and no one is around to reboot. However, the application will still not function while waiting for the timeout and the device is vulnerable to sabotage when in config mode. With a push button it will also be vulnerable to sabotage whenever the saboteur has physical access but then it is vulnerable in other ways as well. An assumption that saboteurs will not have physical access to the device is sufficient for most applications.
11 |
12 |
13 |
--------------------------------------------------------------------------------
/examples/Async_ESP32_FSWebServer/README.md:
--------------------------------------------------------------------------------
1 | # Async_ESP32_FSWebServer Example
2 |
3 | Compare this efficient Async_ESP32_FSWebServer example with the so complicated twin [ESP32_FSWebServer](https://github.com/khoih-prog/ESP_WiFiManager/tree/master/examples/ESP32_FSWebServer) to appreciate the powerful AsynWebServer this [ESPAsync_WiFiManager Library](https://github.com/khoih-prog/ESPAsync_WiFiManager) is relying on.
4 |
5 | ## First, how Config Portal works?
6 |
7 | In `Configuration Portal Mode`, it starts an access point called `ESP_xxxxxx`. Connect to it using the configurable password you can define in the code. For example, `your_password` (see examples):
8 |
9 | ```cpp
10 | // SSID and PW for Config Portal
11 | String ssid = "ESP_" + String(ESP_getChipId(), HEX);
12 | const char* password = "your_password";
13 | ```
14 | After you connected, please, go to http://192.168.4.1, you'll see this `Main` page:
15 |
16 |
17 |
18 |
19 |
20 | Select `Information` to enter the Info page where the board info will be shown (long page)
21 |
22 |
23 |
24 |
25 |
26 | or short page (default)
27 |
28 |
29 |
30 |
31 |
32 | Select `Configuration` to enter this page where you can select an AP and specify its WiFi Credentials
33 |
34 |
35 |
36 |
37 |
38 | Enter your credentials, then click `Save`. The WiFi Credentials will be saved and the board reboots to connect to the selected WiFi AP.
39 |
40 | If you're already connected to a listed WiFi AP and don't want to change anything, just select `Exit Portal` from the `Main` page to reboot the board and connect to the previously-stored AP. The WiFi Credentials are still intact.
41 |
42 | ---
43 |
44 | ## How to use this Async_ESP32_FSWebServer example?
45 |
46 | This shows you how to use this example in Ubuntu (but you can use similar commands in other OSes)
47 |
48 | ### Download Data files
49 |
50 | 1. For example, you already downloaded data files from [Async_ESP32_FSWebServer data](https://github.com/khoih-prog/ESPAsync_WiFiManager/tree/master/examples/Async_ESP32_FSWebServer/data) to a local folder, for example:
51 |
52 | ```
53 | ~/Arduino/libraries/ESPAsync_WiFiManager-master/examples/Async_ESP32_FSWebServer/data
54 | ```
55 |
56 | ### HOWTO Upload files to ESP32 (SPIFFS or FFat)
57 |
58 | Use one of these methods (preferable first)
59 |
60 | 1. Go to http://async-esp32fs.local/edit, then "Choose file" -> "Upload"
61 | 2. or Upload the contents of the data folder with MkSPIFFS Tool ("ESP8266 Sketch Data Upload" in Tools menu in Arduino IDE)
62 | 3. or upload the contents of a folder by running the following commands:
63 | ```
64 | Ubuntu$ cd ~/Arduino/libraries/ESPAsync_WiFiManager-master/examples/Async_ESP32_FSWebServer/data
65 | Ubuntu$ for file in \`\ls -A1\`; do curl -F "file=@$PWD/$file" http://async-esp32fs.local/edit; done
66 | ```
67 | ---
68 |
69 | ### Demonstrating pictures
70 |
71 |
72 |
73 |
74 |
75 | 4. Edit / Delete / Download any file in the the folder by going to http://async-esp32fs.local/edit
76 |
77 |
93 |
94 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/examples/Async_ESP32_FSWebServer/pics/async-esp32fs.local.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoih-prog/ESPAsync_WiFiManager/e83343f4c2df14b504d284982152539692ac2078/examples/Async_ESP32_FSWebServer/pics/async-esp32fs.local.png
--------------------------------------------------------------------------------
/examples/Async_ESP32_FSWebServer/pics/async-esp32fs.local_edit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoih-prog/ESPAsync_WiFiManager/e83343f4c2df14b504d284982152539692ac2078/examples/Async_ESP32_FSWebServer/pics/async-esp32fs.local_edit.png
--------------------------------------------------------------------------------
/examples/Async_ESP32_FSWebServer_DRD/README.md:
--------------------------------------------------------------------------------
1 | # Async_ESP32_FSWebServer_DRD Example
2 |
3 | Compare this efficient Async_ESP32_FSWebServer_DRD example with the so complicated twin [ESP32_FSWebServer_DRD](https://github.com/khoih-prog/ESP_WiFiManager/tree/master/examples/ESP32_FSWebServer_DRD) to appreciate the powerful AsynWebServer this [ESPAsync_WiFiManager Library](https://github.com/khoih-prog/ESPAsync_WiFiManager) is relying on.
4 |
5 | ## First, how Config Portal works?
6 |
7 | In `Configuration Portal Mode`, it starts an access point called `ESP_xxxxxx`. Connect to it using the configurable password you can define in the code. For example, `your_password` (see examples):
8 |
9 | ```cpp
10 | // SSID and PW for Config Portal
11 | String ssid = "ESP_" + String(ESP_getChipId(), HEX);
12 | const char* password = "your_password";
13 | ```
14 | After you connected, please, go to http://192.168.4.1, you'll see this `Main` page:
15 |
16 |
17 |
18 |
19 |
20 | Select `Information` to enter the Info page where the board info will be shown (long page)
21 |
22 |
23 |
24 |
25 |
26 | or short page (default)
27 |
28 |
29 |
30 |
31 |
32 | Select `Configuration` to enter this page where you can select an AP and specify its WiFi Credentials
33 |
34 |
35 |
36 |
37 |
38 | Enter your credentials, then click `Save`. The WiFi Credentials will be saved and the board reboots to connect to the selected WiFi AP.
39 |
40 | If you're already connected to a listed WiFi AP and don't want to change anything, just select `Exit Portal` from the `Main` page to reboot the board and connect to the previously-stored AP. The WiFi Credentials are still intact.
41 |
42 | ---
43 |
44 | ## How to use this Async_ESP32_FSWebServer_DRD example?
45 |
46 | This shows you how to use this example in Ubuntu (but you can use similar commands in other OSes)
47 |
48 | ### Download Data files
49 |
50 | 1. For example, you already downloaded data files from [Async_ESP32_FSWebServer_DRD data](https://github.com/khoih-prog/ESPAsync_WiFiManager/tree/master/examples/Async_ESP32_FSWebServer_DRD/data) to a local folder, for example:
51 |
52 | ```
53 | ~/Arduino/libraries/ESPAsync_WiFiManager-master/examples/Async_ESP32_FSWebServer_DRD/data
54 | ```
55 |
56 | ### HOWTO Upload files to ESP32 (SPIFFS or FFat)
57 |
58 | Use one of these methods (preferable first)
59 |
60 | 1. Go to http://async-esp32fs.local/edit, then "Choose file" -> "Upload"
61 | 2. or Upload the contents of the data folder with MkSPIFFS Tool ("ESP8266 Sketch Data Upload" in Tools menu in Arduino IDE)
62 | 3. or upload the contents of a folder by running the following commands:
63 | ```
64 | Ubuntu$ cd ~/Arduino/libraries/ESPAsync_WiFiManager-master/examples/Async_ESP32_FSWebServer_DRD/data
65 | Ubuntu$ for file in \`\ls -A1\`; do curl -F "file=@$PWD/$file" http://async-esp32fs.local/edit; done
66 | ```
67 |
68 | ---
69 |
70 | ### Demonstrating pictures
71 |
72 |
73 |
74 |
75 |
76 | 4. Edit / Delete / Download any file in the the folder by going to http://async-esp32fs.local/edit
77 |
78 |
93 |
94 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/examples/Async_ESP32_FSWebServer_DRD/pics/async-esp32fs.local.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoih-prog/ESPAsync_WiFiManager/e83343f4c2df14b504d284982152539692ac2078/examples/Async_ESP32_FSWebServer_DRD/pics/async-esp32fs.local.png
--------------------------------------------------------------------------------
/examples/Async_ESP32_FSWebServer_DRD/pics/async-esp32fs.local_edit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoih-prog/ESPAsync_WiFiManager/e83343f4c2df14b504d284982152539692ac2078/examples/Async_ESP32_FSWebServer_DRD/pics/async-esp32fs.local_edit.png
--------------------------------------------------------------------------------
/examples/Async_ESP_FSWebServer/README.md:
--------------------------------------------------------------------------------
1 | # Async_ESP_FSWebServer Example
2 |
3 | Compare this efficient Async_ESP_FSWebServer example with the so complicated twin [ESP_FSWebServer](https://github.com/khoih-prog/ESP_WiFiManager/tree/master/examples/ESP_FSWebServer) to appreciate the powerful AsynWebServer this [ESPAsync_WiFiManager Library](https://github.com/khoih-prog/ESPAsync_WiFiManager) is relying on.
4 |
5 | ## First, how Config Portal works?
6 |
7 | In `Configuration Portal Mode`, it starts an access point called `ESP_xxxxxx`. Connect to it using the configurable password you can define in the code. For example, `your_password` (see examples):
8 |
9 | ```cpp
10 | // SSID and PW for Config Portal
11 | String ssid = "ESP_" + String(ESP_getChipId(), HEX);
12 | const char* password = "your_password";
13 | ```
14 | After you connected, please, go to http://192.168.4.1, you'll see this `Main` page:
15 |
16 |
17 |
18 |
19 |
20 | Select `Information` to enter the Info page where the board info will be shown (long page)
21 |
22 |
23 |
24 |
25 |
26 | or short page (default)
27 |
28 |
29 |
30 |
31 |
32 | Select `Configuration` to enter this page where you can select an AP and specify its WiFi Credentials
33 |
34 |
35 |
36 |
37 |
38 | Enter your credentials, then click `Save`. The WiFi Credentials will be saved and the board reboots to connect to the selected WiFi AP.
39 |
40 | If you're already connected to a listed WiFi AP and don't want to change anything, just select `Exit Portal` from the `Main` page to reboot the board and connect to the previously-stored AP. The WiFi Credentials are still intact.
41 |
42 | ---
43 |
44 | ## How to use this Async_ESP_FSWebServer example?
45 |
46 | This shows you how to use this example in Ubuntu (but you can use similar commands in other OSes)
47 |
48 | ### Download Data files
49 |
50 | 1. For example, you already downloaded data files from [Async_ESP_FSWebServer data](https://github.com/khoih-prog/ESPAsync_WiFiManager/tree/master/examples/Async_ESP_FSWebServer/data) to a local folder, for example:
51 |
52 | ```
53 | ~/Arduino/libraries/ESPAsync_WiFiManager-master/examples/Async_ESP_FSWebServer/data
54 | ```
55 |
56 | ### HOWTO Upload files to ESP8266 (LittleFS or SPIFFS)
57 |
58 | Use one of these methods (preferable first)
59 |
60 | 1. Go to http://async-esp8266fs.local/edit, then "Choose file" -> "Upload"
61 | 2. or Upload the contents of the data folder with MkSPIFFS Tool ("ESP8266 Sketch Data Upload" in Tools menu in Arduino IDE)
62 | 3. or upload the contents of a folder by running the following commands:
63 | ```
64 | Ubuntu$ cd ~/Arduino/libraries/ESPAsync_WiFiManager-master/examples/Async_ESP_FSWebServer/data
65 | Ubuntu$ for file in \`\ls -A1\`; do curl -F "file=@$PWD/$file" http://async-esp8266fs.local/edit; done
66 | ```
67 |
68 | ---
69 |
70 | ### Demonstrating pictures
71 |
72 |
73 |
74 |
75 |
76 | 4. Edit / Delete / Download any file in the the folder by going to http://async-esp8266fs.local/edit
77 |
78 |
93 |
94 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/examples/Async_ESP_FSWebServer/pics/async-esp8266fs.local.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoih-prog/ESPAsync_WiFiManager/e83343f4c2df14b504d284982152539692ac2078/examples/Async_ESP_FSWebServer/pics/async-esp8266fs.local.png
--------------------------------------------------------------------------------
/examples/Async_ESP_FSWebServer/pics/async-esp8266fs.local_edit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoih-prog/ESPAsync_WiFiManager/e83343f4c2df14b504d284982152539692ac2078/examples/Async_ESP_FSWebServer/pics/async-esp8266fs.local_edit.png
--------------------------------------------------------------------------------
/examples/Async_ESP_FSWebServer_DRD/README.md:
--------------------------------------------------------------------------------
1 | # Async_ESP_FSWebServer_DRD Example
2 |
3 | Compare this efficient Async_ESP_FSWebServer example with the so complicated twin [ESP_FSWebServer_DRD](https://github.com/khoih-prog/ESP_WiFiManager/tree/master/examples/ESP_FSWebServer_DRD) to appreciate the powerful AsynWebServer this [ESPAsync_WiFiManager Library](https://github.com/khoih-prog/ESPAsync_WiFiManager) is relying on.
4 |
5 | ## First, how Config Portal works?
6 |
7 | In `Configuration Portal Mode`, it starts an access point called `ESP_xxxxxx`. Connect to it using the configurable password you can define in the code. For example, `your_password` (see examples):
8 |
9 | ```cpp
10 | // SSID and PW for Config Portal
11 | String ssid = "ESP_" + String(ESP_getChipId(), HEX);
12 | const char* password = "your_password";
13 | ```
14 | After you connected, please, go to http://192.168.4.1, you'll see this `Main` page:
15 |
16 |
17 |
18 |
19 |
20 | Select `Information` to enter the Info page where the board info will be shown (long page)
21 |
22 |
23 |
24 |
25 |
26 | or short page (default)
27 |
28 |
29 |
30 |
31 |
32 | Select `Configuration` to enter this page where you can select an AP and specify its WiFi Credentials
33 |
34 |
35 |
36 |
37 |
38 | Enter your credentials, then click `Save`. The WiFi Credentials will be saved and the board reboots to connect to the selected WiFi AP.
39 |
40 | If you're already connected to a listed WiFi AP and don't want to change anything, just select `Exit Portal` from the `Main` page to reboot the board and connect to the previously-stored AP. The WiFi Credentials are still intact.
41 |
42 | ---
43 |
44 | ## How to use this Async_ESP_FSWebServer example?
45 |
46 | This shows you how to use this example in Ubuntu (but you can use similar commands in other OSes)
47 |
48 | ### Download Data files
49 |
50 | 1. For example, you already downloaded data files from [Async_ESP_FSWebServer data](https://github.com/khoih-prog/ESPAsync_WiFiManager/tree/master/examples/Async_ESP_FSWebServer/data) to a local folder, for example:
51 |
52 | ```
53 | ~/Arduino/libraries/ESPAsync_WiFiManager-master/examples/Async_ESP_FSWebServer_DRD/data
54 | ```
55 |
56 | ### HOWTO Upload files to ESP8266 (LittleFS or SPIFFS)
57 |
58 | Use one of these methods (preferable first)
59 |
60 | 1. Go to http://async-esp8266fs.local/edit, then "Choose file" -> "Upload"
61 | 2. or Upload the contents of the data folder with MkSPIFFS Tool ("ESP8266 Sketch Data Upload" in Tools menu in Arduino IDE)
62 | 3. or upload the contents of a folder by running the following commands:
63 | ```
64 | Ubuntu$ cd ~/Arduino/libraries/ESPAsync_WiFiManager-master/examples/Async_ESP_FSWebServer/data
65 | Ubuntu$ for file in \`\ls -A1\`; do curl -F "file=@$PWD/$file" http://async-esp8266fs.local/edit; done
66 | ```
67 |
68 | ---
69 |
70 | ### Demonstrating pictures
71 |
72 |
73 |
74 |
75 |
76 | 4. Edit / Delete / Download any file in the the folder by going to http://async-esp8266fs.local/edit
77 |
78 |