From 3aa115c40924931560e3b67da93e3da1254489d7 Mon Sep 17 00:00:00 2001
From: Khoi Hoang <57012152+khoih-prog@users.noreply.github.com>
Date: Mon, 28 Dec 2020 18:01:36 -0500
Subject: [PATCH] v1.2.5
### Releases v1.2.5
1. Clean-up all compiler warnings possible.
2. Update Table of Contents
3. Add examples
4. Add Version String
---
CONTRIBUTING.md | 22 +-
README.md | 461 ++++++++++++++----
.../AsyncFSBrowser_STM32.ino | 16 +-
.../AsyncMultiWebServer_STM32.ino | 272 +++++++++++
.../Async_AdvancedWebServer.ino | 11 +-
.../Async_HelloServer/Async_HelloServer.ino | 9 +-
.../Async_HelloServer2/Async_HelloServer2.ino | 9 +-
.../Async_HttpBasicAuth.ino | 10 +-
.../Async_PostServer/Async_PostServer.ino | 9 +-
.../Async_RegexPatterns_STM32.ino | 8 +-
.../Async_SimpleWebServer_STM32.ino | 8 +-
examples/MQTTClient_Auth/MQTTClient_Auth.ino | 168 +++++++
examples/MQTTClient_Auth/defines.h | 125 +++++
.../MQTTClient_Basic/MQTTClient_Basic.ino | 170 +++++++
examples/MQTTClient_Basic/defines.h | 125 +++++
.../MQTT_ThingStream/MQTT_ThingStream.ino | 221 +++++++++
examples/MQTT_ThingStream/defines.h | 125 +++++
examples/WebClient/WebClient.ino | 6 +-
examples/WebClient/defines.h | 11 +-
.../WebClientRepeating/WebClientRepeating.ino | 6 +-
examples/WebClientRepeating/defines.h | 10 +-
library.json | 6 +-
library.properties | 3 +-
pics/AsyncMultiWebServer_STM32_SVR1.png | Bin 0 -> 33016 bytes
pics/AsyncMultiWebServer_STM32_SVR2.png | Bin 0 -> 33093 bytes
pics/AsyncMultiWebServer_STM32_SVR3.png | Bin 0 -> 33945 bytes
platformio/platformio.ini | 16 +-
src/AsyncEventSource_STM32.cpp | 5 +-
src/AsyncEventSource_STM32.h | 5 +-
src/AsyncJson_STM32.h | 5 +-
src/AsyncWebAuthentication_STM32.cpp | 3 +-
src/AsyncWebAuthentication_STM32.h | 7 +-
src/AsyncWebHandlerImpl_STM32.h | 7 +-
src/AsyncWebHandlers_STM32.cpp | 3 +-
src/AsyncWebRequest_STM32.cpp | 3 +-
src/AsyncWebResponseImpl_STM32.h | 7 +-
src/AsyncWebResponses_STM32.cpp | 3 +-
src/AsyncWebServer_Debug_STM32.h | 7 +-
src/AsyncWebServer_STM32.cpp | 3 +-
src/AsyncWebServer_STM32.h | 9 +-
src/AsyncWebSocket_STM32.cpp | 3 +-
src/AsyncWebSocket_STM32.h | 5 +-
src/AsyncWebSynchronization_STM32.h | 5 +-
src/Crypto/Hash.h | 2 +
src/Crypto/bearssl_hash.h | 2 +
src/Crypto/md5.h | 2 +
src/Crypto/sha1.h | 2 +
src/StringArray_STM32.h | 5 +-
src/libb64/cdecode.c | 108 ++--
src/libb64/cdecode.h | 15 +-
src/libb64/cencode.c | 76 ++-
src/libb64/cencode.h | 15 +-
52 files changed, 1890 insertions(+), 244 deletions(-)
create mode 100644 examples/AsyncMultiWebServer_STM32/AsyncMultiWebServer_STM32.ino
create mode 100644 examples/MQTTClient_Auth/MQTTClient_Auth.ino
create mode 100644 examples/MQTTClient_Auth/defines.h
create mode 100644 examples/MQTTClient_Basic/MQTTClient_Basic.ino
create mode 100644 examples/MQTTClient_Basic/defines.h
create mode 100644 examples/MQTT_ThingStream/MQTT_ThingStream.ino
create mode 100644 examples/MQTT_ThingStream/defines.h
create mode 100644 pics/AsyncMultiWebServer_STM32_SVR1.png
create mode 100644 pics/AsyncMultiWebServer_STM32_SVR2.png
create mode 100644 pics/AsyncMultiWebServer_STM32_SVR3.png
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 0166a0d..c78be0e 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,21 +1,21 @@
-## Contributing to ESP_WiFiManager
+## Contributing to AsyncWebServer_STM32
### Reporting Bugs
-Please report bugs in ESP_WiFiManager if you find them.
+Please report bugs in AsyncWebServer_STM32 if you find them.
However, before reporting a bug please check through the following:
-* [Existing Open Issues](https://github.com/khoih-prog/ESP_WiFiManager/issues) - someone might have already encountered this.
+* [Existing Open Issues](https://github.com/khoih-prog/AsyncWebServer_STM32/issues) - someone might have already encountered this.
-If you don't find anything, please [open a new issue](https://github.com/khoih-prog/ESP_WiFiManager/issues/new).
+If you don't find anything, please [open a new issue](https://github.com/khoih-prog/AsyncWebServer_STM32/issues/new).
### How to submit a bug report
Please ensure to specify the following:
-* Arduino IDE version (e.g. 1.8.11) or Platform.io version
-* `ESP8266` or `ESP32` Core Version (e.g. ESP8266 core v2.6.3 or ESP32 v1.0.4)
+* Arduino IDE version (e.g. 1.8.13) or Platform.io version
+* Board Core Version (e.g. STM32F7 Nucleo-144 NUCLEO_F767ZI core v1.9.0, etc.)
* Contextual information (e.g. what you were trying to achieve)
* Simplest possible steps to reproduce
* Anything that might be relevant in your opinion, such as:
@@ -26,10 +26,10 @@ Please ensure to specify the following:
### Example
```
-Arduino IDE version: 1.8.11
-ESP8266 Core Version 2.6.3
-OS: Ubuntu 16.04 LTS
-Linux Inspiron 4.4.0-170-generic #199-Ubuntu SMP Thu Nov 14 01:45:04 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
+Arduino IDE version: 1.8.13
+STM32F7 Nucleo-144 NUCLEO_F767ZI core v1.9.0
+OS: Ubuntu 20.04 LTS
+Linux xy-Inspiron-3593 5.4.0-51-generic #56-Ubuntu SMP Mon Oct 5 14:28:49 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
Context:
I encountered an endless loop while trying to connect to Local WiFi.
@@ -44,7 +44,7 @@ Steps to reproduce:
Feel free to post feature requests. It's helpful if you can explain exactly why the feature would be useful.
-There are usually some outstanding feature requests in the [existing issues list](https://github.com/khoih-prog/ESP_WiFiManager/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement), feel free to add comments to them.
+There are usually some outstanding feature requests in the [existing issues list](https://github.com/khoih-prog/AsyncWebServer_STM32/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement), feel free to add comments to them.
### Sending Pull Requests
diff --git a/README.md b/README.md
index a5b666f..7978501 100644
--- a/README.md
+++ b/README.md
@@ -9,17 +9,130 @@
---
---
-### Releases v1.2.4
+## Table of contents
-1. Add back MD5/SHA1 authentication feature.
-2. Add example, update README.md, clean up.
+* [Table of contents](#table-of-contents)
+* [Why do we need this AsyncWebServer_STM32 library](#why-do-we-need-this-asyncwebserver_stm32-library)
+ * [Features](#features)
+ * [Currently supported Boards](#currently-supported-boards)
+* [Changelog](#changelog)
+ * [Releases v1.2.5](#releases-v125)
+ * [Releases v1.2.4](#releases-v124)
+ * [Releases v1.2.3](#releases-v123)
+* [Prerequisites](#prerequisites)
+* [Installation](#installation)
+ * [Use Arduino Library Manager](#use-arduino-library-manager)
+ * [Manual Install](#manual-install)
+ * [VS Code & PlatformIO](#vs-code--platformio)
+* [Important things to remember](#important-things-to-remember)
+* [Principles of operation](#principles-of-operation)
+ * [The Async Web server](#the-async-web-server)
+ * [Request Life Cycle](#request-life-cycle)
+ * [Rewrites and how do they work](#rewrites-and-how-do-they-work)
+ * [Handlers and how do they work](#handlers-and-how-do-they-work)
+ * [Responses and how do they work](#responses-and-how-do-they-work)
+ * [Template processing](#template-processing)
+* [Request Variables](#request-variables)
+ * [Common Variables](#common-variables)
+ * [Headers](#headers)
+ * [GET, POST and FILE parameters](#get-post-and-file-parameters)
+ * [JSON body handling with ArduinoJson](#json-body-handling-with-arduinojson)
+* [Responses](#responses)
+ * [Redirect to another URL](#redirect-to-another-url)
+ * [Basic response with HTTP Code](#basic-response-with-http-code)
+ * [Basic response with HTTP Code and extra headers](#basic-response-with-http-code-and-extra-headers)
+ * [Basic response with string content](#basic-response-with-string-content)
+ * [Basic response with string content and extra headers](#basic-response-with-string-content-and-extra-headers)
+ * [Respond with content coming from a Stream](#respond-with-content-coming-from-a-stream)
+ * [Respond with content coming from a Stream and extra headers](#respond-with-content-coming-from-a-stream-and-extra-headers)
+ * [Respond with content coming from a Stream containing templates](#respond-with-content-coming-from-a-stream-containing-templates)
+ * [Respond with content coming from a Stream containing templates and extra headers](#respond-with-content-coming-from-a-stream-containing-templates-and-extra-headers)
+ * [Respond with content using a callback](#respond-with-content-using-a-callback)
+ * [Respond with content using a callback and extra headers](#respond-with-content-using-a-callback-and-extra-headers)
+ * [Respond with content using a callback containing templates](#respond-with-content-using-a-callback-containing-templates)
+ * [Respond with content using a callback containing templates and extra headers](#respond-with-content-using-a-callback-containing-templates-and-extra-headers)
+ * [Chunked Response](#chunked-response)
+ * [Chunked Response containing templates](#chunked-response-containing-templates)
+ * [Print to response](#print-to-response)
+ * [ArduinoJson Basic Response](#arduinojson-basic-response)
+ * [ArduinoJson Advanced Response](#arduinojson-advanced-response)
+* [Param Rewrite With Matching](#param-rewrite-with-matching)
+* [Using filters](#using-filters)
+* [Bad Responses](#bad-responses)
+ * [Respond with content using a callback without content length to HTTP/1.0 clients](#respond-with-content-using-a-callback-without-content-length-to-http10-clients)
+* [Async WebSocket Plugin](#async-websocket-plugin)
+ * [Async WebSocket Event](#async-websocket-event)
+ * [Methods for sending data to a socket client](#methods-for-sending-data-to-a-socket-client)
+ * [Direct access to web socket message buffer](#direct-access-to-web-socket-message-buffer)
+ * [Limiting the number of web socket clients](#limiting-the-number-of-web-socket-clients)
+* [Async Event Source Plugin](#async-event-source-plugin)
+ * [Setup Event Source on the server](#setup-event-source-on-the-server)
+ * [Setup Event Source in the browser](#setup-event-source-in-the-browser)
+* [Remove handlers and rewrites](#remove-handlers-and-rewrites)
+* [Setting up the server](#setting-up-the-server)
+ * [Setup global and class functions as request handlers](#setup-global-and-class-functions-as-request-handlers)
+ * [Methods for controlling websocket connections](#methods-for-controlling-websocket-connections)
+ * [Adding Default Headers](#adding-default-headers)
+ * [Path variable](#path-variable)
+* [Examples](#examples)
+ * [ 1. Async_AdvancedWebServer](examples/Async_AdvancedWebServer)
+ * [ 2. AsyncFSBrowser_STM32](examples/AsyncFSBrowser_STM32)
+ * [ 3. Async_HelloServer](examples/Async_HelloServer)
+ * [ 4. Async_HelloServer2](examples/Async_HelloServer2)
+ * [ 5. Async_HttpBasicAuth](examples/Async_HttpBasicAuth)
+ * [ 6. AsyncMultiWebServer_STM32](examples/AsyncMultiWebServer_STM32)
+ * [ 7. Async_PostServer](examples/Async_PostServer)
+ * [ 8. Async_RegexPatterns_STM32](examples/Async_RegexPatterns_STM32)
+ * [ 9. Async_SimpleWebServer_STM32](examples/Async_SimpleWebServer_STM32)
+ * [10. **MQTTClient_Auth**](examples/MQTTClient_Auth)
+ * [11. **MQTTClient_Basic**](examples/MQTTClient_Basic)
+ * [12. **MQTT_ThingStream**](examples/MQTT_ThingStream)
+ * [13. WebClient](examples/WebClient)
+ * [14. WebClientRepeating](examples/WebClientRepeating)
+* [Debug Terminal Output Samples](#debug-termimal-output-samples)
+ * [1. AsyncMultiWebServer_STM32 on NUCLEO_F767ZI using Built-in LAN8742A Ethernet and STM32Ethernet Library](#1-asyncmultiwebserver_stm32-on-nucleo_f767zi-using-built-in-lan8742a-ethernet-and-stm32ethernet-library)
+ * [2. WebClient on NUCLEO_F767ZI using Built-in LAN8742A Ethernet and STM32Ethernet Library](#1-webclient-on-nucleo_f767zi-using-built-in-lan8742a-ethernet-and-stm32ethernet-library)
+ * [3. MQTTClient_Auth on NUCLEO_F767ZI using Built-in LAN8742A Ethernet and STM32Ethernet Library](#1-mqttclient_auth-on-nucleo_f767zi-using-built-in-lan8742a-ethernet-and-stm32ethernet-library)
+ * [4. MQTTClient_Basic on NUCLEO_F767ZI using Built-in LAN8742A Ethernet and STM32Ethernet Library](#1-mqttclient_basic-on-nucleo_f767zi-using-built-in-lan8742a-ethernet-and-stm32ethernet-library)
+ * [5. MQTT_ThingStream on NUCLEO_F767ZI using Built-in LAN8742A Ethernet and STM32Ethernet Library](#1-mqtt_thingstream-on-nucleo_f767zi-using-built-in-lan8742a-ethernet-and-stm32ethernet-library)
+* [Debug](#debug)
+* [Troubleshooting](#troubleshooting)
+* [Releases](#releases)
+* [Issues](#issues)
+* [TO DO](#to-do)
+* [DONE](#done)
+* [Contributions and Thanks](#contributions-and-thanks)
+* [Contributing](#contributing)
+* [License](#license)
+* [Copyright](#copyright)
-#### Initial Releases v1.2.3
+---
+---
-1. Initial coding to port [ESPAsyncWebServer](https://github.com/me-no-dev/ESPAsyncWebServer) to STM32 boards using builtin LAN8742A Ethernet. More supports will be added gradually later, such as AsyncUDP, other Ethernet / WiFi shields.
-2. Add more examples.
-3. Add debugging features.
-4. Bump up to v1.2.3 to sync with [ESPAsyncWebServer v1.2.3](https://github.com/me-no-dev/ESPAsyncWebServer).
+### Why do we need this Async [AsyncWebServer_STM32 library](https://github.com/khoih-prog/AsyncWebServer_STM32)
+
+#### Features
+
+- Using asynchronous network means that you can handle **more than one connection at the same time**
+- **You are called once the request is ready and parsed**
+- When you send the response, you are **immediately ready** to handle other connections while the server is taking care of sending the response in the background
+- **Speed is OMG**
+- **Easy to use API, HTTP Basic and Digest MD5 Authentication (default), ChunkedResponse**
+- Easily extensible to handle **any type of content**
+- Supports Continue 100
+- **Async WebSocket plugin offering different locations without extra servers or ports**
+- Async EventSource (Server-Sent Events) plugin to send events to the browser
+- URL Rewrite plugin for conditional and permanent url rewrites
+- ServeStatic plugin that supports cache, Last-Modified, default index and more
+- Simple template processing engine to handle templates
+
+This library is based on, modified from:
+
+1. [Hristo Gochkov's ESPAsyncWebServer](https://github.com/me-no-dev/ESPAsyncWebServer)
+
+to apply the better and faster **asynchronous** feature of the **powerful** [ESPAsyncWebServer Library](https://github.com/me-no-dev/ESPAsyncWebServer) into STM32 boards using builtin LAN8742A Ethernet.
+
+---
#### Currently Supported Boards
@@ -27,20 +140,35 @@
2. Discovery STM32F746G-DISCOVERY
3. Any STM32 boards with enough flash/memory and already configured to run LAN8742A Ethernet.
+
+---
---
-### Async HTTP and WebSocket Server for STM32 boards using builtin LAN8742A Ethernet
+## Changelog
-This library is based on, modified from:
+### Releases v1.2.5
-1. [Hristo Gochkov's ESPAsyncWebServer](https://github.com/me-no-dev/ESPAsyncWebServer)
+1. Clean-up all compiler warnings possible.
+2. Update Table of Contents
+3. Add examples
+4. Add Version String
-to apply the better and faster **asynchronous** feature of the **powerful** [ESPAsyncWebServer Library](https://github.com/me-no-dev/ESPAsyncWebServer) into STM32 boards using builtin LAN8742A Ethernet.
+### Releases v1.2.4
+
+1. Add back MD5/SHA1 authentication feature.
+2. Add example, update README.md, clean up.
+
+#### Releases v1.2.3
+
+1. Initial coding to port [ESPAsyncWebServer](https://github.com/me-no-dev/ESPAsyncWebServer) to STM32 boards using builtin LAN8742A Ethernet. More supports will be added gradually later, such as AsyncUDP, other Ethernet / WiFi shields.
+2. Add more examples.
+3. Add debugging features.
+4. Bump up to v1.2.3 to sync with [ESPAsyncWebServer v1.2.3](https://github.com/me-no-dev/ESPAsyncWebServer).
---
---
-## Prerequisite
+## Prerequisites
1. [`Arduino IDE 1.8.13+` for Arduino](https://www.arduino.cc/en/Main/Software)
2. [`Arduino Core for STM32 1.9.0+`](https://github.com/stm32duino/Arduino_Core_STM32) for STM32 (Use Arduino Board Manager)
@@ -53,6 +181,7 @@ to apply the better and faster **asynchronous** feature of the **powerful** [ESP
## Installation
### Use Arduino Library Manager
+
The best and easiest way is to use `Arduino Library Manager`. Search for `AsyncWebServer_STM32`, then select / install the latest version. You can also use this link [![arduino-library-badge](https://www.ardu-badge.com/badge/AsyncWebServer_STM32.svg?)](https://www.ardu-badge.com/AsyncWebServer_STM32) for more detailed instructions.
### Manual Install
@@ -63,88 +192,15 @@ The best and easiest way is to use `Arduino Library Manager`. Search for `AsyncW
4. Copy the whole `AsyncWebServer_STM32-master` folder to Arduino libraries' directory such as `~/Arduino/libraries/`.
### VS Code & PlatformIO:
+
1. Install [VS Code](https://code.visualstudio.com/)
2. Install [PlatformIO](https://platformio.org/platformio-ide)
-3. Install **AsyncWebServer_STM32** library by using [Library Manager](https://docs.platformio.org/en/latest/librarymanager/). Search for ***AsyncWebServer_STM32*** in [Platform.io Author's Libraries](https://platformio.org/lib/search?query=author:%22Khoi%20Hoang%22)
+3. Install [**AsyncWebServer_STM32** library](https://platformio.org/lib/show/11237/AsyncWebServer_STM32) by using [Library Manager](https://platformio.org/lib/show/11237/AsyncWebServer_STM32/installation). Search for **AsyncWebServer_STM32** in [Platform.io Author's Libraries](https://platformio.org/lib/search?query=author:%22Khoi%20Hoang%22)
4. Use included [platformio.ini](platformio/platformio.ini) file from examples to ensure that all dependent libraries will installed automatically. Please visit documentation for the other options and examples at [Project Configuration File](https://docs.platformio.org/page/projectconf.html)
----
-
-## Table of contents
-
-- [AsyncWebServer_STM32](#espasyncwebserver)
- - [Table of contents](#table-of-contents)
- - [Why should you care](#why-should-you-care)
- - [Important things to remember](#important-things-to-remember)
- - [Principles of operation](#principles-of-operation)
- - [The Async Web server](#the-async-web-server)
- - [Request Life Cycle](#request-life-cycle)
- - [Rewrites and how do they work](#rewrites-and-how-do-they-work)
- - [Handlers and how do they work](#handlers-and-how-do-they-work)
- - [Responses and how do they work](#responses-and-how-do-they-work)
- - [Template processing](#template-processing)
- - [Request Variables](#request-variables)
- - [Common Variables](#common-variables)
- - [Headers](#headers)
- - [GET, POST and FILE parameters](#get-post-and-file-parameters)
- - [JSON body handling with ArduinoJson](#json-body-handling-with-arduinojson)
- - [Responses](#responses)
- - [Redirect to another URL](#redirect-to-another-url)
- - [Basic response with HTTP Code](#basic-response-with-http-code)
- - [Basic response with HTTP Code and extra headers](#basic-response-with-http-code-and-extra-headers)
- - [Basic response with string content](#basic-response-with-string-content)
- - [Basic response with string content and extra headers](#basic-response-with-string-content-and-extra-headers)
- - [Respond with content coming from a Stream](#respond-with-content-coming-from-a-stream)
- - [Respond with content coming from a Stream and extra headers](#respond-with-content-coming-from-a-stream-and-extra-headers)
- - [Respond with content coming from a Stream containing templates](#respond-with-content-coming-from-a-stream-containing-templates)
- - [Respond with content coming from a Stream containing templates and extra headers](#respond-with-content-coming-from-a-stream-containing-templates-and-extra-headers)
- - [Respond with content using a callback](#respond-with-content-using-a-callback)
- - [Respond with content using a callback and extra headers](#respond-with-content-using-a-callback-and-extra-headers)
- - [Respond with content using a callback containing templates](#respond-with-content-using-a-callback-containing-templates)
- - [Respond with content using a callback containing templates and extra headers](#respond-with-content-using-a-callback-containing-templates-and-extra-headers)
- - [Chunked Response](#chunked-response)
- - [Chunked Response containing templates](#chunked-response-containing-templates)
- - [Print to response](#print-to-response)
- - [ArduinoJson Basic Response](#arduinojson-basic-response)
- - [ArduinoJson Advanced Response](#arduinojson-advanced-response)
- - [Param Rewrite With Matching](#param-rewrite-with-matching)
- - [Using filters](#using-filters)
- - [Bad Responses](#bad-responses)
- - [Respond with content using a callback without content length to HTTP/1.0 clients](#respond-with-content-using-a-callback-without-content-length-to-http10-clients)
- - [Async WebSocket Plugin](#async-websocket-plugin)
- - [Async WebSocket Event](#async-websocket-event)
- - [Methods for sending data to a socket client](#methods-for-sending-data-to-a-socket-client)
- - [Direct access to web socket message buffer](#direct-access-to-web-socket-message-buffer)
- - [Limiting the number of web socket clients](#limiting-the-number-of-web-socket-clients)
- - [Async Event Source Plugin](#async-event-source-plugin)
- - [Setup Event Source on the server](#setup-event-source-on-the-server)
- - [Setup Event Source in the browser](#setup-event-source-in-the-browser)
- - [Remove handlers and rewrites](#remove-handlers-and-rewrites)
- - [Setting up the server](#setting-up-the-server)
- - [Setup global and class functions as request handlers](#setup-global-and-class-functions-as-request-handlers)
- - [Methods for controlling websocket connections](#methods-for-controlling-websocket-connections)
- - [Adding Default Headers](#adding-default-headers)
- - [Path variable](#path-variable)
---
---
-## Why should you care
-
-- Using asynchronous network means that you can handle **more than one connection at the same time**
-- You are called once the request is ready and parsed
-- When you send the response, you are **immediately ready** to handle other connections while the server is taking care of sending the response in the background
-- **Speed is OMG**
-- **Easy to use API, HTTP Basic and Digest MD5 Authentication (default), ChunkedResponse**
-- Easily extensible to handle **any type of content**
-- Supports Continue 100
-- Async WebSocket plugin offering different locations without extra servers or ports
-- Async EventSource (Server-Sent Events) plugin to send events to the browser
-- URL Rewrite plugin for conditional and permanent url rewrites
-- ServeStatic plugin that supports cache, Last-Modified, default index and more
-- Simple template processing engine to handle templates
-
----
-
## Important things to remember
- This is fully asynchronous server and as such does not run on the loop thread.
@@ -1309,12 +1365,16 @@ build_flags =
2. [AsyncFSBrowser_STM32](examples/AsyncFSBrowser_STM32)
3. [Async_HelloServer](examples/Async_HelloServer)
4. [Async_HelloServer2](examples/Async_HelloServer2)
- 5. [Async_PostServer](examples/Async_PostServer)
- 6. [Async_RegexPatterns_STM32](examples/Async_RegexPatterns_STM32)
- 7. [Async_SimpleWebServer_STM32](examples/Async_SimpleWebServer_STM32)
- 8. [WebClient](examples/WebClient)
- 9. [WebClientRepeating](examples/WebClientRepeating)
-10. [Async_HttpBasicAuth](examples/Async_HttpBasicAuth)
+ 5. [Async_HttpBasicAuth](examples/Async_HttpBasicAuth)
+ 6. [Async_PostServer](examples/Async_PostServer)
+ 7. [**AsyncMultiWebServer_STM32**](examples/AsyncMultiWebServer_STM32)
+ 8. [Async_RegexPatterns_STM32](examples/Async_RegexPatterns_STM32)
+ 9. [Async_SimpleWebServer_STM32](examples/Async_SimpleWebServer_STM32)
+10. [**MQTTClient_Auth**](examples/MQTTClient_Auth)
+11. [**MQTTClient_Basic**](examples/MQTTClient_Basic)
+12. [**MQTT_ThingStream**](examples/MQTT_ThingStream)
+13. [WebClient](examples/WebClient)
+14. [WebClientRepeating](examples/WebClientRepeating)
---
@@ -1389,6 +1449,8 @@ build_flags =
#define BOARD_NAME BOARD_TYPE
#endif
+#define SHIELD_TYPE "LAN8742A built-in Ethernet"
+
#include
#include
#include
@@ -1515,7 +1577,9 @@ void setup(void)
digitalWrite(led, 0);
Serial.begin(115200);
- Serial.println("\nStart Async_AdvancedWebServer_STM32 on " + String(BOARD_NAME));
+
+ Serial.printf("\nStarting Async_AdvancedWebServer_STM32 on %s with %s\n", BOARD_NAME, SHIELD_TYPE);
+ Serial.println(ASYNC_WEBSERVER_STM32_VERSION);
// start the ethernet connection and the server
// Use random mac
@@ -1560,15 +1624,206 @@ You can access the Async Advanced WebServer @ the server IP
+---
+---
+
+### Debug Termimal Output Samples
+
+#### 1. AsyncMultiWebServer_STM32 on NUCLEO_F767ZI using Built-in LAN8742A Ethernet and STM32Ethernet Library
+
+Following are debug terminal output and screen shots when running example [AsyncMultiWebServer_STM32](examples/AsyncMultiWebServer_STM32) on STM32F7 Nucleo-144 NUCLEO_F767ZI using Built-in LAN8742A Ethernet and STM32Ethernet Library to demonstrate the operation of 3 independent AsyncWebServers on 3 different ports and how to handle the complicated AsyncMultiWebServers.
+
+
+```
+Starting AsyncMultiWebServer_STM32 on NUCLEO_F767ZI with LAN8742A built-in Ethernet
+AsyncWebServer_STM32 v1.2.5
+
+Connected to network. IP = 192.168.2.141
+Initialize multiServer OK, serverIndex = 0, port = 8080
+HTTP server started at ports 8080
+Initialize multiServer OK, serverIndex = 1, port = 8081
+HTTP server started at ports 8081
+Initialize multiServer OK, serverIndex = 2, port = 8082
+HTTP server started at ports 8082
+```
+
+You can access the Async Advanced WebServers @ the server IP and corresponding ports (8080, 8081 and 8082)
+
+
+
+
+
+
+
+
+
+
+
+
+
---
+#### 2. WebClient on NUCLEO_F767ZI using Built-in LAN8742A Ethernet and STM32Ethernet Library
+
+Following is debug terminal output when running example [WebClient](examples/WebClient) on STM32F7 Nucleo-144 NUCLEO_F767ZI using Built-in LAN8742A Ethernet and STM32Ethernet Library.
+
+```
+Starting WebClient on NUCLEO_F767ZI with LAN8742A built-in Ethernet
+AsyncWebServer_STM32 v1.2.5
+You're connected to the network, IP = 192.168.2.71
+
+Starting connection to server...
+Connected to server
+HTTP/1.1 200 OK
+Server: nginx/1.4.2
+Date: Mon, 28 Dec 2020 22:30:39 GMT
+Content-Type: text/plain
+Content-Length: 2263
+Last-Modified: Wed, 02 Oct 2013 13:46:47 GMT
+Connection: close
+Vary: Accept-Encoding
+ETag: "524c23c7-8d7"
+Accept-Ranges: bytes
+
+
+ `:;;;,` .:;;:.
+ .;;;;;;;;;;;` :;;;;;;;;;;: TM
+ `;;;;;;;;;;;;;;;` :;;;;;;;;;;;;;;;
+ :;;;;;;;;;;;;;;;;;; `;;;;;;;;;;;;;;;;;;
+ ;;;;;;;;;;;;;;;;;;;;; .;;;;;;;;;;;;;;;;;;;;
+ ;;;;;;;;:` `;;;;;;;;; ,;;;;;;;;.` .;;;;;;;;
+ .;;;;;;, :;;;;;;; .;;;;;;; ;;;;;;;
+ ;;;;;; ;;;;;;; ;;;;;;, ;;;;;;.
+ ,;;;;; ;;;;;;.;;;;;;` ;;;;;;
+ ;;;;;. ;;;;;;;;;;;` ``` ;;;;;`
+ ;;;;; ;;;;;;;;;, ;;; .;;;;;
+`;;;;: `;;;;;;;; ;;; ;;;;;
+,;;;;` `,,,,,,,, ;;;;;;; .,,;;;,,, ;;;;;
+:;;;;` .;;;;;;;; ;;;;;, :;;;;;;;; ;;;;;
+:;;;;` .;;;;;;;; `;;;;;; :;;;;;;;; ;;;;;
+.;;;;. ;;;;;;;. ;;; ;;;;;
+ ;;;;; ;;;;;;;;; ;;; ;;;;;
+ ;;;;; .;;;;;;;;;; ;;; ;;;;;,
+ ;;;;;; `;;;;;;;;;;;; ;;;;;
+ `;;;;;, .;;;;;; ;;;;;;; ;;;;;;
+ ;;;;;;: :;;;;;;. ;;;;;;; ;;;;;;
+ ;;;;;;;` .;;;;;;;, ;;;;;;;; ;;;;;;;:
+ ;;;;;;;;;:,:;;;;;;;;;: ;;;;;;;;;;:,;;;;;;;;;;
+ `;;;;;;;;;;;;;;;;;;;. ;;;;;;;;;;;;;;;;;;;;
+ ;;;;;;;;;;;;;;;;; :;;;;;;;;;;;;;;;;:
+ ,;;;;;;;;;;;;;, ;;;;;;;;;;;;;;
+ .;;;;;;;;;` ,;;;;;;;;:
+
+
+
+
+ ;;; ;;;;;` ;;;;: .;; ;; ,;;;;;, ;;. `;, ;;;;
+ ;;; ;;:;;; ;;;;;; .;; ;; ,;;;;;: ;;; `;, ;;;:;;
+ ,;:; ;; ;; ;; ;; .;; ;; ,;, ;;;,`;, ;; ;;
+ ;; ;: ;; ;; ;; ;; .;; ;; ,;, ;;;;`;, ;; ;;.
+ ;: ;; ;;;;;: ;; ;; .;; ;; ,;, ;;`;;;, ;; ;;`
+ ,;;;;; ;;`;; ;; ;; .;; ;; ,;, ;; ;;;, ;; ;;
+ ;; ,;, ;; .;; ;;;;;: ;;;;;: ,;;;;;: ;; ;;, ;;;;;;
+ ;; ;; ;; ;;` ;;;;. `;;;: ,;;;;;, ;; ;;, ;;;;
+
+Disconnecting from server...
+```
+
---
+
+#### 3. MQTTClient_Auth on NUCLEO_F767ZI using Built-in LAN8742A Ethernet and STM32Ethernet Library
+
+Following is debug terminal output when running example [MQTTClient_Auth](examples/MQTTClient_Auth) on STM32F7 Nucleo-144 NUCLEO_F767ZI using Built-in LAN8742A Ethernet and STM32Ethernet Library.
+
+```
+Starting MQTTClient_Auth on NUCLEO_F767ZI with LAN8742A built-in Ethernet
+AsyncWebServer_STM32 v1.2.5
+
+Connected to network. IP = 192.168.2.71
+Attempting MQTT connection to broker.emqx.io...connected
+Message Send : MQTT_Pub => Hello from MQTTClient_Auth on NUCLEO_F767ZI with LAN8742A built-in Ethernet
+Message arrived [MQTT_Pub] Hello from MQTTClient_Auth on NUCLEO_F767ZI with LAN8742A built-in Ethernet
+Message Send : MQTT_Pub => Hello from MQTTClient_Auth on NUCLEO_F767ZI with LAN8742A built-in Ethernet
+Message arrived [MQTT_Pub] Hello from MQTTClient_Auth on NUCLEO_F767ZI with LAN8742A built-in Ethernet
+```
+
+---
+
+#### 4. MQTTClient_Basic on NUCLEO_F767ZI using Built-in LAN8742A Ethernet and STM32Ethernet Library
+
+Following is debug terminal output when running example [MQTTClient_Basic](examples/MQTTClient_Basic) on STM32F7 Nucleo-144 NUCLEO_F767ZI using Built-in LAN8742A Ethernet and STM32Ethernet Library.
+
+```
+Starting MQTTClient_Basic on NUCLEO_F767ZI with LAN8742A built-in Ethernet
+AsyncWebServer_STM32 v1.2.5
+
+Connected to network. IP = 192.168.2.71
+Attempting MQTT connection to broker.shiftr.io...connected
+Message Send : MQTT_Pub => Hello from MQTTClient_Basic on NUCLEO_F767ZI with LAN8742A built-in Ethernet
+Message arrived [MQTT_Pub] Hello from MQTTClient_Basic on NUCLEO_F767ZI with LAN8742A built-in Ethernet
+Message Send : MQTT_Pub => Hello from MQTTClient_Basic on NUCLEO_F767ZI with LAN8742A built-in Ethernet
+Message arrived [MQTT_Pub] Hello from MQTTClient_Basic on NUCLEO_F767ZI with LAN8742A built-in Ethernet
+Message Send : MQTT_Pub => Hello from MQTTClient_Basic on NUCLEO_F767ZI with LAN8742A built-in Ethernet
+Message arrived [MQTT_Pub] Hello from MQTTClient_Basic on NUCLEO_F767ZI with LAN8742A built-in Ethernet
+Message Send : MQTT_Pub => Hello from MQTTClient_Basic on NUCLEO_F767ZI with LAN8742A built-in Ethernet
+Message arrived [MQTT_Pub] Hello from MQTTClient_Basic on NUCLEO_F767ZI with LAN8742A built-in Ethernet
+Message Send : MQTT_Pub => Hello from MQTTClient_Basic on NUCLEO_F767ZI with LAN8742A built-in Ethernet
+Message arrived [MQTT_Pub] Hello from MQTTClient_Basic on NUCLEO_F767ZI with LAN8742A built-in Ethernet
+Message Send : MQTT_Pub => Hello from MQTTClient_Basic on NUCLEO_F767ZI with LAN8742A built-in Ethernet
+Message arrived [MQTT_Pub] Hello from MQTTClient_Basic on NUCLEO_F767ZI with LAN8742A built-in Ethernet
+```
+
+---
+
+#### 5. MQTT_ThingStream on NUCLEO_F767ZI using Built-in LAN8742A Ethernet and STM32Ethernet Library
+
+Following is debug terminal output when running example [MQTT_ThingStream](examples/MQTT_ThingStream) on STM32F7 Nucleo-144 NUCLEO_F767ZI using Built-in LAN8742A Ethernet and STM32Ethernet Library.
+
+```
+Starting MQTT_ThingStream on NUCLEO_F767ZI with LAN8742A built-in Ethernet
+AsyncWebServer_STM32 v1.2.5
+
+Connected to network. IP = 192.168.2.71
+***************************************
+STM32_Pub
+***************************************
+Attempting MQTT connection to broker.emqx.io
+...connected
+Published connection message successfully!
+Subcribed to: STM32_Sub
+MQTT Message Send : STM32_Pub => Hello from MQTT_ThingStream on NUCLEO_F767ZI with LAN8742A built-in Ethernet
+MQTT Message receive [STM32_Pub] Hello from MQTT_ThingStream on NUCLEO_F767ZI with LAN8742A built-in Ethernet
+MQTT Message Send : STM32_Pub => Hello from MQTT_ThingStream on NUCLEO_F767ZI with LAN8742A built-in Ethernet
+MQTT Message receive [STM32_Pub] Hello from MQTT_ThingStream on NUCLEO_F767ZI with LAN8742A built-in Ethernet
+MQTT Message Send : STM32_Pub => Hello from MQTT_ThingStream on NUCLEO_F767ZI with LAN8742A built-in Ethernet
+MQTT Message receive [STM32_Pub] Hello from MQTT_ThingStream on NUCLEO_F767ZI with LAN8742A built-in Ethernet
+MQTT Message Send : STM32_Pub => Hello from MQTT_ThingStream on NUCLEO_F767ZI with LAN8742A built-in Ethernet
+MQTT Message receive [STM32_Pub] Hello from MQTT_ThingStream on NUCLEO_F767ZI with LAN8742A built-in Ethernet
+MQTT Message Send : STM32_Pub => Hello from MQTT_ThingStream on NUCLEO_F767ZI with LAN8742A built-in Ethernet
+MQTT Message receive [STM32_Pub] Hello from MQTT_ThingStream on NUCLEO_F767ZI with LAN8742A built-in Ethernet
+```
+
+---
+---
+
+### Debug
+
+Debug is enabled by default on Serial. Debug Level from 0 to 4. To disable, change the _ETHERNET_WEBSERVER_LOGLEVEL_ to 0
+
+```cpp
+// Use this to output debug msgs to Serial
+#define ASYNCWEBSERVER_STM32_DEBUG_PORT Serial
+// Use this to disable all output debug msgs
+// Debug Level from 0 to 4
+#define _ASYNCWEBSERVER_STM32_LOGLEVEL_ 0
+```
+
### Troubleshooting
If you get compilation errors, more often than not, you may need to install a newer version of Arduino IDE, the Arduino `STM32` core or depending libraries.
-Sometimes, the library will only work if you update the `STM32` core to the latest version because I am always using the latest cores /libraries.
+Sometimes, the library will only work if you update the `STM32` core to the latest version because I'm always using the latest cores /libraries.
If you connect to the created configuration Access Point but the ConfigPortal does not show up, just open a browser and type in the IP of the web portal, by default `192.168.4.1`.
@@ -1600,6 +1855,15 @@ Submit issues to: [AsyncWebServer_STM32 issues](https://github.com/khoih-prog/As
---
---
+## Releases
+
+### Releases v1.2.5
+
+1. Clean-up all compiler warnings possible.
+2. Update Table of Contents
+3. Add examples
+4. Add Version String
+
### Releases v1.2.4
1. Add back MD5/SHA1 authentication feature.
@@ -1618,7 +1882,7 @@ Submit issues to: [AsyncWebServer_STM32 issues](https://github.com/khoih-prog/As
2. Discovery STM32F746G-DISCOVERY
3. Any STM32 boards with enough flash/memory and already configured to run LAN8742A Ethernet.
----
+
---
This library is based on, modified from:
@@ -1627,6 +1891,7 @@ This library is based on, modified from:
to apply the better and faster **asynchronous** feature of the **great** [ESPAsyncWebServer Library](https://github.com/me-no-dev/ESPAsyncWebServer) into STM32 boards using builtin LAN8742A Ethernet.
+---
---
### Contributions and Thanks
@@ -1658,7 +1923,7 @@ If you want to contribute to this project:
---
-### License and credits ###
+### License
- The library is licensed under [MIT](https://github.com/khoih-prog/AsyncWebServer_STM32/blob/master/LICENSE)
diff --git a/examples/AsyncFSBrowser_STM32/AsyncFSBrowser_STM32.ino b/examples/AsyncFSBrowser_STM32/AsyncFSBrowser_STM32.ino
index 6651f54..7a269bc 100644
--- a/examples/AsyncFSBrowser_STM32/AsyncFSBrowser_STM32.ino
+++ b/examples/AsyncFSBrowser_STM32/AsyncFSBrowser_STM32.ino
@@ -9,13 +9,14 @@
Built by Khoi Hoang https://github.com/khoih-prog/AsyncWebServer_STM32
Licensed under MIT license
- Version: 1.2.4
+ Version: 1.2.5
Version Modified By Date Comments
------- ----------- ---------- -----------
1.2.3 K Hoang 02/09/2020 Initial coding for STM32 for built-in Ethernet (Nucleo-144, DISCOVERY, etc).
Bump up version to v1.2.3 to sync with ESPAsyncWebServer v1.2.3
1.2.4 K Hoang 05/09/2020 Add back MD5/SHA1 authentication feature.
+ 1.2.5 K Hoang 28/12/2020 Suppress all possible compiler warnings. Add examples.
*****************************************************************************************************************************/
/*
Currently support
@@ -83,6 +84,8 @@
#define BOARD_NAME BOARD_TYPE
#endif
+#define SHIELD_TYPE "LAN8742A built-in Ethernet"
+
#include
#include
#include
@@ -126,7 +129,7 @@ void onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventT
if (type == WS_EVT_CONNECT)
{
Serial.printf("ws[%s][%u] connect\n", server->url(), client->id());
- client->printf("Hello Client %u :)", client->id());
+ client->printf("Hello Client %lu :)", client->id());
client->ping();
}
else if (type == WS_EVT_DISCONNECT)
@@ -160,7 +163,7 @@ void onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventT
}
else
{
- char buff[3];
+ char buff[6];
for (size_t i = 0; i < info->len; i++)
{
@@ -199,7 +202,7 @@ void onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventT
}
else
{
- char buff[3];
+ char buff[6];
for (size_t i = 0; i < len; i++)
{
@@ -237,7 +240,8 @@ void setup()
Serial.begin(115200);
while (!Serial);
- Serial.println("\nStarting AsyncFSBrowser_STM32 on " + String(BOARD_NAME));
+ Serial.printf("\nStarting AsyncFSBrowser_STM32 on %s with %s\n", BOARD_NAME, SHIELD_TYPE);
+ Serial.println(ASYNC_WEBSERVER_STM32_VERSION);
// start the ethernet connection and the server
// Use random mac
@@ -320,6 +324,8 @@ void setup()
server.onRequestBody([](AsyncWebServerRequest * request, uint8_t *data, size_t len, size_t index, size_t total)
{
+ AWS_STM32_UNUSED(request);
+
if (!index)
Serial.printf("BodyStart: %u\n", total);
diff --git a/examples/AsyncMultiWebServer_STM32/AsyncMultiWebServer_STM32.ino b/examples/AsyncMultiWebServer_STM32/AsyncMultiWebServer_STM32.ino
new file mode 100644
index 0000000..1805a3c
--- /dev/null
+++ b/examples/AsyncMultiWebServer_STM32/AsyncMultiWebServer_STM32.ino
@@ -0,0 +1,272 @@
+/****************************************************************************************************************************
+ AsyncMultiWebServer_STM32.h - Dead simple AsyncWebServer for STM32 built-in LAN8742A Ethernet
+
+ For STM32 with built-in LAN8742A Ethernet (Nucleo-144, DISCOVERY, etc)
+
+ AsyncWebServer_STM32 is a library for the STM32 run built-in Ethernet WebServer
+
+ Based on and modified from ESPAsyncWebServer (https://github.com/me-no-dev/ESPAsyncWebServer)
+ Built by Khoi Hoang https://github.com/khoih-prog/AsyncWebServer_STM32
+ Licensed under MIT license
+
+ Version: 1.2.5
+
+ Version Modified By Date Comments
+ ------- ----------- ---------- -----------
+ 1.2.3 K Hoang 02/09/2020 Initial coding for STM32 for built-in Ethernet (Nucleo-144, DISCOVERY, etc).
+ Bump up version to v1.2.3 to sync with ESPAsyncWebServer v1.2.3
+ 1.2.4 K Hoang 05/09/2020 Add back MD5/SHA1 authentication feature.
+ 1.2.5 K Hoang 28/12/2020 Suppress all possible compiler warnings. Add examples.
+ *****************************************************************************************************************************/
+/*
+ Currently support
+ 1) STM32 boards with built-in Ethernet (to use USE_BUILTIN_ETHERNET = true) such as :
+ - Nucleo-144 (F429ZI, F767ZI)
+ - Discovery (STM32F746G-DISCOVERY)
+ - STM32 boards (STM32F/L/H/G/WB/MP1) with 32K+ Flash, with Built-in Ethernet,
+ - See How To Use Built-in Ethernet at (https://github.com/khoih-prog/EthernetWebServer_STM32/issues/1)
+*/
+
+#if !( defined(STM32F0) || defined(STM32F1) || defined(STM32F2) || defined(STM32F3) ||defined(STM32F4) || defined(STM32F7) || \
+ defined(STM32L0) || defined(STM32L1) || defined(STM32L4) || defined(STM32H7) ||defined(STM32G0) || defined(STM32G4) || \
+ defined(STM32WB) || defined(STM32MP1) )
+ #error This code is designed to run on STM32F/L/H/G/WB/MP1 platform! Please check your Tools->Board setting.
+#endif
+
+#if defined(STM32F0)
+ #warning STM32F0 board selected
+ #define BOARD_TYPE "STM32F0"
+#elif defined(STM32F1)
+ #warning STM32F1 board selected
+ #define BOARD_TYPE "STM32F1"
+#elif defined(STM32F2)
+ #warning STM32F2 board selected
+ #define BOARD_TYPE "STM32F2"
+#elif defined(STM32F3)
+ #warning STM32F3 board selected
+ #define BOARD_TYPE "STM32F3"
+#elif defined(STM32F4)
+ #warning STM32F4 board selected
+ #define BOARD_TYPE "STM32F4"
+#elif defined(STM32F7)
+ #warning STM32F7 board selected
+ #define BOARD_TYPE "STM32F7"
+#elif defined(STM32L0)
+ #warning STM32L0 board selected
+ #define BOARD_TYPE "STM32L0"
+#elif defined(STM32L1)
+ #warning STM32L1 board selected
+ #define BOARD_TYPE "STM32L1"
+#elif defined(STM32L4)
+ #warning STM32L4 board selected
+ #define BOARD_TYPE "STM32L4"
+#elif defined(STM32H7)
+ #warning STM32H7 board selected
+ #define BOARD_TYPE "STM32H7"
+#elif defined(STM32G0)
+ #warning STM32G0 board selected
+ #define BOARD_TYPE "STM32G0"
+#elif defined(STM32G4)
+ #warning STM32G4 board selected
+ #define BOARD_TYPE "STM32G4"
+#elif defined(STM32WB)
+ #warning STM32WB board selected
+ #define BOARD_TYPE "STM32WB"
+#elif defined(STM32MP1)
+ #warning STM32MP1 board selected
+ #define BOARD_TYPE "STM32MP1"
+#else
+ #warning STM32 unknown board selected
+ #define BOARD_TYPE "STM32 Unknown"
+#endif
+
+#ifndef BOARD_NAME
+ #define BOARD_NAME BOARD_TYPE
+#endif
+
+#define SHIELD_TYPE "LAN8742A built-in Ethernet"
+
+#include
+#include
+#include
+
+// Enter a MAC address and IP address for your controller below.
+#define NUMBER_OF_MAC 20
+
+byte mac[][NUMBER_OF_MAC] =
+{
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x01 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x02 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x03 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x04 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x05 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x06 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x07 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x08 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x09 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x0A },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x0B },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x0C },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x0D },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x0E },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x0F },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x10 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x11 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x12 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x13 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x14 },
+};
+// Select the IP address according to your local network
+IPAddress ip(192, 168, 2, 232);
+
+unsigned int analogReadPin [] = { 12, 13, 14 };
+
+#define BUFFER_SIZE 500
+
+#define HTTP_PORT1 8080
+#define HTTP_PORT2 8081
+#define HTTP_PORT3 8082
+
+AsyncWebServer* server1;
+AsyncWebServer* server2;
+AsyncWebServer* server3;
+
+AsyncWebServer* multiServer [] = { server1, server2, server3 };
+uint16_t http_port [] = { HTTP_PORT1, HTTP_PORT2, HTTP_PORT3 };
+
+#define NUM_SERVERS ( sizeof(multiServer) / sizeof(AsyncWebServer*) )
+
+unsigned int serverIndex;
+
+String createBuffer()
+{
+ char temp[BUFFER_SIZE];
+
+ memset(temp, 0, sizeof(temp));
+
+ int sec = millis() / 1000;
+ int min = sec / 60;
+ int hr = min / 60;
+ int day = hr / 24;
+
+ snprintf(temp, BUFFER_SIZE - 1,
+ "\
+\
+\
+%s\
+\
+\
+\
+Hello from %s
\
+running AsyncWebServer_STM32
\
+on %s
\
+Uptime: %d d %02d:%02d:%02d
\
+\
+", BOARD_NAME, BOARD_NAME, "Built-in LAN8742A", day, hr, min % 60, sec % 60);
+
+ return temp;
+}
+
+
+void handleRoot(AsyncWebServerRequest * request)
+{
+ String message = createBuffer();
+ request->send(200, F("text/html"), message);
+}
+
+String createNotFoundBuffer(AsyncWebServerRequest * request)
+{
+ String message;
+
+ message.reserve(500);
+
+ message = F("File Not Found\n\n");
+
+ message += F("URI: ");
+ message += request->url();
+ message += F("\nMethod: ");
+ message += (request->method() == HTTP_GET) ? F("GET") : F("POST");
+ message += F("\nArguments: ");
+ message += request->args();
+ message += F("\n");
+
+ for (uint8_t i = 0; i < request->args(); i++)
+ {
+ message += " " + request->argName(i) + ": " + request->arg(i) + "\n";
+ }
+
+ return message;
+}
+
+void handleNotFound(AsyncWebServerRequest * request)
+{
+ String message = createNotFoundBuffer(request);
+ request->send(404, F("text/plain"), message);
+}
+
+void setup()
+{
+ Serial.begin(115200);
+ while (!Serial);
+
+ delay(200);
+
+ Serial.printf("\nStarting AsyncMultiWebServer_STM32 on %s with %s\n", BOARD_NAME, SHIELD_TYPE);
+ Serial.println(ASYNC_WEBSERVER_STM32_VERSION);
+
+ // start the ethernet connection and the server
+ // Use random mac
+ uint16_t index = millis() % NUMBER_OF_MAC;
+
+ // Use Static IP
+ //Ethernet.begin(mac[index], ip);
+ // Use DHCP dynamic IP and random mac
+ Ethernet.begin(mac[index]);
+
+ Serial.print("\nConnected to network. IP = ");
+ Serial.println(Ethernet.localIP());
+
+ for (serverIndex = 0; serverIndex < NUM_SERVERS; serverIndex++)
+ {
+ multiServer[serverIndex] = new AsyncWebServer(http_port[serverIndex]);
+
+ if (multiServer[serverIndex])
+ {
+ Serial.printf("Initialize multiServer OK, serverIndex = %d, port = %d\n", serverIndex, http_port[serverIndex]);
+ }
+ else
+ {
+ Serial.printf("Error initialize multiServer, serverIndex = %d\n", serverIndex);
+
+ while(1);
+ }
+
+ multiServer[serverIndex]->on("/", HTTP_GET, [](AsyncWebServerRequest * request)
+ {
+ handleRoot(request);
+ });
+
+ multiServer[serverIndex]->on("/hello", HTTP_GET, [](AsyncWebServerRequest * request)
+ {
+ String message = F("Hello from AsyncWebServer using built-in LAN8742A Ethernet, running on ");
+ message += BOARD_NAME;
+
+ request->send(200, "text/plain", message);
+ });
+
+ multiServer[serverIndex]->onNotFound([](AsyncWebServerRequest * request)
+ {
+ handleNotFound(request);
+ });
+
+ multiServer[serverIndex]->begin();
+
+ Serial.printf("HTTP server started at ports %d\n", http_port[serverIndex]);
+ }
+}
+
+void loop()
+{
+}
diff --git a/examples/Async_AdvancedWebServer/Async_AdvancedWebServer.ino b/examples/Async_AdvancedWebServer/Async_AdvancedWebServer.ino
index 6fdc82a..dfda7db 100644
--- a/examples/Async_AdvancedWebServer/Async_AdvancedWebServer.ino
+++ b/examples/Async_AdvancedWebServer/Async_AdvancedWebServer.ino
@@ -37,13 +37,14 @@
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- Version: 1.2.4
+ Version: 1.2.5
Version Modified By Date Comments
------- ----------- ---------- -----------
1.2.3 K Hoang 02/09/2020 Initial coding for STM32 for built-in Ethernet (Nucleo-144, DISCOVERY, etc).
Bump up version to v1.2.3 to sync with ESPAsyncWebServer v1.2.3
1.2.4 K Hoang 05/09/2020 Add back MD5/SHA1 authentication feature.
+ 1.2.5 K Hoang 28/12/2020 Suppress all possible compiler warnings. Add examples.
*****************************************************************************************************************************/
/*
Currently support
@@ -60,7 +61,7 @@
#error This code is designed to run on STM32F/L/H/G/WB/MP1 platform! Please check your Tools->Board setting.
#endif
-#define _ASYNCWEBSERVER_STM32_LOGLEVEL_ 3
+#define _ASYNCWEBSERVER_STM32_LOGLEVEL_ 4
#if defined(STM32F0)
#warning STM32F0 board selected
@@ -113,6 +114,8 @@
#define BOARD_NAME BOARD_TYPE
#endif
+#define SHIELD_TYPE "LAN8742A built-in Ethernet"
+
#include
#include
#include
@@ -239,7 +242,9 @@ void setup(void)
digitalWrite(led, 0);
Serial.begin(115200);
- Serial.println("\nStart Async_AdvancedWebServer_STM32 on " + String(BOARD_NAME));
+
+ Serial.printf("\nStarting Async_AdvancedWebServer_STM32 on %s with %s\n", BOARD_NAME, SHIELD_TYPE);
+ Serial.println(ASYNC_WEBSERVER_STM32_VERSION);
// start the ethernet connection and the server
// Use random mac
diff --git a/examples/Async_HelloServer/Async_HelloServer.ino b/examples/Async_HelloServer/Async_HelloServer.ino
index 593791b..2f73035 100644
--- a/examples/Async_HelloServer/Async_HelloServer.ino
+++ b/examples/Async_HelloServer/Async_HelloServer.ino
@@ -9,13 +9,14 @@
Built by Khoi Hoang https://github.com/khoih-prog/AsyncWebServer_STM32
Licensed under MIT license
- Version: 1.2.4
+ Version: 1.2.5
Version Modified By Date Comments
------- ----------- ---------- -----------
1.2.3 K Hoang 02/09/2020 Initial coding for STM32 for built-in Ethernet (Nucleo-144, DISCOVERY, etc).
Bump up version to v1.2.3 to sync with ESPAsyncWebServer v1.2.3
1.2.4 K Hoang 05/09/2020 Add back MD5/SHA1 authentication feature.
+ 1.2.5 K Hoang 28/12/2020 Suppress all possible compiler warnings. Add examples.
*****************************************************************************************************************************/
/*
Currently support
@@ -83,6 +84,8 @@
#define BOARD_NAME BOARD_TYPE
#endif
+#define SHIELD_TYPE "LAN8742A built-in Ethernet"
+
#include
#include
#include
@@ -156,7 +159,9 @@ void setup(void)
digitalWrite(led, 0);
Serial.begin(115200);
- Serial.println("\nStart Async_HelloServer on " + String(BOARD_NAME));
+
+ Serial.printf("\nStarting Async_HelloServer on %s with %s\n", BOARD_NAME, SHIELD_TYPE);
+ Serial.println(ASYNC_WEBSERVER_STM32_VERSION);
// start the ethernet connection and the server
// Use random mac
diff --git a/examples/Async_HelloServer2/Async_HelloServer2.ino b/examples/Async_HelloServer2/Async_HelloServer2.ino
index a7a74c6..cd4c6cf 100644
--- a/examples/Async_HelloServer2/Async_HelloServer2.ino
+++ b/examples/Async_HelloServer2/Async_HelloServer2.ino
@@ -9,13 +9,14 @@
Built by Khoi Hoang https://github.com/khoih-prog/AsyncWebServer_STM32
Licensed under MIT license
- Version: 1.2.4
+ Version: 1.2.5
Version Modified By Date Comments
------- ----------- ---------- -----------
1.2.3 K Hoang 02/09/2020 Initial coding for STM32 for built-in Ethernet (Nucleo-144, DISCOVERY, etc).
Bump up version to v1.2.3 to sync with ESPAsyncWebServer v1.2.3
1.2.4 K Hoang 05/09/2020 Add back MD5/SHA1 authentication feature.
+ 1.2.5 K Hoang 28/12/2020 Suppress all possible compiler warnings. Add examples.
*****************************************************************************************************************************/
/*
Currently support
@@ -83,6 +84,8 @@
#define BOARD_NAME BOARD_TYPE
#endif
+#define SHIELD_TYPE "LAN8742A built-in Ethernet"
+
#include
#include
#include
@@ -156,7 +159,9 @@ void setup(void)
digitalWrite(led, 0);
Serial.begin(115200);
- Serial.println("\nStart Async_HelloServer2 on " + String(BOARD_NAME));
+
+ Serial.printf("\nStarting Async_HelloServer2 on %s with %s\n", BOARD_NAME, SHIELD_TYPE);
+ Serial.println(ASYNC_WEBSERVER_STM32_VERSION);
// start the ethernet connection and the server
// Use random mac
diff --git a/examples/Async_HttpBasicAuth/Async_HttpBasicAuth.ino b/examples/Async_HttpBasicAuth/Async_HttpBasicAuth.ino
index 1416daa..d78942e 100644
--- a/examples/Async_HttpBasicAuth/Async_HttpBasicAuth.ino
+++ b/examples/Async_HttpBasicAuth/Async_HttpBasicAuth.ino
@@ -9,13 +9,14 @@
Built by Khoi Hoang https://github.com/khoih-prog/AsyncWebServer_STM32
Licensed under MIT license
- Version: 1.2.4
+ Version: 1.2.5
Version Modified By Date Comments
------- ----------- ---------- -----------
1.2.3 K Hoang 02/09/2020 Initial coding for STM32 for built-in Ethernet (Nucleo-144, DISCOVERY, etc).
Bump up version to v1.2.3 to sync with ESPAsyncWebServer v1.2.3
1.2.4 K Hoang 05/09/2020 Add back MD5/SHA1 authentication feature.
+ 1.2.5 K Hoang 28/12/2020 Suppress all possible compiler warnings. Add examples.
*****************************************************************************************************************************/
/*
Currently support
@@ -86,6 +87,8 @@
#define BOARD_NAME BOARD_TYPE
#endif
+#define SHIELD_TYPE "LAN8742A built-in Ethernet"
+
#include
#include
#include
@@ -127,8 +130,9 @@ const char* www_password = "ethernet";
void setup()
{
Serial.begin(115200);
- delay(1000);
- Serial.println("\nStart Async_HTTPBasicAuth on " + String(BOARD_NAME));
+
+ Serial.printf("\nStarting Async_HTTPBasicAuth on %s with %s\n", BOARD_NAME, SHIELD_TYPE);
+ Serial.println(ASYNC_WEBSERVER_STM32_VERSION);
// start the ethernet connection and the server
// Use random mac
diff --git a/examples/Async_PostServer/Async_PostServer.ino b/examples/Async_PostServer/Async_PostServer.ino
index 2c4f013..10433dc 100644
--- a/examples/Async_PostServer/Async_PostServer.ino
+++ b/examples/Async_PostServer/Async_PostServer.ino
@@ -9,13 +9,14 @@
Built by Khoi Hoang https://github.com/khoih-prog/AsyncWebServer_STM32
Licensed under MIT license
- Version: 1.2.4
+ Version: 1.2.5
Version Modified By Date Comments
------- ----------- ---------- -----------
1.2.3 K Hoang 02/09/2020 Initial coding for STM32 for built-in Ethernet (Nucleo-144, DISCOVERY, etc).
Bump up version to v1.2.3 to sync with ESPAsyncWebServer v1.2.3
1.2.4 K Hoang 05/09/2020 Add back MD5/SHA1 authentication feature.
+ 1.2.5 K Hoang 28/12/2020 Suppress all possible compiler warnings. Add examples.
*****************************************************************************************************************************/
/*
Currently support
@@ -83,6 +84,8 @@
#define BOARD_NAME BOARD_TYPE
#endif
+#define SHIELD_TYPE "LAN8742A built-in Ethernet"
+
#include
#include
#include
@@ -211,7 +214,9 @@ void setup(void)
digitalWrite(led, 0);
Serial.begin(115200);
- Serial.println("\nStart Async_PostServer on " + String(BOARD_NAME));
+
+ Serial.printf("\nStarting Async_PostServer on %s with %s\n", BOARD_NAME, SHIELD_TYPE);
+ Serial.println(ASYNC_WEBSERVER_STM32_VERSION);
// start the ethernet connection and the server
// Use random mac
diff --git a/examples/Async_RegexPatterns_STM32/Async_RegexPatterns_STM32.ino b/examples/Async_RegexPatterns_STM32/Async_RegexPatterns_STM32.ino
index afa5480..0dafbd9 100644
--- a/examples/Async_RegexPatterns_STM32/Async_RegexPatterns_STM32.ino
+++ b/examples/Async_RegexPatterns_STM32/Async_RegexPatterns_STM32.ino
@@ -9,13 +9,14 @@
Built by Khoi Hoang https://github.com/khoih-prog/AsyncWebServer_STM32
Licensed under MIT license
- Version: 1.2.4
+ Version: 1.2.5
Version Modified By Date Comments
------- ----------- ---------- -----------
1.2.3 K Hoang 02/09/2020 Initial coding for STM32 for built-in Ethernet (Nucleo-144, DISCOVERY, etc).
Bump up version to v1.2.3 to sync with ESPAsyncWebServer v1.2.3
1.2.4 K Hoang 05/09/2020 Add back MD5/SHA1 authentication feature.
+ 1.2.5 K Hoang 28/12/2020 Suppress all possible compiler warnings. Add examples.
*****************************************************************************************************************************/
/*
Currently support
@@ -102,6 +103,8 @@
#define BOARD_NAME BOARD_TYPE
#endif
+#define SHIELD_TYPE "LAN8742A built-in Ethernet"
+
#include
#include
#include
@@ -149,7 +152,8 @@ void setup()
Serial.begin(115200);
while (!Serial);
- Serial.println("\nStarting Async_RegexPatterns_STM32 on " + String(BOARD_NAME));
+ Serial.printf("\nStarting Async_RegexPatterns_STM32 on %s with %s\n", BOARD_NAME, SHIELD_TYPE);
+ Serial.println(ASYNC_WEBSERVER_STM32_VERSION);
// start the ethernet connection and the server
// Use random mac
diff --git a/examples/Async_SimpleWebServer_STM32/Async_SimpleWebServer_STM32.ino b/examples/Async_SimpleWebServer_STM32/Async_SimpleWebServer_STM32.ino
index 97fedf1..b17fd68 100644
--- a/examples/Async_SimpleWebServer_STM32/Async_SimpleWebServer_STM32.ino
+++ b/examples/Async_SimpleWebServer_STM32/Async_SimpleWebServer_STM32.ino
@@ -9,13 +9,14 @@
Built by Khoi Hoang https://github.com/khoih-prog/AsyncWebServer_STM32
Licensed under MIT license
- Version: 1.2.4
+ Version: 1.2.5
Version Modified By Date Comments
------- ----------- ---------- -----------
1.2.3 K Hoang 02/09/2020 Initial coding for STM32 for built-in Ethernet (Nucleo-144, DISCOVERY, etc).
Bump up version to v1.2.3 to sync with ESPAsyncWebServer v1.2.3
1.2.4 K Hoang 05/09/2020 Add back MD5/SHA1 authentication feature.
+ 1.2.5 K Hoang 28/12/2020 Suppress all possible compiler warnings. Add examples.
*****************************************************************************************************************************/
/*
Currently support
@@ -89,6 +90,8 @@
#define BOARD_NAME BOARD_TYPE
#endif
+#define SHIELD_TYPE "LAN8742A built-in Ethernet"
+
#include
#include
#include
@@ -136,7 +139,8 @@ void setup()
Serial.begin(115200);
while (!Serial);
- Serial.println("\nStarting Async_SimpleWebServer_STM32 on " + String(BOARD_NAME));
+ Serial.printf("\nStarting Async_SimpleWebServer_STM32 on %s with %s\n", BOARD_NAME, SHIELD_TYPE);
+ Serial.println(ASYNC_WEBSERVER_STM32_VERSION);
// start the ethernet connection and the server
// Use random mac
diff --git a/examples/MQTTClient_Auth/MQTTClient_Auth.ino b/examples/MQTTClient_Auth/MQTTClient_Auth.ino
new file mode 100644
index 0000000..6c3cf7b
--- /dev/null
+++ b/examples/MQTTClient_Auth/MQTTClient_Auth.ino
@@ -0,0 +1,168 @@
+/****************************************************************************************************************************
+ MQTTClient_Auth.ino - Dead simple MQTT Client for Ethernet shields
+
+ For STM32 with built-in LAN8742A Ethernet (Nucleo-144, DISCOVERY, etc)
+
+ AsyncWebServer_STM32 is a library for the STM32 run built-in Ethernet WebServer
+
+ Based on and modified from ESPAsyncWebServer (https://github.com/me-no-dev/ESPAsyncWebServer)
+ Built by Khoi Hoang https://github.com/khoih-prog/AsyncWebServer_STM32
+ Licensed under MIT license
+
+ Version: 1.2.5
+
+ Version Modified By Date Comments
+ ------- ----------- ---------- -----------
+ 1.2.3 K Hoang 02/09/2020 Initial coding for STM32 for built-in Ethernet (Nucleo-144, DISCOVERY, etc).
+ Bump up version to v1.2.3 to sync with ESPAsyncWebServer v1.2.3
+ 1.2.4 K Hoang 05/09/2020 Add back MD5/SHA1 authentication feature.
+ 1.2.5 K Hoang 28/12/2020 Suppress all possible compiler warnings. Add examples.
+ *****************************************************************************************************************************/
+
+/*
+ Basic MQTT example (without SSL!) with Authentication
+ This sketch demonstrates the basic capabilities of the library.
+ It connects to an MQTT server then:
+ - providing username and password
+ - publishes "hello world" to the topic "outTopic"
+ - subscribes to the topic "inTopic", printing out any messages
+ it receives. NB - it assumes the received payloads are strings not binary
+ It will reconnect to the server if the connection is lost using a blocking
+ reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to
+ achieve the same result without blocking the main loop.
+*/
+
+// To remove boolean warnings caused by PubSubClient library
+#define boolean bool
+
+#include "defines.h"
+
+#include
+
+// Update these with values suitable for your network.
+//const char* mqttServer = "broker.example"; // Broker address
+const char* mqttServer = "broker.emqx.io"; // Broker address
+//const char* mqttServer = "broker.shiftr.io"; // Broker address
+
+const char *ID = "MQTTClient_SSL-Client"; // Name of our device, must be unique
+const char *TOPIC = "MQTT_Pub"; // Topic to subcribe to
+const char *subTopic = "MQTT_Sub"; // Topic to subcribe to
+
+//IPAddress mqttServer(172, 16, 0, 2);
+
+void callback(char* topic, byte* payload, unsigned int length)
+{
+ Serial.print("Message arrived [");
+ Serial.print(topic);
+ Serial.print("] ");
+
+ for (unsigned int i = 0; i < length; i++)
+ {
+ Serial.print((char)payload[i]);
+ }
+
+ Serial.println();
+}
+
+EthernetClient ethClient;
+PubSubClient client(mqttServer, 1883, callback, ethClient);
+
+void reconnect()
+{
+ // Loop until we're reconnected
+ while (!client.connected())
+ {
+ Serial.print("Attempting MQTT connection to ");
+ Serial.print(mqttServer);
+
+ // Attempt to connect
+ if (client.connect("arduino", "try", "try"))
+ {
+ Serial.println("...connected");
+
+ // Once connected, publish an announcement...
+ String data = "Hello from MQTTClient_SSL on " + String(BOARD_NAME);
+
+ client.publish(TOPIC, data.c_str());
+
+ //Serial.println("Published connection message successfully!");
+ //Serial.print("Subcribed to: ");
+ //Serial.println(subTopic);
+
+ client.subscribe(subTopic);
+ // for loopback testing
+ client.subscribe(TOPIC);
+ }
+ else
+ {
+ Serial.print("...failed, rc=");
+ Serial.print(client.state());
+ Serial.println(" try again in 5 seconds");
+
+ // Wait 5 seconds before retrying
+ delay(5000);
+ }
+ }
+}
+
+void setup()
+{
+ // Open serial communications and wait for port to open:
+ Serial.begin(115200);
+ while (!Serial);
+
+ Serial.printf("\nStarting MQTTClient_Auth on %s with %s\n", BOARD_NAME, SHIELD_TYPE);
+ Serial.println(ASYNC_WEBSERVER_STM32_VERSION);
+
+ // start the ethernet connection and the server
+ // Use random mac
+ uint16_t index = millis() % NUMBER_OF_MAC;
+
+ // Use Static IP
+ //Ethernet.begin(mac[index], ip);
+ // Use DHCP dynamic IP and random mac
+ Ethernet.begin(mac[index]);
+
+ Serial.print("\nConnected to network. IP = ");
+ Serial.println(Ethernet.localIP());
+
+ // Note - the default maximum packet size is 128 bytes. If the
+ // combined length of clientId, username and password exceed this use the
+ // following to increase the buffer size:
+ // client.setBufferSize(255);
+}
+
+#define MQTT_PUBLISH_INTERVAL_MS 5000L
+
+String data = "Hello from MQTTClient_Auth on " + String(BOARD_NAME) + " with " + String(SHIELD_TYPE);
+const char *pubData = data.c_str();
+
+unsigned long lastMsg = 0;
+
+void loop()
+{
+ static unsigned long now;
+
+ if (!client.connected())
+ {
+ reconnect();
+ }
+
+ // Sending Data
+ now = millis();
+
+ if (now - lastMsg > MQTT_PUBLISH_INTERVAL_MS)
+ {
+ lastMsg = now;
+
+ if (!client.publish(TOPIC, pubData))
+ {
+ Serial.println("Message failed to send.");
+ }
+
+ Serial.print("Message Send : " + String(TOPIC) + " => ");
+ Serial.println(data);
+ }
+
+ client.loop();
+}
diff --git a/examples/MQTTClient_Auth/defines.h b/examples/MQTTClient_Auth/defines.h
new file mode 100644
index 0000000..15f9c6f
--- /dev/null
+++ b/examples/MQTTClient_Auth/defines.h
@@ -0,0 +1,125 @@
+/****************************************************************************************************************************
+ defines.h
+
+ For STM32 with built-in LAN8742A Ethernet (Nucleo-144, DISCOVERY, etc)
+
+ AsyncWebServer_STM32 is a library for the STM32 run built-in Ethernet WebServer
+
+ Based on and modified from ESPAsyncWebServer (https://github.com/me-no-dev/ESPAsyncWebServer)
+ Built by Khoi Hoang https://github.com/khoih-prog/AsyncWebServer_STM32
+ Licensed under MIT license
+
+ Version: 1.2.5
+
+ Version Modified By Date Comments
+ ------- ----------- ---------- -----------
+ 1.2.3 K Hoang 02/09/2020 Initial coding for STM32 for built-in Ethernet (Nucleo-144, DISCOVERY, etc).
+ Bump up version to v1.2.3 to sync with ESPAsyncWebServer v1.2.3
+ 1.2.4 K Hoang 05/09/2020 Add back MD5/SHA1 authentication feature.
+ 1.2.5 K Hoang 28/12/2020 Suppress all possible compiler warnings. Add examples.
+ *****************************************************************************************************************************/
+/*
+ Currently support
+ 1) STM32 boards with built-in Ethernet (to use USE_BUILTIN_ETHERNET = true) such as :
+ - Nucleo-144 (F429ZI, F767ZI)
+ - Discovery (STM32F746G-DISCOVERY)
+ - STM32 boards (STM32F/L/H/G/WB/MP1) with 32K+ Flash, with Built-in Ethernet,
+ - See How To Use Built-in Ethernet at (https://github.com/khoih-prog/EthernetWebServer_STM32/issues/1)
+*/
+
+#ifndef defines_h
+#define defines_h
+
+#if !( defined(STM32F0) || defined(STM32F1) || defined(STM32F2) || defined(STM32F3) ||defined(STM32F4) || defined(STM32F7) || \
+ defined(STM32L0) || defined(STM32L1) || defined(STM32L4) || defined(STM32H7) ||defined(STM32G0) || defined(STM32G4) || \
+ defined(STM32WB) || defined(STM32MP1) )
+ #error This code is designed to run on STM32F/L/H/G/WB/MP1 platform! Please check your Tools->Board setting.
+#endif
+
+#if defined(STM32F0)
+ #warning STM32F0 board selected
+ #define BOARD_TYPE "STM32F0"
+#elif defined(STM32F1)
+ #warning STM32F1 board selected
+ #define BOARD_TYPE "STM32F1"
+#elif defined(STM32F2)
+ #warning STM32F2 board selected
+ #define BOARD_TYPE "STM32F2"
+#elif defined(STM32F3)
+ #warning STM32F3 board selected
+ #define BOARD_TYPE "STM32F3"
+#elif defined(STM32F4)
+ #warning STM32F4 board selected
+ #define BOARD_TYPE "STM32F4"
+#elif defined(STM32F7)
+ #warning STM32F7 board selected
+ #define BOARD_TYPE "STM32F7"
+#elif defined(STM32L0)
+ #warning STM32L0 board selected
+ #define BOARD_TYPE "STM32L0"
+#elif defined(STM32L1)
+ #warning STM32L1 board selected
+ #define BOARD_TYPE "STM32L1"
+#elif defined(STM32L4)
+ #warning STM32L4 board selected
+ #define BOARD_TYPE "STM32L4"
+#elif defined(STM32H7)
+ #warning STM32H7 board selected
+ #define BOARD_TYPE "STM32H7"
+#elif defined(STM32G0)
+ #warning STM32G0 board selected
+ #define BOARD_TYPE "STM32G0"
+#elif defined(STM32G4)
+ #warning STM32G4 board selected
+ #define BOARD_TYPE "STM32G4"
+#elif defined(STM32WB)
+ #warning STM32WB board selected
+ #define BOARD_TYPE "STM32WB"
+#elif defined(STM32MP1)
+ #warning STM32MP1 board selected
+ #define BOARD_TYPE "STM32MP1"
+#else
+ #warning STM32 unknown board selected
+ #define BOARD_TYPE "STM32 Unknown"
+#endif
+
+#ifndef BOARD_NAME
+ #define BOARD_NAME BOARD_TYPE
+#endif
+
+#define SHIELD_TYPE "LAN8742A built-in Ethernet"
+
+#include
+#include
+#include
+
+// Enter a MAC address and IP address for your controller below.
+#define NUMBER_OF_MAC 20
+
+byte mac[][NUMBER_OF_MAC] =
+{
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x01 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x02 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x03 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x04 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x05 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x06 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x07 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x08 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x09 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x0A },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x0B },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x0C },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x0D },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x0E },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x0F },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x10 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x11 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x12 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x13 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x14 },
+};
+// Select the IP address according to your local network
+IPAddress ip(192, 168, 2, 232);
+
+#endif //defines_h
diff --git a/examples/MQTTClient_Basic/MQTTClient_Basic.ino b/examples/MQTTClient_Basic/MQTTClient_Basic.ino
new file mode 100644
index 0000000..1a7fa74
--- /dev/null
+++ b/examples/MQTTClient_Basic/MQTTClient_Basic.ino
@@ -0,0 +1,170 @@
+/****************************************************************************************************************************
+ MQTTClient_Basic.ino - Dead simple MQTT Client for Ethernet shields
+
+ For STM32 with built-in LAN8742A Ethernet (Nucleo-144, DISCOVERY, etc)
+
+ AsyncWebServer_STM32 is a library for the STM32 run built-in Ethernet WebServer
+
+ Based on and modified from ESPAsyncWebServer (https://github.com/me-no-dev/ESPAsyncWebServer)
+ Built by Khoi Hoang https://github.com/khoih-prog/AsyncWebServer_STM32
+ Licensed under MIT license
+
+ Version: 1.2.5
+
+ Version Modified By Date Comments
+ ------- ----------- ---------- -----------
+ 1.2.3 K Hoang 02/09/2020 Initial coding for STM32 for built-in Ethernet (Nucleo-144, DISCOVERY, etc).
+ Bump up version to v1.2.3 to sync with ESPAsyncWebServer v1.2.3
+ 1.2.4 K Hoang 05/09/2020 Add back MD5/SHA1 authentication feature.
+ 1.2.5 K Hoang 28/12/2020 Suppress all possible compiler warnings. Add examples.
+ *****************************************************************************************************************************/
+
+/*
+ Basic MQTT example (without SSL!) with Authentication
+ This sketch demonstrates the basic capabilities of the library.
+ It connects to an MQTT server then:
+ - providing username and password
+ - publishes "hello world" to the topic "outTopic"
+ - subscribes to the topic "inTopic", printing out any messages
+ it receives. NB - it assumes the received payloads are strings not binary
+
+ It will reconnect to the server if the connection is lost using a blocking
+ reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to
+ achieve the same result without blocking the main loop.
+*/
+
+// To remove boolean warnings caused by PubSubClient library
+#define boolean bool
+
+#include "defines.h"
+
+#include
+
+// Update these with values suitable for your network.
+//const char* mqttServer = "broker.example"; // Broker address
+//const char* mqttServer = "broker.emqx.io"; // Broker address
+const char* mqttServer = "broker.shiftr.io"; // Broker address
+
+const char *ID = "MQTTClient_SSL-Client"; // Name of our device, must be unique
+const char *TOPIC = "MQTT_Pub"; // Topic to subcribe to
+const char *subTopic = "MQTT_Sub"; // Topic to subcribe to
+
+//IPAddress mqttServer(172, 16, 0, 2);
+
+void callback(char* topic, byte* payload, unsigned int length)
+{
+ Serial.print("Message arrived [");
+ Serial.print(topic);
+ Serial.print("] ");
+
+ for (unsigned int i = 0; i < length; i++)
+ {
+ Serial.print((char)payload[i]);
+ }
+
+ Serial.println();
+}
+
+EthernetClient ethClient;
+PubSubClient client(mqttServer, 1883, callback, ethClient);
+
+void reconnect()
+{
+ // Loop until we're reconnected
+ while (!client.connected())
+ {
+ Serial.print("Attempting MQTT connection to ");
+ Serial.print(mqttServer);
+
+ // Attempt to connect
+ if (client.connect(ID, "try", "try"))
+ {
+ Serial.println("...connected");
+
+ // Once connected, publish an announcement...
+ String data = "Hello from MQTTClient_SSL on " + String(BOARD_NAME);
+
+ client.publish(TOPIC, data.c_str());
+
+ //Serial.println("Published connection message successfully!");
+ //Serial.print("Subcribed to: ");
+ //Serial.println(subTopic);
+
+ client.subscribe(subTopic);
+ // for loopback testing
+ client.subscribe(TOPIC);
+ }
+ else
+ {
+ Serial.print("...failed, rc=");
+ Serial.print(client.state());
+ Serial.println(" try again in 5 seconds");
+
+ // Wait 5 seconds before retrying
+ delay(5000);
+ }
+ }
+}
+
+void setup()
+{
+ // Open serial communications and wait for port to open:
+ Serial.begin(115200);
+ while (!Serial);
+
+ Serial.printf("\nStarting MQTTClient_Basic on %s with %s\n", BOARD_NAME, SHIELD_TYPE);
+ Serial.println(ASYNC_WEBSERVER_STM32_VERSION);
+
+ // start the ethernet connection and the server
+ // Use random mac
+ uint16_t index = millis() % NUMBER_OF_MAC;
+
+ // Use Static IP
+ //Ethernet.begin(mac[index], ip);
+ // Use DHCP dynamic IP and random mac
+ Ethernet.begin(mac[index]);
+
+ Serial.print("\nConnected to network. IP = ");
+ Serial.println(Ethernet.localIP());
+
+ client.setServer(mqttServer, 1883);
+ client.setCallback(callback);
+
+ // Allow the hardware to sort itself out
+ delay(1500);
+}
+
+#define MQTT_PUBLISH_INTERVAL_MS 5000L
+
+String data = "Hello from MQTTClient_Basic on " + String(BOARD_NAME) + " with " + String(SHIELD_TYPE);
+const char *pubData = data.c_str();
+
+unsigned long lastMsg = 0;
+
+void loop()
+{
+ static unsigned long now;
+
+ if (!client.connected())
+ {
+ reconnect();
+ }
+
+ // Sending Data
+ now = millis();
+
+ if (now - lastMsg > MQTT_PUBLISH_INTERVAL_MS)
+ {
+ lastMsg = now;
+
+ if (!client.publish(TOPIC, pubData))
+ {
+ Serial.println("Message failed to send.");
+ }
+
+ Serial.print("Message Send : " + String(TOPIC) + " => ");
+ Serial.println(data);
+ }
+
+ client.loop();
+}
diff --git a/examples/MQTTClient_Basic/defines.h b/examples/MQTTClient_Basic/defines.h
new file mode 100644
index 0000000..15f9c6f
--- /dev/null
+++ b/examples/MQTTClient_Basic/defines.h
@@ -0,0 +1,125 @@
+/****************************************************************************************************************************
+ defines.h
+
+ For STM32 with built-in LAN8742A Ethernet (Nucleo-144, DISCOVERY, etc)
+
+ AsyncWebServer_STM32 is a library for the STM32 run built-in Ethernet WebServer
+
+ Based on and modified from ESPAsyncWebServer (https://github.com/me-no-dev/ESPAsyncWebServer)
+ Built by Khoi Hoang https://github.com/khoih-prog/AsyncWebServer_STM32
+ Licensed under MIT license
+
+ Version: 1.2.5
+
+ Version Modified By Date Comments
+ ------- ----------- ---------- -----------
+ 1.2.3 K Hoang 02/09/2020 Initial coding for STM32 for built-in Ethernet (Nucleo-144, DISCOVERY, etc).
+ Bump up version to v1.2.3 to sync with ESPAsyncWebServer v1.2.3
+ 1.2.4 K Hoang 05/09/2020 Add back MD5/SHA1 authentication feature.
+ 1.2.5 K Hoang 28/12/2020 Suppress all possible compiler warnings. Add examples.
+ *****************************************************************************************************************************/
+/*
+ Currently support
+ 1) STM32 boards with built-in Ethernet (to use USE_BUILTIN_ETHERNET = true) such as :
+ - Nucleo-144 (F429ZI, F767ZI)
+ - Discovery (STM32F746G-DISCOVERY)
+ - STM32 boards (STM32F/L/H/G/WB/MP1) with 32K+ Flash, with Built-in Ethernet,
+ - See How To Use Built-in Ethernet at (https://github.com/khoih-prog/EthernetWebServer_STM32/issues/1)
+*/
+
+#ifndef defines_h
+#define defines_h
+
+#if !( defined(STM32F0) || defined(STM32F1) || defined(STM32F2) || defined(STM32F3) ||defined(STM32F4) || defined(STM32F7) || \
+ defined(STM32L0) || defined(STM32L1) || defined(STM32L4) || defined(STM32H7) ||defined(STM32G0) || defined(STM32G4) || \
+ defined(STM32WB) || defined(STM32MP1) )
+ #error This code is designed to run on STM32F/L/H/G/WB/MP1 platform! Please check your Tools->Board setting.
+#endif
+
+#if defined(STM32F0)
+ #warning STM32F0 board selected
+ #define BOARD_TYPE "STM32F0"
+#elif defined(STM32F1)
+ #warning STM32F1 board selected
+ #define BOARD_TYPE "STM32F1"
+#elif defined(STM32F2)
+ #warning STM32F2 board selected
+ #define BOARD_TYPE "STM32F2"
+#elif defined(STM32F3)
+ #warning STM32F3 board selected
+ #define BOARD_TYPE "STM32F3"
+#elif defined(STM32F4)
+ #warning STM32F4 board selected
+ #define BOARD_TYPE "STM32F4"
+#elif defined(STM32F7)
+ #warning STM32F7 board selected
+ #define BOARD_TYPE "STM32F7"
+#elif defined(STM32L0)
+ #warning STM32L0 board selected
+ #define BOARD_TYPE "STM32L0"
+#elif defined(STM32L1)
+ #warning STM32L1 board selected
+ #define BOARD_TYPE "STM32L1"
+#elif defined(STM32L4)
+ #warning STM32L4 board selected
+ #define BOARD_TYPE "STM32L4"
+#elif defined(STM32H7)
+ #warning STM32H7 board selected
+ #define BOARD_TYPE "STM32H7"
+#elif defined(STM32G0)
+ #warning STM32G0 board selected
+ #define BOARD_TYPE "STM32G0"
+#elif defined(STM32G4)
+ #warning STM32G4 board selected
+ #define BOARD_TYPE "STM32G4"
+#elif defined(STM32WB)
+ #warning STM32WB board selected
+ #define BOARD_TYPE "STM32WB"
+#elif defined(STM32MP1)
+ #warning STM32MP1 board selected
+ #define BOARD_TYPE "STM32MP1"
+#else
+ #warning STM32 unknown board selected
+ #define BOARD_TYPE "STM32 Unknown"
+#endif
+
+#ifndef BOARD_NAME
+ #define BOARD_NAME BOARD_TYPE
+#endif
+
+#define SHIELD_TYPE "LAN8742A built-in Ethernet"
+
+#include
+#include
+#include
+
+// Enter a MAC address and IP address for your controller below.
+#define NUMBER_OF_MAC 20
+
+byte mac[][NUMBER_OF_MAC] =
+{
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x01 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x02 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x03 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x04 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x05 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x06 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x07 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x08 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x09 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x0A },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x0B },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x0C },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x0D },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x0E },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x0F },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x10 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x11 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x12 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x13 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x14 },
+};
+// Select the IP address according to your local network
+IPAddress ip(192, 168, 2, 232);
+
+#endif //defines_h
diff --git a/examples/MQTT_ThingStream/MQTT_ThingStream.ino b/examples/MQTT_ThingStream/MQTT_ThingStream.ino
new file mode 100644
index 0000000..5ae7873
--- /dev/null
+++ b/examples/MQTT_ThingStream/MQTT_ThingStream.ino
@@ -0,0 +1,221 @@
+/****************************************************************************************************************************
+ MQTT_ThingStream.ino - Dead simple MQTT Client for Ethernet shields
+
+ For STM32 with built-in LAN8742A Ethernet (Nucleo-144, DISCOVERY, etc)
+
+ AsyncWebServer_STM32 is a library for the STM32 run built-in Ethernet WebServer
+
+ Based on and modified from ESPAsyncWebServer (https://github.com/me-no-dev/ESPAsyncWebServer)
+ Built by Khoi Hoang https://github.com/khoih-prog/AsyncWebServer_STM32
+ Licensed under MIT license
+
+ Version: 1.2.5
+
+ Version Modified By Date Comments
+ ------- ----------- ---------- -----------
+ 1.2.3 K Hoang 02/09/2020 Initial coding for STM32 for built-in Ethernet (Nucleo-144, DISCOVERY, etc).
+ Bump up version to v1.2.3 to sync with ESPAsyncWebServer v1.2.3
+ 1.2.4 K Hoang 05/09/2020 Add back MD5/SHA1 authentication feature.
+ 1.2.5 K Hoang 28/12/2020 Suppress all possible compiler warnings. Add examples.
+ *****************************************************************************************************************************/
+/*
+ Basic MQTT example (without SSL!)
+ This sketch demonstrates the basic capabilities of the library.
+ It connects to an MQTT server then:
+ - publishes {Hello from MQTTClient_SSL on NUCLEO_F767ZI} to the topic [STM32_Pub]
+ - subscribes to the topic [STM32_Sub], printing out any messages
+ it receives. NB - it assumes the received payloads are strings not binary
+ It will reconnect to the server if the connection is lost using a blocking
+ reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to
+ achieve the same result without blocking the main loop.
+
+ You will need to populate "certificates.h" with your trust anchors
+ (see https://github.com/OPEnSLab-OSU/SSLClient/blob/master/TrustAnchors.md)
+ and my_cert/my_key with your certificate/private key pair
+ (see https://github.com/OPEnSLab-OSU/SSLClient#mtls).
+*/
+
+// To remove boolean warnings caused by PubSubClient library
+#define boolean bool
+
+#include "defines.h"
+
+#include
+
+const char my_cert[] = "FIXME";
+const char my_key[] = "FIXME";
+
+#define USING_THINGSTREAM_IO false //true
+
+#if USING_THINGSTREAM_IO
+
+const char *MQTT_PREFIX_TOPIC = "esp32-sniffer/";
+const char *MQTT_ANNOUNCE_TOPIC = "/status";
+const char *MQTT_CONTROL_TOPIC = "/control";
+const char *MQTT_BLE_TOPIC = "/ble";
+
+
+// GOT FROM ThingsStream!
+const char *MQTT_SERVER = "mqtt.thingstream.io";
+const char *MQTT_USER = "MQTT_USER";
+const char *MQTT_PASS = "MQTT_PASS";
+const char *MQTT_CLIENT_ID = "MQTT_CLIENT_ID";
+
+String topic = MQTT_PREFIX_TOPIC + String("12345678") + MQTT_BLE_TOPIC;
+String subTopic = MQTT_PREFIX_TOPIC + String("12345678") + MQTT_BLE_TOPIC;
+
+#else
+
+const char* MQTT_SERVER = "broker.emqx.io"; // Broker address
+
+const char* ID = "MQTTClient_SSL-Client"; // Name of our device, must be unique
+String topic = "STM32_Pub"; // Topic to subcribe to
+String subTopic = "STM32_Sub"; // Topic to subcribe to
+
+#endif
+
+void mqtt_receive_callback(char* topic, byte* payload, unsigned int length);
+
+const int MQTT_PORT = 1883; //if you use SSL //1883 no SSL
+
+unsigned long lastMsg = 0;
+
+// Initialize the SSL client library
+// Arguments: EthernetClient, our trust anchors
+
+
+EthernetClient ethClient;
+
+PubSubClient client(MQTT_SERVER, MQTT_PORT, mqtt_receive_callback, ethClient);
+
+/*
+ Called whenever a payload is received from a subscribed MQTT topic
+*/
+void mqtt_receive_callback(char* topic, byte* payload, unsigned int length)
+{
+ Serial.print("MQTT Message receive [");
+ Serial.print(topic);
+ Serial.print("] ");
+
+ for (unsigned int i = 0; i < length; i++)
+ {
+ Serial.print((char)payload[i]);
+ }
+
+ Serial.println();
+}
+
+void reconnect()
+{
+ // Loop until we're reconnected
+ while (!client.connected())
+ {
+ Serial.print("Attempting MQTT connection to ");
+ Serial.println(MQTT_SERVER);
+
+ // Attempt to connect
+
+#if USING_THINGSTREAM_IO
+ int connect_status = client.connect(MQTT_CLIENT_ID, MQTT_USER, MQTT_PASS, topic.c_str(), 2, false, "");
+#else
+ int connect_status = client.connect(ID);
+#endif
+
+ if (connect_status)
+ {
+ Serial.println("...connected");
+
+ // Once connected, publish an announcement...
+ String data = "Hello from MQTTClient_SSL on " + String(BOARD_NAME);
+
+ client.publish(topic.c_str(), data.c_str());
+
+ Serial.println("Published connection message successfully!");
+
+ Serial.print("Subcribed to: ");
+ Serial.println(subTopic);
+
+ // This is a workaround to address https://github.com/OPEnSLab-OSU/SSLClient/issues/9
+ //ethClientSSL.flush();
+ // ... and resubscribe
+ client.subscribe(subTopic.c_str());
+ // for loopback testing
+ client.subscribe(topic.c_str());
+ // This is a workaround to address https://github.com/OPEnSLab-OSU/SSLClient/issues/9
+ //ethClientSSL.flush();
+ }
+ else
+ {
+ Serial.print("failed, rc=");
+ Serial.print(client.state());
+ Serial.println(" try again in 5 seconds");
+
+ // Wait 5 seconds before retrying
+ delay(5000);
+ }
+ }
+}
+
+void setup()
+{
+ // Open serial communications and wait for port to open:
+ Serial.begin(115200);
+ while (!Serial);
+
+ Serial.printf("\nStarting MQTT_ThingStream on %s with %s\n", BOARD_NAME, SHIELD_TYPE);
+ Serial.println(ASYNC_WEBSERVER_STM32_VERSION);
+
+ // start the ethernet connection and the server
+ // Use random mac
+ uint16_t index = millis() % NUMBER_OF_MAC;
+
+ // Use Static IP
+ //Ethernet.begin(mac[index], ip);
+ // Use DHCP dynamic IP and random mac
+ Ethernet.begin(mac[index]);
+
+ Serial.print("\nConnected to network. IP = ");
+ Serial.println(Ethernet.localIP());
+
+ // Note - the default maximum packet size is 256 bytes. If the
+ // combined length of clientId, username and password exceed this use the
+ // following to increase the buffer size:
+ //client.setBufferSize(256);
+
+ Serial.println("***************************************");
+ Serial.println(topic);
+ Serial.println("***************************************");
+}
+
+#define MQTT_PUBLISH_INTERVAL_MS 5000L
+
+String data = "Hello from MQTT_ThingStream on " + String(BOARD_NAME) + " with " + String(SHIELD_TYPE);
+const char *pubData = data.c_str();
+
+void loop()
+{
+ static unsigned long now;
+
+ if (!client.connected())
+ {
+ reconnect();
+ }
+
+ // Sending Data
+ now = millis();
+
+ if (now - lastMsg > MQTT_PUBLISH_INTERVAL_MS)
+ {
+ lastMsg = now;
+
+ if (!client.publish(topic.c_str(), pubData))
+ {
+ Serial.println("Message failed to send.");
+ }
+
+ Serial.print("MQTT Message Send : " + topic + " => ");
+ Serial.println(data);
+ }
+
+ client.loop();
+}
diff --git a/examples/MQTT_ThingStream/defines.h b/examples/MQTT_ThingStream/defines.h
new file mode 100644
index 0000000..15f9c6f
--- /dev/null
+++ b/examples/MQTT_ThingStream/defines.h
@@ -0,0 +1,125 @@
+/****************************************************************************************************************************
+ defines.h
+
+ For STM32 with built-in LAN8742A Ethernet (Nucleo-144, DISCOVERY, etc)
+
+ AsyncWebServer_STM32 is a library for the STM32 run built-in Ethernet WebServer
+
+ Based on and modified from ESPAsyncWebServer (https://github.com/me-no-dev/ESPAsyncWebServer)
+ Built by Khoi Hoang https://github.com/khoih-prog/AsyncWebServer_STM32
+ Licensed under MIT license
+
+ Version: 1.2.5
+
+ Version Modified By Date Comments
+ ------- ----------- ---------- -----------
+ 1.2.3 K Hoang 02/09/2020 Initial coding for STM32 for built-in Ethernet (Nucleo-144, DISCOVERY, etc).
+ Bump up version to v1.2.3 to sync with ESPAsyncWebServer v1.2.3
+ 1.2.4 K Hoang 05/09/2020 Add back MD5/SHA1 authentication feature.
+ 1.2.5 K Hoang 28/12/2020 Suppress all possible compiler warnings. Add examples.
+ *****************************************************************************************************************************/
+/*
+ Currently support
+ 1) STM32 boards with built-in Ethernet (to use USE_BUILTIN_ETHERNET = true) such as :
+ - Nucleo-144 (F429ZI, F767ZI)
+ - Discovery (STM32F746G-DISCOVERY)
+ - STM32 boards (STM32F/L/H/G/WB/MP1) with 32K+ Flash, with Built-in Ethernet,
+ - See How To Use Built-in Ethernet at (https://github.com/khoih-prog/EthernetWebServer_STM32/issues/1)
+*/
+
+#ifndef defines_h
+#define defines_h
+
+#if !( defined(STM32F0) || defined(STM32F1) || defined(STM32F2) || defined(STM32F3) ||defined(STM32F4) || defined(STM32F7) || \
+ defined(STM32L0) || defined(STM32L1) || defined(STM32L4) || defined(STM32H7) ||defined(STM32G0) || defined(STM32G4) || \
+ defined(STM32WB) || defined(STM32MP1) )
+ #error This code is designed to run on STM32F/L/H/G/WB/MP1 platform! Please check your Tools->Board setting.
+#endif
+
+#if defined(STM32F0)
+ #warning STM32F0 board selected
+ #define BOARD_TYPE "STM32F0"
+#elif defined(STM32F1)
+ #warning STM32F1 board selected
+ #define BOARD_TYPE "STM32F1"
+#elif defined(STM32F2)
+ #warning STM32F2 board selected
+ #define BOARD_TYPE "STM32F2"
+#elif defined(STM32F3)
+ #warning STM32F3 board selected
+ #define BOARD_TYPE "STM32F3"
+#elif defined(STM32F4)
+ #warning STM32F4 board selected
+ #define BOARD_TYPE "STM32F4"
+#elif defined(STM32F7)
+ #warning STM32F7 board selected
+ #define BOARD_TYPE "STM32F7"
+#elif defined(STM32L0)
+ #warning STM32L0 board selected
+ #define BOARD_TYPE "STM32L0"
+#elif defined(STM32L1)
+ #warning STM32L1 board selected
+ #define BOARD_TYPE "STM32L1"
+#elif defined(STM32L4)
+ #warning STM32L4 board selected
+ #define BOARD_TYPE "STM32L4"
+#elif defined(STM32H7)
+ #warning STM32H7 board selected
+ #define BOARD_TYPE "STM32H7"
+#elif defined(STM32G0)
+ #warning STM32G0 board selected
+ #define BOARD_TYPE "STM32G0"
+#elif defined(STM32G4)
+ #warning STM32G4 board selected
+ #define BOARD_TYPE "STM32G4"
+#elif defined(STM32WB)
+ #warning STM32WB board selected
+ #define BOARD_TYPE "STM32WB"
+#elif defined(STM32MP1)
+ #warning STM32MP1 board selected
+ #define BOARD_TYPE "STM32MP1"
+#else
+ #warning STM32 unknown board selected
+ #define BOARD_TYPE "STM32 Unknown"
+#endif
+
+#ifndef BOARD_NAME
+ #define BOARD_NAME BOARD_TYPE
+#endif
+
+#define SHIELD_TYPE "LAN8742A built-in Ethernet"
+
+#include
+#include
+#include
+
+// Enter a MAC address and IP address for your controller below.
+#define NUMBER_OF_MAC 20
+
+byte mac[][NUMBER_OF_MAC] =
+{
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x01 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x02 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x03 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x04 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x05 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x06 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x07 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x08 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x09 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x0A },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x0B },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x0C },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x0D },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x0E },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x0F },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x10 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x11 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x12 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x13 },
+ { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x14 },
+};
+// Select the IP address according to your local network
+IPAddress ip(192, 168, 2, 232);
+
+#endif //defines_h
diff --git a/examples/WebClient/WebClient.ino b/examples/WebClient/WebClient.ino
index b3867e9..258a2f9 100644
--- a/examples/WebClient/WebClient.ino
+++ b/examples/WebClient/WebClient.ino
@@ -9,13 +9,14 @@
Built by Khoi Hoang https://github.com/khoih-prog/AsyncWebServer_STM32
Licensed under MIT license
- Version: 1.2.4
+ Version: 1.2.5
Version Modified By Date Comments
------- ----------- ---------- -----------
1.2.3 K Hoang 02/09/2020 Initial coding for STM32 for built-in Ethernet (Nucleo-144, DISCOVERY, etc).
Bump up version to v1.2.3 to sync with ESPAsyncWebServer v1.2.3
1.2.4 K Hoang 05/09/2020 Add back MD5/SHA1 authentication feature.
+ 1.2.5 K Hoang 28/12/2020 Suppress all possible compiler warnings. Add examples.
*****************************************************************************************************************************/
/*
Currently support
@@ -39,7 +40,8 @@ void setup()
Serial.begin(115200);
while (!Serial);
- Serial.println("\nStart WebClient on " + String(BOARD_NAME));
+ Serial.printf("\nStarting WebClient on %s with %s\n", BOARD_NAME, SHIELD_TYPE);
+ Serial.println(ASYNC_WEBSERVER_STM32_VERSION);
// start the ethernet connection and the server
// Use random mac
diff --git a/examples/WebClient/defines.h b/examples/WebClient/defines.h
index 77114f0..15f9c6f 100644
--- a/examples/WebClient/defines.h
+++ b/examples/WebClient/defines.h
@@ -9,11 +9,14 @@
Built by Khoi Hoang https://github.com/khoih-prog/AsyncWebServer_STM32
Licensed under MIT license
- Version: 1.0.0
+ Version: 1.2.5
Version Modified By Date Comments
------- ----------- ---------- -----------
- 1.0.0 K Hoang 02/09/2020 Initial coding for STM32 for built-in Ethernet (Nucleo-144, DISCOVERY, etc)
+ 1.2.3 K Hoang 02/09/2020 Initial coding for STM32 for built-in Ethernet (Nucleo-144, DISCOVERY, etc).
+ Bump up version to v1.2.3 to sync with ESPAsyncWebServer v1.2.3
+ 1.2.4 K Hoang 05/09/2020 Add back MD5/SHA1 authentication feature.
+ 1.2.5 K Hoang 28/12/2020 Suppress all possible compiler warnings. Add examples.
*****************************************************************************************************************************/
/*
Currently support
@@ -84,9 +87,11 @@
#define BOARD_NAME BOARD_TYPE
#endif
+#define SHIELD_TYPE "LAN8742A built-in Ethernet"
+
#include
#include
-//#include
+#include
// Enter a MAC address and IP address for your controller below.
#define NUMBER_OF_MAC 20
diff --git a/examples/WebClientRepeating/WebClientRepeating.ino b/examples/WebClientRepeating/WebClientRepeating.ino
index e401b6e..84545cc 100644
--- a/examples/WebClientRepeating/WebClientRepeating.ino
+++ b/examples/WebClientRepeating/WebClientRepeating.ino
@@ -9,13 +9,14 @@
Built by Khoi Hoang https://github.com/khoih-prog/AsyncWebServer_STM32
Licensed under MIT license
- Version: 1.2.4
+ Version: 1.2.5
Version Modified By Date Comments
------- ----------- ---------- -----------
1.2.3 K Hoang 02/09/2020 Initial coding for STM32 for built-in Ethernet (Nucleo-144, DISCOVERY, etc).
Bump up version to v1.2.3 to sync with ESPAsyncWebServer v1.2.3
1.2.4 K Hoang 05/09/2020 Add back MD5/SHA1 authentication feature.
+ 1.2.5 K Hoang 28/12/2020 Suppress all possible compiler warnings. Add examples.
*****************************************************************************************************************************/
/*
Currently support
@@ -72,7 +73,8 @@ void setup()
Serial.begin(115200);
while (!Serial);
- Serial.println("\nStart WebClientRepeating on " + String(BOARD_NAME));
+ Serial.printf("\nStarting WebClientRepeating on %s with %s\n", BOARD_NAME, SHIELD_TYPE);
+ Serial.println(ASYNC_WEBSERVER_STM32_VERSION);
// start the ethernet connection and the server
// Use random mac
diff --git a/examples/WebClientRepeating/defines.h b/examples/WebClientRepeating/defines.h
index 745c739..15f9c6f 100644
--- a/examples/WebClientRepeating/defines.h
+++ b/examples/WebClientRepeating/defines.h
@@ -9,11 +9,14 @@
Built by Khoi Hoang https://github.com/khoih-prog/AsyncWebServer_STM32
Licensed under MIT license
- Version: 1.0.0
+ Version: 1.2.5
Version Modified By Date Comments
------- ----------- ---------- -----------
- 1.0.0 K Hoang 02/09/2020 Initial coding for STM32 for built-in Ethernet (Nucleo-144, DISCOVERY, etc)
+ 1.2.3 K Hoang 02/09/2020 Initial coding for STM32 for built-in Ethernet (Nucleo-144, DISCOVERY, etc).
+ Bump up version to v1.2.3 to sync with ESPAsyncWebServer v1.2.3
+ 1.2.4 K Hoang 05/09/2020 Add back MD5/SHA1 authentication feature.
+ 1.2.5 K Hoang 28/12/2020 Suppress all possible compiler warnings. Add examples.
*****************************************************************************************************************************/
/*
Currently support
@@ -84,8 +87,11 @@
#define BOARD_NAME BOARD_TYPE
#endif
+#define SHIELD_TYPE "LAN8742A built-in Ethernet"
+
#include
#include
+#include
// Enter a MAC address and IP address for your controller below.
#define NUMBER_OF_MAC 20
diff --git a/library.json b/library.json
index 7219b03..cda0c45 100644
--- a/library.json
+++ b/library.json
@@ -1,8 +1,8 @@
{
"name":"AsyncWebServer_STM32",
- "version": "1.2.4",
- "description":"Asynchronous HTTP and WebSocket Server Library for STM32 using builtin LAN8742A Ethernet",
- "keywords":"http,async,websocket,webserver,stm32,ethernet",
+ "version": "1.2.5",
+ "description":"Asynchronous HTTP and WebSocket Server Library for STM32F/L/H/G/WB/MP1 using LAN8742A Ethernet",
+ "keywords":"http,async,websocket,webserver,stm32f,stm32l,stm32h,stm32g,stm32wb,stm32mp1,ethernet,lan8742a",
"authors":
[
{
diff --git a/library.properties b/library.properties
index 07ef708..91b1200 100644
--- a/library.properties
+++ b/library.properties
@@ -1,5 +1,5 @@
name=AsyncWebServer_STM32
-version=1.2.4
+version=1.2.5
author=Hristo Gochkov,Khoi Hoang
maintainer=Khoi Hoang
license=MIT
@@ -9,3 +9,4 @@ category=Communication,AsyncWebServer
url=https://github.com/khoih-prog/AsyncWebServer_STM32
architectures=stm32
depends=STM32duino LwIP,STM32duino STM32Ethernet,STM32AsyncTCP
+includes=LwIP.h,STM32Ethernet.h,AsyncWebServer_STM32.h
diff --git a/pics/AsyncMultiWebServer_STM32_SVR1.png b/pics/AsyncMultiWebServer_STM32_SVR1.png
new file mode 100644
index 0000000000000000000000000000000000000000..9b09e6fb1c908021352e42a16fb7b84d53a93922
GIT binary patch
literal 33016
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
KRUv8e?Y{w%i3&yl
literal 0
HcmV?d00001
diff --git a/pics/AsyncMultiWebServer_STM32_SVR2.png b/pics/AsyncMultiWebServer_STM32_SVR2.png
new file mode 100644
index 0000000000000000000000000000000000000000..915bec36fbf0d855523d0b016e9461a0d2f47b44
GIT binary patch
literal 33093
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