bin2array to dynamically create C array on build
This commit is contained in:
39
resources/AsyncWebSerial/.clang-format
Normal file
39
resources/AsyncWebSerial/.clang-format
Normal file
@@ -0,0 +1,39 @@
|
||||
# Base style
|
||||
BasedOnStyle: LLVM
|
||||
|
||||
# Custom configurations
|
||||
IndentWidth: 4 # Number of spaces per indentation level
|
||||
TabWidth: 4 # Width of a tab (useful if 'UseTab' is set)
|
||||
UseTab: Never # Use spaces instead of tabs
|
||||
|
||||
# Function formatting
|
||||
BreakBeforeBraces: Linux
|
||||
AllowShortFunctionsOnASingleLine: Inline # Allow short functions to stay on a single line
|
||||
AlwaysBreakBeforeMultilineStrings: false # Keep multiline strings together
|
||||
|
||||
# Alignment
|
||||
AlignConsecutiveAssignments: true # Align consecutive assignments
|
||||
AlignTrailingComments: true # Align trailing comments
|
||||
|
||||
# Parameter formatting
|
||||
AllowAllParametersOfDeclarationOnNextLine: false # Parameters declared on the same line if possible
|
||||
|
||||
# Array and list formatting
|
||||
BinPackArguments: true # Place multiple arguments on the same line if possible
|
||||
BinPackParameters: true # Same logic for parameters
|
||||
ColumnLimit: 120 # Line length limit
|
||||
|
||||
# Pointer and reference formatting
|
||||
PointerAlignment: Right # Align pointer near the variable name or type (values: Left, Right, Middle)
|
||||
ReferenceAlignment: Right # Same logic for references
|
||||
|
||||
# Namespace
|
||||
IndentNamespace: None # No indentation for namespaces
|
||||
NamespaceIndentation: None # Alternative namespace indentation option
|
||||
|
||||
# Comments
|
||||
ReflowComments: true # Reformat comments to fit within the line length limit
|
||||
|
||||
# Optional advanced configurations
|
||||
IncludeBlocks: Preserve # Preserve blank lines between includes
|
||||
SortIncludes: true # Sort includes alphabetically EmptyLineBeforeAccessModifier: Always # Blank line before "public:", "private:", etc.
|
||||
7
resources/AsyncWebSerial/.github/dependabot.yml
vendored
Normal file
7
resources/AsyncWebSerial/.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
38
resources/AsyncWebSerial/.github/workflows/ci.yml
vendored
Normal file
38
resources/AsyncWebSerial/.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
name: Build
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
platformio:
|
||||
name: PlatformIO
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
board: [esp32dev]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Cache PlatformIO
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
key: ${{ runner.os }}-pio
|
||||
path: |
|
||||
~/.cache/pip
|
||||
~/.platformio
|
||||
|
||||
- name: Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
||||
- name: Install PlatformIO
|
||||
run: |
|
||||
python -m pip install -U pip
|
||||
pip install -U platformio
|
||||
|
||||
- run: PLATFORMIO_SRC_DIR=examples/demo PIO_BOARD=${{ matrix.board }} pio run
|
||||
19
resources/AsyncWebSerial/.github/workflows/dependabot.yml
vendored
Normal file
19
resources/AsyncWebSerial/.github/workflows/dependabot.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
name: PlatformIO Dependabot
|
||||
|
||||
on:
|
||||
workflow_dispatch: # option to manually trigger the workflow
|
||||
schedule:
|
||||
# Runs every day at 00:00
|
||||
- cron: '0 0 * * *'
|
||||
|
||||
jobs:
|
||||
dependabot:
|
||||
runs-on: ubuntu-latest
|
||||
name: run PlatformIO Dependabot
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: run PlatformIO Dependabot
|
||||
uses: peterus/platformio_dependabot@v1
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
3
resources/AsyncWebSerial/.gitignore
vendored
Normal file
3
resources/AsyncWebSerial/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
/.pio
|
||||
/.vscode
|
||||
node_modules
|
||||
21
resources/AsyncWebSerial/LICENSE
Normal file
21
resources/AsyncWebSerial/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 Andrea Sessa
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
95
resources/AsyncWebSerial/README.md
Normal file
95
resources/AsyncWebSerial/README.md
Normal file
@@ -0,0 +1,95 @@
|
||||
# AsyncWebSerial
|
||||
|
||||
AsyncWebSerial: Simplify ESP32 debugging and logging with seamless browser-based serial communication.
|
||||
|
||||
## Features
|
||||
|
||||
- **Browser-Based Serial Access**: Log and debug ESP32 microcontrollers directly from a web browser using the Web Serial API.
|
||||
- **Real-Time Communication**: Stream logs and data in real time, eliminating the need for traditional serial monitors.
|
||||
- **Asynchronous Operation**: Leverages asynchronous processing for smooth and efficient communication.
|
||||
- **Cross-Platform Compatibility**: Works on any browser that supports the Web Serial API, no additional software required.
|
||||
- **Customizable Integration**: Easily integrates into ESP32 projects, enabling tailored debugging and logging workflows.
|
||||
- **User-Friendly Interface**: Provides an intuitive way to monitor and interact with the ESP32 during development.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- [AsyncTCP (mathieucarbou fork)](https://github.com/mathieucarbou/AsyncTCP)
|
||||
- [ESPAsyncWebServer (mathieucarbou fork)](https://github.com/mathieucarbou/ESPAsyncWebServer)
|
||||
|
||||
## Build web interface
|
||||
|
||||
Install frontend dependencies:
|
||||
|
||||
```bash
|
||||
yarn && yarn build
|
||||
```
|
||||
|
||||
## Implementation
|
||||
|
||||
### Add AsyncWebSerial to your platformIO project platformio.ini
|
||||
|
||||
```ini
|
||||
[env:esp32]
|
||||
platform = espressif32
|
||||
board = esp32dev
|
||||
framework = arduino
|
||||
monitor_speed = 115200
|
||||
lib_deps =
|
||||
circuitcode/AsyncWebSerial
|
||||
```
|
||||
|
||||
### Include the library in your code
|
||||
|
||||
```cpp
|
||||
#include <AsyncWebSerial.h>
|
||||
```
|
||||
|
||||
### Initialize the library
|
||||
|
||||
```cpp
|
||||
AsyncWebServer server(80);
|
||||
AsyncWebSerial webSerial;
|
||||
```
|
||||
|
||||
### Use the library
|
||||
|
||||
```cpp
|
||||
void setup() {
|
||||
webSerial.begin(&server);
|
||||
server.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
webSerial.loop();
|
||||
}
|
||||
```
|
||||
|
||||
### Send data to the AsyncWebSerial
|
||||
|
||||
```cpp
|
||||
webSerial.println("Hello, World!");
|
||||
webSerial.printf("Hello, %s!", "World");
|
||||
```
|
||||
|
||||
### Receive data from the AsyncWebSerial
|
||||
|
||||
You can use the `onMessage` method to receive data from the AsyncWebSerial. The method accepts a callback function that will be called when data is received. The callback function can accept both `const char *` and `String` data types.
|
||||
|
||||
```cpp
|
||||
webSerial.onMessage([](const char *data, size_t len) {
|
||||
Serial.write(data, len);
|
||||
});
|
||||
|
||||
webSerial.onMessage([](const String &msg) {
|
||||
Serial.println(msg);
|
||||
});
|
||||
```
|
||||
|
||||
### Connect to the device serial page
|
||||
|
||||
Navigate to `http://<device-ip>/webserial` to access the serial page.
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
||||
|
||||
18
resources/AsyncWebSerial/examples/demo/demo.ino
Normal file
18
resources/AsyncWebSerial/examples/demo/demo.ino
Normal file
@@ -0,0 +1,18 @@
|
||||
#include <Arduino.h>
|
||||
#include <AsyncWebSerial.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
|
||||
AsyncWebSerial webSerial;
|
||||
AsyncWebServer server(80);
|
||||
|
||||
void setup()
|
||||
{
|
||||
webSerial.begin(&server);
|
||||
server.begin();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
webSerial.loop();
|
||||
delay(10);
|
||||
}
|
||||
74
resources/AsyncWebSerial/frontend/build.js
Normal file
74
resources/AsyncWebSerial/frontend/build.js
Normal file
@@ -0,0 +1,74 @@
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const zlib = require("zlib");
|
||||
const htmlMinifier = require("html-minifier-terser").minify;
|
||||
|
||||
// Define paths
|
||||
const inputPath = path.join(__dirname, "index.html");
|
||||
const outputPath = path.join(__dirname, "../src/AsyncWebSerialHTML.h");
|
||||
|
||||
// Function to split buffer into 64-byte chunks
|
||||
function splitIntoChunks(buffer, chunkSize) {
|
||||
let chunks = [];
|
||||
for (let i = 0; i < buffer.length; i += chunkSize) {
|
||||
chunks.push(buffer.slice(i, i + chunkSize));
|
||||
}
|
||||
return chunks;
|
||||
}
|
||||
|
||||
(async function () {
|
||||
// read the index.html file
|
||||
const indexHtml = fs.readFileSync(inputPath, "utf8").toString();
|
||||
|
||||
// Minify the HTML content
|
||||
const minifiedHtml = await htmlMinifier(indexHtml, {
|
||||
collapseWhitespace: true,
|
||||
removeComments: true,
|
||||
removeAttributeQuotes: true,
|
||||
removeRedundantAttributes: true,
|
||||
removeScriptTypeAttributes: true,
|
||||
removeStyleLinkTypeAttributes: true,
|
||||
useShortDoctype: true,
|
||||
minifyCSS: true,
|
||||
minifyJS: true,
|
||||
shortAttributes: true,
|
||||
shortClassName: true,
|
||||
});
|
||||
|
||||
let oldSize = (indexHtml.length / 1024).toFixed(2);
|
||||
let newSize = (minifiedHtml.length / 1024).toFixed(2);
|
||||
|
||||
console.log(`[Minifier] Original: ${oldSize}KB | Minified: ${newSize}KB`);
|
||||
|
||||
// Gzip the minified HTML content
|
||||
let gzippedHtml = zlib.gzipSync(minifiedHtml);
|
||||
|
||||
// Recreate the AsyncWebSerialHTML.h file with the new gzipped content
|
||||
// the content is stored as a byte array split into 64 byte chunks to avoid issues with the IDE
|
||||
let content = `#ifndef AsyncWebSerial_HTML_H
|
||||
#define AsyncWebSerial_HTML_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
const uint8_t ASYNCWEBSERIAL_HTML[] PROGMEM = {\n`;
|
||||
|
||||
// Split gzipped HTML into 64-byte chunks
|
||||
let chunks = splitIntoChunks(gzippedHtml, 64);
|
||||
chunks.forEach((chunk, index) => {
|
||||
content += ` ${Array.from(chunk)
|
||||
.map((byte) => `0x${byte.toString(16).padStart(2, "0")}`)
|
||||
.join(", ")}`;
|
||||
if (index < chunks.length - 1) {
|
||||
content += ",\n";
|
||||
}
|
||||
});
|
||||
|
||||
content += `\n};
|
||||
|
||||
#endif // AsyncWebSerial_HTML_H`;
|
||||
|
||||
// Write the content to the output file
|
||||
fs.writeFileSync(outputPath, content);
|
||||
|
||||
console.log("AsyncWebSerialHTML.h file created successfully!");
|
||||
})();
|
||||
365
resources/AsyncWebSerial/frontend/index.html
Normal file
365
resources/AsyncWebSerial/frontend/index.html
Normal file
@@ -0,0 +1,365 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>NukiHub WebSerial</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style type="text/css">
|
||||
div {
|
||||
display: block;
|
||||
}
|
||||
|
||||
a {
|
||||
margin: 0.4rem;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
*,
|
||||
::after,
|
||||
::before {
|
||||
box-sizing: border-box;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
overscroll-behavior: none;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI",
|
||||
Roboto, "Helvetica Neue", sans-serif;
|
||||
background: #000;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.app {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
.gap-2 {
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1 1 0%;
|
||||
align-content: flex-end;
|
||||
height: 100%;
|
||||
color: #d4d4d8;
|
||||
font-family: monospace;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.content p {
|
||||
margin: 0;
|
||||
overflow-wrap: break-word;
|
||||
text-wrap: wrap;
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
.panel {
|
||||
position: relative;
|
||||
border: #fff 0.5rem solid;
|
||||
border-radius: 1rem;
|
||||
max-width: 45rem;
|
||||
width: calc(100% - 1rem);
|
||||
font-size: medium;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
border-bottom-width: 1px;
|
||||
flex-direction: row;
|
||||
column-gap: 1.5rem;
|
||||
padding-top: 0.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
padding-right: 0.5rem;
|
||||
color: #a1a1aa;
|
||||
}
|
||||
|
||||
.buttons button {
|
||||
cursor: pointer;
|
||||
padding: 8px 10px 8px;
|
||||
font-size: medium;
|
||||
outline-style: none;
|
||||
border: 0px;
|
||||
color: #a1a1aa;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.buttons button svg {
|
||||
width: 1.4rem;
|
||||
height: 1.4rem;
|
||||
}
|
||||
|
||||
.buttons button:hover {
|
||||
background-color: #18181b;
|
||||
}
|
||||
|
||||
.w-full {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.rounded {
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.grow {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.shadow {
|
||||
filter: drop-shadow(0 4px 3px rgb(0 0 0 / 0.07)) drop-shadow(0 2px 2px rgb(0 0 0 / 0.06));
|
||||
}
|
||||
|
||||
.items-center {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.command_container {
|
||||
border-top-width: 1px;
|
||||
border-bottom: 1px;
|
||||
border-color: #18181b;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
input {
|
||||
margin: 0;
|
||||
padding: .375rem .75rem;
|
||||
border: 0 solid #6b7280;
|
||||
border-radius: .25rem;
|
||||
font-family: monospace;
|
||||
font-size: .875rem;
|
||||
line-height: 1.5rem;
|
||||
background-color: #ffffff0d;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.command {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#submit-button {
|
||||
border: 0 solid #e5e7eb;
|
||||
margin: 0;
|
||||
text-transform: none;
|
||||
background-image: none;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: .25rem;
|
||||
padding: .5rem 1.5rem;
|
||||
font-size: .875rem;
|
||||
line-height: 1.25rem;
|
||||
color: #fff;
|
||||
background-color: rgb(29 78 216);
|
||||
}
|
||||
|
||||
#submit-button svg {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
}
|
||||
|
||||
.ml-4 {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
.connection-status {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
border-bottom-width: 1px;
|
||||
padding: 0.5rem 1rem;
|
||||
font-size: .75rem;
|
||||
line-height: 1rem;
|
||||
color: rgb(113 113 122);
|
||||
align-items: center;
|
||||
border-color: rgb(24 24 27);
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.badge {
|
||||
width: 0.375rem;
|
||||
height: 0.375rem;
|
||||
border-radius: 9999px;
|
||||
}
|
||||
|
||||
.badge.green {
|
||||
background-color: #22c55e;
|
||||
}
|
||||
|
||||
.badge.orange {
|
||||
background-color: #f59e0b;
|
||||
}
|
||||
|
||||
.badge.red {
|
||||
background-color: #ef4444;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="app">
|
||||
<header>
|
||||
<div class="buttons">
|
||||
<div>
|
||||
Buffer size:
|
||||
<input type="text" id="buffer" class="rounded shadow" placeholder="Buffer size" value="1000">
|
||||
</div>
|
||||
<button class="rounded shadow" onclick="terminalClean()">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M4 7l16 0" />
|
||||
<path d="M10 11l0 6" />
|
||||
<path d="M14 11l0 6" />
|
||||
<path d="M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2 -2l1 -12" />
|
||||
<path d="M9 7v-3a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v3" />
|
||||
</svg>
|
||||
</button>
|
||||
<button class="rounded shadow" onclick="enableScroll=!enableScroll">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M5 13a2 2 0 0 1 2 -2h10a2 2 0 0 1 2 2v6a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2v-6z" />
|
||||
<path d="M11 16a1 1 0 1 0 2 0a1 1 0 0 0 -2 0" />
|
||||
<path d="M8 11v-4a4 4 0 1 1 8 0v4" />
|
||||
</svg>
|
||||
</button>
|
||||
<button class="rounded shadow" onclick="enableTimestamp=!enableTimestamp">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0" />
|
||||
<path d="M12 7v5l3 3" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="content"></div>
|
||||
|
||||
<footer>
|
||||
<div class="command_container">
|
||||
<form class="flex w-full items-center">
|
||||
<input id="command" autocomplete="off" type="text" required="" class="command"
|
||||
placeholder="Enter command here">
|
||||
<div class="ml-4">
|
||||
<button id="submit-button" type="submit">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||||
stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M10 14l11 -11" />
|
||||
<path d="M21 3l-6.5 18a.55 .55 0 0 1 -1 0l-3.5 -7l-7 -3.5a.55 .55 0 0 1 0 -1l18 -6.5" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="connection-status"></div>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<script type="text/javascript">
|
||||
let enableScroll = true;
|
||||
let enableTimestamp = true;
|
||||
|
||||
let url = `ws://${window.location.hostname}/ws`;
|
||||
let websocket;
|
||||
let contentArea = document.querySelector('.content');
|
||||
let connectionStatus = document.querySelector('.connection-status');
|
||||
|
||||
initApp();
|
||||
|
||||
function initApp() {
|
||||
connectionStatus.innerHTML = '';
|
||||
initWebSocket();
|
||||
|
||||
document.querySelector('form').addEventListener('submit', function (e) {
|
||||
e.preventDefault();
|
||||
let command = document.getElementById('command').value;
|
||||
websocket.send(command);
|
||||
document.getElementById('command').value = '';
|
||||
});
|
||||
}
|
||||
|
||||
function initWebSocket() {
|
||||
connectionStatus.innerHTML = '<div class="badge orange"></div> Connecting...';
|
||||
websocket = new WebSocket(url);
|
||||
websocket.onopen = onOpen;
|
||||
websocket.onclose = onClose;
|
||||
websocket.onmessage = onMessage;
|
||||
}
|
||||
|
||||
function onOpen(event) {
|
||||
connectionStatus.innerHTML = '<div class="badge green"></div> Connected';
|
||||
terminalWrite('Connected to ' + url);
|
||||
}
|
||||
|
||||
function onClose(event) {
|
||||
connectionStatus.innerHTML = '<div class="badge red"></div> Disconnected';
|
||||
setTimeout(initWebSocket, 2000);
|
||||
}
|
||||
|
||||
function onMessage(event) {
|
||||
terminalWrite(event.data);
|
||||
}
|
||||
|
||||
function terminalWrite(data) {
|
||||
if (enableTimestamp) {
|
||||
let now = new Date();
|
||||
data = "[" + now.toLocaleTimeString() + "] " + data;
|
||||
}
|
||||
contentArea.innerHTML += '<p>' + data + '</p>';
|
||||
if (enableScroll) {
|
||||
contentArea.scrollTop = contentArea.scrollHeight;
|
||||
}
|
||||
|
||||
// Limit buffer size to avoid memory issues in the browser
|
||||
let bufferSize = parseInt(document.getElementById('buffer').value);
|
||||
if (isNaN(bufferSize)) {
|
||||
bufferSize = 1000;
|
||||
}
|
||||
|
||||
let lines = contentArea.querySelectorAll('p');
|
||||
if (lines.length > bufferSize) {
|
||||
for (let i = 0; i < lines.length - bufferSize; i++) {
|
||||
contentArea.removeChild(lines[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function terminalClean() {
|
||||
contentArea.innerHTML = '';
|
||||
}
|
||||
</script>
|
||||
|
||||
</html>
|
||||
12
resources/AsyncWebSerial/frontend/package.json
Normal file
12
resources/AsyncWebSerial/frontend/package.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"scripts": {
|
||||
"build": "node build.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"html-minifier-terser": "^7.1.0"
|
||||
},
|
||||
"license": "MIT",
|
||||
"files": [
|
||||
"LICENSE"
|
||||
]
|
||||
}
|
||||
168
resources/AsyncWebSerial/frontend/yarn.lock
Normal file
168
resources/AsyncWebSerial/frontend/yarn.lock
Normal file
@@ -0,0 +1,168 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@jridgewell/gen-mapping@^0.3.5":
|
||||
version "0.3.5"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36"
|
||||
integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==
|
||||
dependencies:
|
||||
"@jridgewell/set-array" "^1.2.1"
|
||||
"@jridgewell/sourcemap-codec" "^1.4.10"
|
||||
"@jridgewell/trace-mapping" "^0.3.24"
|
||||
|
||||
"@jridgewell/resolve-uri@^3.1.0":
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6"
|
||||
integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==
|
||||
|
||||
"@jridgewell/set-array@^1.2.1":
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280"
|
||||
integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==
|
||||
|
||||
"@jridgewell/source-map@^0.3.3":
|
||||
version "0.3.6"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.6.tgz#9d71ca886e32502eb9362c9a74a46787c36df81a"
|
||||
integrity sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==
|
||||
dependencies:
|
||||
"@jridgewell/gen-mapping" "^0.3.5"
|
||||
"@jridgewell/trace-mapping" "^0.3.25"
|
||||
|
||||
"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14":
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a"
|
||||
integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==
|
||||
|
||||
"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25":
|
||||
version "0.3.25"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0"
|
||||
integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==
|
||||
dependencies:
|
||||
"@jridgewell/resolve-uri" "^3.1.0"
|
||||
"@jridgewell/sourcemap-codec" "^1.4.14"
|
||||
|
||||
acorn@^8.8.2:
|
||||
version "8.14.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0"
|
||||
integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==
|
||||
|
||||
buffer-from@^1.0.0:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
|
||||
integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
|
||||
|
||||
camel-case@^4.1.2:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a"
|
||||
integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==
|
||||
dependencies:
|
||||
pascal-case "^3.1.2"
|
||||
tslib "^2.0.3"
|
||||
|
||||
clean-css@~5.3.2:
|
||||
version "5.3.3"
|
||||
resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.3.3.tgz#b330653cd3bd6b75009cc25c714cae7b93351ccd"
|
||||
integrity sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==
|
||||
dependencies:
|
||||
source-map "~0.6.0"
|
||||
|
||||
commander@^10.0.0:
|
||||
version "10.0.1"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06"
|
||||
integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==
|
||||
|
||||
commander@^2.20.0:
|
||||
version "2.20.3"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
|
||||
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
|
||||
|
||||
dot-case@^3.0.4:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751"
|
||||
integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==
|
||||
dependencies:
|
||||
no-case "^3.0.4"
|
||||
tslib "^2.0.3"
|
||||
|
||||
entities@^4.4.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48"
|
||||
integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==
|
||||
|
||||
html-minifier-terser@^7.1.0:
|
||||
version "7.2.0"
|
||||
resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-7.2.0.tgz#18752e23a2f0ed4b0f550f217bb41693e975b942"
|
||||
integrity sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA==
|
||||
dependencies:
|
||||
camel-case "^4.1.2"
|
||||
clean-css "~5.3.2"
|
||||
commander "^10.0.0"
|
||||
entities "^4.4.0"
|
||||
param-case "^3.0.4"
|
||||
relateurl "^0.2.7"
|
||||
terser "^5.15.1"
|
||||
|
||||
lower-case@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28"
|
||||
integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==
|
||||
dependencies:
|
||||
tslib "^2.0.3"
|
||||
|
||||
no-case@^3.0.4:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d"
|
||||
integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==
|
||||
dependencies:
|
||||
lower-case "^2.0.2"
|
||||
tslib "^2.0.3"
|
||||
|
||||
param-case@^3.0.4:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5"
|
||||
integrity sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==
|
||||
dependencies:
|
||||
dot-case "^3.0.4"
|
||||
tslib "^2.0.3"
|
||||
|
||||
pascal-case@^3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb"
|
||||
integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==
|
||||
dependencies:
|
||||
no-case "^3.0.4"
|
||||
tslib "^2.0.3"
|
||||
|
||||
relateurl@^0.2.7:
|
||||
version "0.2.7"
|
||||
resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9"
|
||||
integrity sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==
|
||||
|
||||
source-map-support@~0.5.20:
|
||||
version "0.5.21"
|
||||
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
|
||||
integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==
|
||||
dependencies:
|
||||
buffer-from "^1.0.0"
|
||||
source-map "^0.6.0"
|
||||
|
||||
source-map@^0.6.0, source-map@~0.6.0:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
|
||||
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
|
||||
|
||||
terser@^5.15.1:
|
||||
version "5.36.0"
|
||||
resolved "https://registry.yarnpkg.com/terser/-/terser-5.36.0.tgz#8b0dbed459ac40ff7b4c9fd5a3a2029de105180e"
|
||||
integrity sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==
|
||||
dependencies:
|
||||
"@jridgewell/source-map" "^0.3.3"
|
||||
acorn "^8.8.2"
|
||||
commander "^2.20.0"
|
||||
source-map-support "~0.5.20"
|
||||
|
||||
tslib@^2.0.3:
|
||||
version "2.8.1"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f"
|
||||
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
|
||||
33
resources/AsyncWebSerial/library.json
Normal file
33
resources/AsyncWebSerial/library.json
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "AsyncWebSerial",
|
||||
"version": "1.0.1",
|
||||
"keywords": "web serial, ESP32",
|
||||
"description": "AsyncWebSerial: Simplify ESP32 debugging and logging with seamless browser-based serial communication.",
|
||||
"homepage": "https://github.com/circuitcode/AsyncWebSerial",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/circuitcode/AsyncWebSerial.git"
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "Andrea Sessa",
|
||||
"maintanier": true
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"framworks": "arduino",
|
||||
"platforms": "espressif32",
|
||||
"headers": [
|
||||
"AsyncWebSerial.h"
|
||||
],
|
||||
"export": {
|
||||
"include": [
|
||||
"examples",
|
||||
"src",
|
||||
"library.json",
|
||||
"library.properties",
|
||||
"LICENSE",
|
||||
"README.md"
|
||||
]
|
||||
}
|
||||
}
|
||||
10
resources/AsyncWebSerial/library.properties
Normal file
10
resources/AsyncWebSerial/library.properties
Normal file
@@ -0,0 +1,10 @@
|
||||
name=AsyncWebSerial
|
||||
version=1.0.1
|
||||
author=Andrea Sessa <andrea.sessa@gmail.com>
|
||||
maintainer=Andrea Sessa <andrea.sessa@gmail.com>
|
||||
category=Device Control
|
||||
sentence=Browser-based logging and debugging for ESP32 using the Web Serial API.
|
||||
paragraph=AsyncWebSerial is a lightweight library designed for ESP32 microcontrollers, enabling developers to log and debug their projects directly from a web browser. Its asynchronous design ensures smooth communication, making it an ideal tool for modern ESP32 development workflows.
|
||||
url=https://github.com/circuitcode/AsyncWebSerial
|
||||
architectures=esp32
|
||||
license=MIT
|
||||
13
resources/AsyncWebSerial/platformio.ini
Normal file
13
resources/AsyncWebSerial/platformio.ini
Normal file
@@ -0,0 +1,13 @@
|
||||
[platformio]
|
||||
lib_dir = .
|
||||
|
||||
[env:esp32dev]
|
||||
platform = espressif32
|
||||
board = esp32dev
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
mathieucarbou/AsyncTCP@^3.2.14
|
||||
mathieucarbou/ESPAsyncWebServer@^3.3.23
|
||||
build_flags =
|
||||
-D CONFIG_ASYNC_TCP_QUEUE_SIZE=512
|
||||
-D CONFIG_ASYNC_TCP_RUNNING_CORE=1
|
||||
119
resources/AsyncWebSerial/src/AsyncWebSerial.cpp
Normal file
119
resources/AsyncWebSerial/src/AsyncWebSerial.cpp
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* AsyncWebSerial.cpp
|
||||
*
|
||||
* This file implements the AsyncWebSerial class, which provides a web-based serial interface
|
||||
* using an asynchronous web server and WebSocket communication. It allows for sending
|
||||
* and receiving serial data over a web interface, with optional authentication.
|
||||
*
|
||||
* Usage:
|
||||
* - Call begin() to initialize the AsyncWebSerial with a server and URL.
|
||||
* - Use onMessage() to set a callback for received messages.
|
||||
* - Use setAuthentication() to enable authentication for the web interface.
|
||||
* - Use the Print interface to send data to the web interface.
|
||||
* - Call loop() periodically to clean up inactive clients.
|
||||
*/
|
||||
|
||||
#include "AsyncWebSerial.h"
|
||||
#include "AsyncWebSerialHTML.h"
|
||||
|
||||
void AsyncWebSerial::begin(AsyncWebServer *server, const char *url)
|
||||
{
|
||||
_server = server;
|
||||
_socket = new AsyncWebSocket("/ws_serial");
|
||||
|
||||
if (_isAuthenticationRequired)
|
||||
_socket->setAuthentication(_username.c_str(), _password.c_str());
|
||||
|
||||
// handle web page request
|
||||
_server->on(url, HTTP_GET, [&](AsyncWebServerRequest *request) {
|
||||
if (_isAuthenticationRequired && !request->authenticate(_username.c_str(), _password.c_str()))
|
||||
return request->requestAuthentication();
|
||||
|
||||
AsyncWebServerResponse *response =
|
||||
request->beginResponse(200, "text/html", ASYNCWEBSERIAL_HTML, sizeof(ASYNCWEBSERIAL_HTML));
|
||||
response->addHeader("Content-Encoding", "gzip");
|
||||
request->send(response);
|
||||
});
|
||||
|
||||
// handle websocket connection
|
||||
_socket->onEvent([&](AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg,
|
||||
uint8_t *data, size_t len) {
|
||||
switch (type) {
|
||||
case WS_EVT_CONNECT:
|
||||
// set the client to not close when the queue is full
|
||||
client->setCloseClientOnQueueFull(false);
|
||||
break;
|
||||
case WS_EVT_DATA:
|
||||
if (len > 0) {
|
||||
// invoke the message received callback
|
||||
if (_onMessageReceived != nullptr)
|
||||
_onMessageReceived(data, len);
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
_server->addHandler(_socket);
|
||||
}
|
||||
|
||||
// onMessage callback setter
|
||||
void AsyncWebSerial::onMessage(WSMessageCallback callback)
|
||||
{
|
||||
_onMessageReceived = callback;
|
||||
}
|
||||
|
||||
// onMessage callback setter
|
||||
void AsyncWebSerial::onMessage(WSStringMessageCallback callback)
|
||||
{
|
||||
// keep a reference to the callback function
|
||||
_stringMessageCallback = callback;
|
||||
|
||||
// set the internal callback to convert the uint8_t data to a string and
|
||||
// call the string callback
|
||||
_onMessageReceived = [&](uint8_t *data, size_t len) {
|
||||
if (data && len) {
|
||||
String msg;
|
||||
msg.reserve(len);
|
||||
msg = String((char *)data, len);
|
||||
_stringMessageCallback(msg);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void AsyncWebSerial::setAuthentication(const String &username, const String &password)
|
||||
{
|
||||
_username = username;
|
||||
_password = password;
|
||||
_isAuthenticationRequired = !_username.isEmpty() && !_password.isEmpty();
|
||||
|
||||
// if the socket is already created, set the authentication immediately
|
||||
if (_socket != nullptr)
|
||||
_socket->setAuthentication(_username.c_str(), _password.c_str());
|
||||
}
|
||||
|
||||
void AsyncWebSerial::loop()
|
||||
{
|
||||
if (_socket)
|
||||
_socket->cleanupClients();
|
||||
}
|
||||
|
||||
// Print interface implementation
|
||||
size_t AsyncWebSerial::write(uint8_t m)
|
||||
{
|
||||
if (!_socket)
|
||||
return 0;
|
||||
|
||||
return write(&m, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Print interface implementation
|
||||
size_t AsyncWebSerial::write(const uint8_t *buffer, size_t size)
|
||||
{
|
||||
if (!_socket || size == 0)
|
||||
return 0;
|
||||
|
||||
String message((const char *)buffer, size);
|
||||
_socket->textAll(message);
|
||||
return size;
|
||||
}
|
||||
48
resources/AsyncWebSerial/src/AsyncWebSerial.h
Normal file
48
resources/AsyncWebSerial/src/AsyncWebSerial.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* @file AsyncWebSerial.h
|
||||
* @brief A web serial interface for the ESP32 microcontroller.
|
||||
* @license MIT License (https://opensource.org/licenses/MIT)
|
||||
*/
|
||||
|
||||
#ifndef AsyncWebSerial_h
|
||||
#define AsyncWebSerial_h
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <AsyncTCP.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <WiFi.h>
|
||||
#include <stdlib_noniso.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
// define the callable object type for the message received callback
|
||||
typedef std::function<void(uint8_t *data, size_t len)> WSMessageCallback;
|
||||
typedef std::function<void(const String &msg)> WSStringMessageCallback;
|
||||
|
||||
class AsyncWebSerial : public Print
|
||||
{
|
||||
public:
|
||||
void begin(AsyncWebServer *server, const char *url = "/webserial");
|
||||
|
||||
void setAuthentication(const String &username, const String &password);
|
||||
void onMessage(WSMessageCallback callback);
|
||||
void onMessage(WSStringMessageCallback callback);
|
||||
|
||||
void loop();
|
||||
|
||||
// Print interface implementation
|
||||
virtual size_t write(uint8_t) override;
|
||||
virtual size_t write(const uint8_t *buffer, size_t size) override;
|
||||
|
||||
private:
|
||||
AsyncWebServer *_server;
|
||||
AsyncWebSocket *_socket;
|
||||
bool _isAuthenticationRequired = false;
|
||||
String _username;
|
||||
String _password;
|
||||
|
||||
WSMessageCallback _onMessageReceived = nullptr;
|
||||
WSStringMessageCallback _stringMessageCallback = nullptr;
|
||||
};
|
||||
|
||||
#endif // AsyncWebSerial_h
|
||||
46
resources/AsyncWebSerial/src/AsyncWebSerialHTML.h
Normal file
46
resources/AsyncWebSerial/src/AsyncWebSerialHTML.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#ifndef AsyncWebSerial_HTML_H
|
||||
#define AsyncWebSerial_HTML_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
const uint8_t ASYNCWEBSERIAL_HTML[] PROGMEM = {
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xdd, 0x59, 0x61, 0x8f, 0xdb, 0x36, 0x12, 0xfd, 0x2b, 0xac, 0xf6, 0x9a, 0x48, 0xb7, 0xa6, 0x2c, 0xc9, 0xf6, 0xae, 0x57, 0xb2, 0x0c, 0x24, 0x9b, 0x1c, 0x12, 0x20, 0xc9, 0x01, 0xb7, 0x29, 0x7a, 0x40, 0x51, 0xb4, 0x94, 0x34, 0xb2, 0xd9, 0xa5, 0x48, 0x95, 0xa2, 0x6c, 0x6f, 0x04, 0xff, 0xf7, 0x03, 0x29, 0xd9, 0x96, 0xec, 0x4d,
|
||||
0xdb, 0xe0, 0xbe, 0x35, 0x89, 0x2d, 0x71, 0x38, 0xe4, 0x90, 0x6f, 0xde, 0x0c, 0xc7, 0xcc, 0xe2, 0xbb, 0x4c, 0xa4, 0xea, 0xa9, 0x04, 0xb4, 0x56, 0x05, 0x5b, 0x2e, 0xba, 0x6f, 0x20, 0xd9, 0x72, 0x51, 0x80, 0x22, 0x28, 0x5d, 0x13, 0x59, 0x81, 0x8a, 0x6b, 0x95, 0xe3, 0x79, 0x27, 0x5b, 0x2b, 0x55, 0x62, 0xf8, 0xbd, 0xa6, 0x9b, 0xf8, 0xbf, 0xf8, 0x87, 0x57, 0xf8, 0x5e, 0x14, 0x25, 0x51,
|
||||
0x34, 0x61, 0x80, 0x52, 0xc1, 0x15, 0x70, 0x15, 0x5b, 0xef, 0xdf, 0xc6, 0x90, 0xad, 0xc0, 0x5a, 0x2e, 0x14, 0x55, 0x0c, 0x96, 0xaf, 0xaa, 0x27, 0x9e, 0xfe, 0x08, 0xc9, 0x03, 0x48, 0x4a, 0xd8, 0x62, 0xdc, 0x4a, 0xdb, 0xf9, 0x38, 0x29, 0x20, 0xde, 0x50, 0xd8, 0x96, 0x42, 0xaa, 0xd3, 0x14, 0x5b, 0x9a, 0xa9, 0x75, 0x9c, 0xc1, 0x86, 0xa6, 0x80, 0x4d, 0x63, 0x44, 0x39, 0x55, 0x94, 0x30,
|
||||
0x5c, 0xa5, 0x84, 0x41, 0xec, 0x5b, 0xcb, 0x45, 0xa5, 0x9e, 0x18, 0x2c, 0x33, 0xba, 0x69, 0x32, 0x5a, 0x95, 0x8c, 0x3c, 0x85, 0x09, 0x13, 0xe9, 0xe3, 0x9e, 0x34, 0x05, 0x91, 0x2b, 0xca, 0x43, 0x77, 0x2a, 0xa1, 0x88, 0x14, 0xec, 0x14, 0xce, 0x20, 0x15, 0x92, 0x28, 0x2a, 0x78, 0xc8, 0x05, 0x87, 0xfd, 0x3f, 0x47, 0x61, 0x48, 0x72, 0x05, 0x72, 0x14, 0x86, 0x09, 0xe4, 0x42, 0x42, 0x93,
|
||||
0x88, 0x1d, 0xae, 0xe8, 0x17, 0xca, 0x57, 0x61, 0x22, 0x64, 0x06, 0x12, 0x27, 0x62, 0x17, 0x75, 0xaf, 0x66, 0x0d, 0xa1, 0xb7, 0xd7, 0x20, 0x35, 0x6b, 0xa0, 0xab, 0xb5, 0x0a, 0x7d, 0xcf, 0xfb, 0x7e, 0x9f, 0x88, 0xec, 0xa9, 0x11, 0x1b, 0x90, 0x55, 0x2a, 0x05, 0x63, 0x38, 0x81, 0x35, 0xd9, 0x50, 0x21, 0x8d, 0x99, 0xa8, 0xa7, 0x19, 0xb5, 0x53, 0x98, 0xd7, 0x6e, 0x7d, 0x5e, 0x54, 0x92,
|
||||
0x2c, 0xd3, 0x06, 0xbd, 0x28, 0x17, 0x5c, 0xe1, 0x9c, 0x14, 0x94, 0x3d, 0x85, 0x98, 0x94, 0x25, 0x03, 0x5c, 0x3d, 0x55, 0x0a, 0x8a, 0x51, 0xfb, 0xc0, 0x35, 0x1d, 0xbd, 0x66, 0x94, 0x3f, 0x7e, 0x24, 0xe9, 0x83, 0x91, 0xfc, 0x4b, 0x70, 0x35, 0xb2, 0x1e, 0x60, 0x25, 0x00, 0xfd, 0xf0, 0xde, 0x1a, 0xfd, 0x47, 0x24, 0x42, 0x89, 0x91, 0xf5, 0x0e, 0xd8, 0x06, 0x14, 0x4d, 0x09, 0xfa, 0x04,
|
||||
0x35, 0x58, 0xa3, 0x8a, 0xf0, 0x0a, 0x57, 0x20, 0x69, 0x1e, 0x25, 0x24, 0x7d, 0x5c, 0x49, 0x51, 0xf3, 0x2c, 0xbc, 0xf2, 0x3c, 0xaf, 0xbf, 0xbc, 0xbd, 0x4b, 0xca, 0xb2, 0xbf, 0xb3, 0xe8, 0x00, 0x6a, 0xce, 0x60, 0x17, 0xe9, 0x2f, 0x9c, 0x51, 0x09, 0xa9, 0xc1, 0x30, 0x15, 0xac, 0x2e, 0xf8, 0xde, 0x5d, 0x49, 0x9a, 0x1d, 0xd1, 0xd7, 0x8d, 0xbd, 0xbb, 0x22, 0x25, 0x0e, 0x9a, 0x15, 0x29,
|
||||
0x43, 0x77, 0x26, 0xa1, 0xd8, 0xbb, 0x9d, 0x53, 0x1b, 0x3d, 0x45, 0xe8, 0x23, 0x1f, 0x79, 0xdf, 0x47, 0x84, 0xd1, 0x15, 0xc7, 0x5d, 0x8f, 0xb1, 0x80, 0x81, 0x67, 0x03, 0xb8, 0x52, 0xc1, 0x84, 0x0c, 0xaf, 0xb2, 0x69, 0x36, 0xcd, 0xe6, 0x03, 0x78, 0x0a, 0xc1, 0x45, 0x55, 0x92, 0x14, 0x22, 0x8d, 0x7b, 0xce, 0xc4, 0x16, 0xef, 0xc2, 0x35, 0xcd, 0x32, 0xe0, 0x27, 0xc9, 0x53, 0x48, 0x6a,
|
||||
0x25, 0xda, 0x71, 0x15, 0xfd, 0x02, 0xa1, 0x3f, 0x2d, 0x77, 0xc7, 0xc5, 0xa0, 0xb2, 0x39, 0xfa, 0xe0, 0x38, 0x64, 0x2b, 0x49, 0x19, 0x26, 0x12, 0xc8, 0x23, 0xde, 0x0a, 0x99, 0xb5, 0xc4, 0x31, 0x42, 0xfd, 0x15, 0x6d, 0xd7, 0x54, 0x01, 0x36, 0x86, 0xc3, 0x52, 0x02, 0x66, 0x94, 0xc3, 0xde, 0x2d, 0x09, 0x07, 0xd6, 0x94, 0xa2, 0xa2, 0x06, 0x18, 0x09, 0x8c, 0x28, 0xba, 0x81, 0x8e, 0x37,
|
||||
0xe1, 0x55, 0x9e, 0xe7, 0xc8, 0x00, 0x81, 0x2a, 0xc1, 0x68, 0x76, 0xe0, 0x93, 0x24, 0x19, 0xad, 0xab, 0xd0, 0xd7, 0x04, 0x2d, 0xc8, 0xae, 0xe3, 0xd7, 0x54, 0x2b, 0x76, 0x44, 0x49, 0x09, 0x4b, 0x6d, 0x8d, 0x04, 0xc2, 0x48, 0xab, 0x39, 0xbd, 0xbd, 0x14, 0x90, 0xd1, 0xba, 0xd8, 0xbb, 0x49, 0xad, 0x94, 0xe0, 0x55, 0x33, 0x70, 0x55, 0x8b, 0x2d, 0x55, 0x50, 0x54, 0x61, 0x0a, 0x5c, 0x81,
|
||||
0x8c, 0x7e, 0xab, 0x2b, 0x45, 0xf3, 0xa7, 0x4b, 0xc0, 0x5b, 0x10, 0x30, 0x83, 0x5c, 0xb5, 0x78, 0x75, 0x02, 0x69, 0xfc, 0x60, 0x24, 0xc7, 0x58, 0x50, 0x4a, 0x14, 0xdd, 0x3a, 0xfd, 0xf2, 0x82, 0x11, 0x52, 0x6c, 0xa3, 0x96, 0x15, 0x58, 0xfb, 0xde, 0x37, 0x7b, 0x3e, 0xf0, 0x1b, 0x2b, 0xd1, 0xd1, 0xe1, 0x28, 0x69, 0xe7, 0x3b, 0x13, 0xb6, 0x66, 0x5b, 0x59, 0xe7, 0x7f, 0xe2, 0x13, 0x9f,
|
||||
0x90, 0xe3, 0x56, 0x51, 0xfb, 0x6c, 0xd2, 0x5a, 0x56, 0x42, 0x86, 0xa5, 0xa0, 0x66, 0x83, 0x87, 0x38, 0x9a, 0x97, 0x3b, 0xe4, 0x7b, 0xe5, 0x0e, 0xcd, 0xf5, 0x0a, 0xcf, 0xf0, 0x8a, 0x44, 0xad, 0xb4, 0xd3, 0xb0, 0x49, 0x1c, 0x6d, 0x80, 0x76, 0x6e, 0xf2, 0x86, 0xe6, 0x7a, 0x81, 0x82, 0xdb, 0x0e, 0x25, 0x09, 0xaf, 0x4a, 0x22, 0x81, 0xab, 0xf3, 0xb5, 0xa0, 0x6a, 0xb3, 0x6a, 0x3a, 0x5c,
|
||||
0xda, 0x8c, 0x73, 0xa0, 0xb1, 0x69, 0x9d, 0xab, 0x87, 0x6b, 0x4d, 0xb8, 0xe6, 0xc2, 0xc2, 0x95, 0x3f, 0xf7, 0xe7, 0x7e, 0xb2, 0x77, 0xb7, 0x38, 0xaf, 0x19, 0x6b, 0x4e, 0xe9, 0x62, 0xef, 0x1a, 0x3d, 0xc8, 0x9a, 0x21, 0x79, 0xba, 0xf8, 0xd2, 0x8e, 0x18, 0x30, 0x40, 0x87, 0xa5, 0xd8, 0x9a, 0x78, 0xc3, 0xfa, 0x2d, 0xf4, 0xf7, 0x6e, 0xb5, 0x26, 0x99, 0x96, 0x51, 0xa6, 0x40, 0x86, 0x99,
|
||||
0x14, 0x25, 0x6e, 0x45, 0xb6, 0x87, 0xa6, 0xe5, 0x0e, 0x4d, 0xca, 0x1d, 0x92, 0xab, 0xc4, 0xf6, 0x90, 0xfe, 0x3b, 0x46, 0xae, 0x77, 0xeb, 0x38, 0x68, 0xa8, 0x17, 0x94, 0x3b, 0xf3, 0x19, 0xea, 0xdd, 0x38, 0xce, 0xde, 0x35, 0x6c, 0xc3, 0x2d, 0xdb, 0x9a, 0x4b, 0x02, 0xea, 0xb8, 0x2b, 0x0a, 0xc2, 0xb3, 0x5f, 0x34, 0x03, 0x09, 0xe5, 0x1a, 0x80, 0x76, 0x2f, 0x4a, 0x94, 0x3d, 0x52, 0x0d,
|
||||
0xc8, 0xd6, 0x97, 0x0c, 0x30, 0x8a, 0xbe, 0x95, 0xef, 0x26, 0x68, 0x71, 0x02, 0x6a, 0x0b, 0xc0, 0x8f, 0x64, 0xd1, 0x51, 0xb5, 0xa7, 0xbc, 0xac, 0x55, 0x73, 0x91, 0x90, 0xdd, 0xc9, 0xad, 0x09, 0x5a, 0xd7, 0x3c, 0x8e, 0x34, 0x69, 0x83, 0x18, 0x5d, 0xdd, 0x24, 0xb7, 0xc1, 0xdc, 0x3b, 0x0b, 0x66, 0x37, 0x30, 0xba, 0xcf, 0xa7, 0xaa, 0x13, 0x19, 0xdd, 0x79, 0x3b, 0xa7, 0xa1, 0xe2, 0x91,
|
||||
0x2a, 0xad, 0x99, 0x0b, 0x52, 0xe4, 0xe6, 0x8f, 0x97, 0x45, 0xa7, 0xf6, 0x11, 0xcc, 0x3e, 0x45, 0xae, 0xaa, 0x3a, 0x29, 0xa8, 0xc2, 0x5d, 0x78, 0x9c, 0xaf, 0x17, 0x66, 0x70, 0x0b, 0xc9, 0xe9, 0xdc, 0x31, 0xa9, 0xcd, 0x70, 0x3a, 0x17, 0xb2, 0xe8, 0x42, 0xe1, 0x64, 0x9c, 0x16, 0x64, 0xd5, 0x05, 0xc8, 0x59, 0xa0, 0x0d, 0x90, 0xef, 0x9d, 0x68, 0x7f, 0xc1, 0x09, 0x9d, 0xf8, 0x59, 0xcc,
|
||||
0x8e, 0xb0, 0x1b, 0xd0, 0x3b, 0x34, 0xfe, 0x0c, 0xb2, 0xa0, 0x9f, 0x27, 0xf2, 0x3c, 0xbf, 0x84, 0x4f, 0x33, 0x35, 0xb8, 0x43, 0xb7, 0x73, 0x14, 0xf8, 0x37, 0xce, 0x19, 0x48, 0xfd, 0xb8, 0xed, 0x47, 0xad, 0x09, 0xaa, 0x82, 0xe1, 0x69, 0xd3, 0xcf, 0x8e, 0xfe, 0xe1, 0x2c, 0xe3, 0x6d, 0xc2, 0xc3, 0x95, 0x22, 0xaa, 0x3e, 0x4b, 0xbd, 0x5f, 0xcd, 0xb3, 0x5f, 0x4b, 0xa2, 0x67, 0xfb, 0x3e,
|
||||
0xdb, 0xf5, 0x33, 0x9b, 0x3e, 0xed, 0x58, 0xef, 0xcd, 0xf7, 0x27, 0xc8, 0x7c, 0x82, 0xc0, 0x79, 0xce, 0x05, 0x83, 0xe0, 0x31, 0x60, 0x4c, 0x91, 0xfe, 0x77, 0xeb, 0x44, 0xbd, 0x03, 0x3a, 0x21, 0xd9, 0x0a, 0x3a, 0x24, 0x3a, 0xde, 0x1f, 0xc0, 0x38, 0x34, 0x87, 0x4e, 0xbb, 0xbb, 0xbb, 0xbb, 0xd3, 0x87, 0xa9, 0x19, 0xe8, 0xae, 0x24, 0x00, 0x7f, 0x26, 0x9f, 0x05, 0x41, 0x3a, 0x9b, 0xc1,
|
||||
0x41, 0x4b, 0x48, 0xc2, 0x57, 0xf0, 0x8c, 0x5a, 0x3e, 0xbb, 0x03, 0x2f, 0x39, 0xa8, 0x49, 0x9d, 0xe5, 0x2e, 0x74, 0x20, 0x9f, 0x4e, 0xa7, 0xd3, 0xfd, 0x62, 0xdc, 0x96, 0x7c, 0x8b, 0x71, 0x5b, 0xa5, 0xea, 0xda, 0x6b, 0xb9, 0xc8, 0xe8, 0x06, 0xa5, 0x8c, 0x54, 0x55, 0x4c, 0xca, 0xb2, 0x2d, 0x60, 0x41, 0xf6, 0xc5, 0x5d, 0xfe, 0x35, 0xa2, 0xe5, 0xeb, 0x3a, 0xcf, 0x41, 0x22, 0x03, 0x30,
|
||||
0x5a, 0x98, 0xe8, 0x47, 0x34, 0x8b, 0x93, 0x56, 0xdc, 0x0e, 0xb0, 0xba, 0x7c, 0x8b, 0xda, 0xd4, 0x67, 0xa1, 0x92, 0x91, 0x14, 0xd6, 0x82, 0x65, 0x20, 0x63, 0xab, 0x37, 0x83, 0x85, 0x36, 0x84, 0xd5, 0x10, 0xfb, 0x9e, 0xe7, 0x2d, 0x17, 0x63, 0x3d, 0xff, 0xa2, 0x23, 0xd7, 0x57, 0x66, 0x12, 0x3c, 0x65, 0x34, 0x7d, 0x8c, 0x15, 0xc8, 0x82, 0x72, 0xc2, 0xee, 0x19, 0x10, 0x6e, 0x3b, 0xcb,
|
||||
0x45, 0xb5, 0x59, 0xa1, 0x5d, 0xc1, 0x78, 0x15, 0xeb, 0x12, 0x3b, 0x1c, 0x8f, 0xb7, 0xdb, 0xad, 0xbb, 0x9d, 0xb8, 0x42, 0xae, 0xc6, 0x81, 0xe7, 0x79, 0x63, 0xad, 0xd0, 0x96, 0xc5, 0xc1, 0x14, 0xb5, 0xee, 0xd1, 0x6f, 0xba, 0x76, 0x7e, 0x2d, 0x76, 0xb1, 0xa5, 0xf3, 0xb1, 0x71, 0xaf, 0x85, 0x72, 0xca, 0x58, 0xac, 0xa3, 0x17, 0x55, 0x4a, 0x8a, 0x47, 0x88, 0xd3, 0x5a, 0xea, 0x93, 0xeb,
|
||||
0x5e, 0xa3, 0xd9, 0xc9, 0x70, 0x37, 0xd7, 0xa1, 0xa9, 0x59, 0x96, 0x92, 0x32, 0x36, 0x0b, 0xee, 0x0b, 0x7f, 0x13, 0x94, 0xb7, 0xd2, 0xe5, 0xa2, 0x24, 0x6a, 0x7d, 0x98, 0xd3, 0xcc, 0x9f, 0xc5, 0xd6, 0x47, 0x0f, 0x79, 0xeb, 0x60, 0xba, 0x09, 0xa6, 0xef, 0xbc, 0x2f, 0x7d, 0xdb, 0xe3, 0x4e, 0x5f, 0xeb, 0x4c, 0xd1, 0x2d, 0xf3, 0x6f, 0x90, 0x67, 0xf5, 0x85, 0xbe, 0x87, 0x7c, 0x9f, 0x79,
|
||||
0xe8, 0x66, 0x28, 0x9d, 0x3e, 0x27, 0x9d, 0xe9, 0x09, 0x90, 0x1f, 0x90, 0x00, 0x05, 0xa8, 0x3d, 0x7c, 0x02, 0x14, 0xac, 0xe7, 0x83, 0x36, 0x0e, 0x98, 0x8f, 0xb0, 0x1f, 0x0c, 0x46, 0xde, 0xa1, 0xdb, 0x0d, 0x9e, 0x10, 0x53, 0x78, 0x22, 0x0f, 0xe9, 0x27, 0xf6, 0xd7, 0xd3, 0x81, 0xc0, 0xdf, 0x4c, 0xf4, 0x18, 0x8d, 0xf1, 0x72, 0x31, 0x6e, 0x3d, 0xb8, 0x44, 0x7f, 0xd1, 0x95, 0x16, 0x70,
|
||||
0x92, 0x30, 0x78, 0x30, 0xf5, 0x7f, 0xfc, 0x5d, 0xbf, 0x65, 0xfd, 0xdd, 0xfd, 0x3a, 0x43, 0xfe, 0xe4, 0xe8, 0x02, 0xdf, 0xb8, 0x60, 0xed, 0x7b, 0x03, 0x49, 0xb0, 0xb9, 0xe9, 0xb5, 0xb1, 0xf6, 0x1a, 0x1e, 0xa8, 0x60, 0x3d, 0x6a, 0x83, 0x6f, 0xbe, 0x0c, 0x69, 0xe0, 0x23, 0xff, 0xa6, 0x73, 0x92, 0x6f, 0xbc, 0xeb, 0x1d, 0x5d, 0xe6, 0xe9, 0x31, 0x43, 0x2e, 0xcd, 0x91, 0xef, 0x6f, 0xf0,
|
||||
0x94, 0x4c, 0xd1, 0xb4, 0xf3, 0xe9, 0x1c, 0x79, 0x9b, 0xe9, 0xff, 0xed, 0xd5, 0xcf, 0xb4, 0x80, 0x4a, 0x91, 0xa2, 0x3c, 0x38, 0xf6, 0x28, 0xf8, 0xdb, 0xfb, 0x56, 0x1f, 0x2b, 0xe4, 0x0e, 0xdd, 0x75, 0x0e, 0xf0, 0xe7, 0xc8, 0xeb, 0x9a, 0xc6, 0x03, 0xba, 0x3d, 0xf4, 0x58, 0x80, 0x6e, 0x37, 0x33, 0x36, 0x41, 0xcf, 0xc4, 0x52, 0x97, 0x1b, 0xc7, 0x97, 0xc9, 0xb9, 0x3b, 0x2a, 0x0f, 0x1a,
|
||||
0xb9, 0x10, 0xea, 0x5c, 0xe1, 0xac, 0x72, 0xd4, 0x4a, 0xb2, 0x38, 0xf8, 0x4f, 0x1f, 0xb1, 0xa8, 0x2d, 0x99, 0x51, 0xbf, 0x0a, 0xb5, 0x96, 0xa7, 0xe4, 0xde, 0x4d, 0x81, 0xf4, 0xef, 0x99, 0x54, 0x14, 0x25, 0x03, 0x05, 0xb1, 0xc8, 0x73, 0x24, 0xf5, 0x4d, 0x86, 0x84, 0x2c, 0xb6, 0xac, 0xa1, 0xb5, 0x61, 0xc6, 0x7f, 0xab, 0x27, 0x44, 0x87, 0xae, 0x35, 0x48, 0x7d, 0xb7, 0x71, 0x5a, 0xa1,
|
||||
0xae, 0x15, 0x8e, 0x79, 0x9f, 0x66, 0xf1, 0xb0, 0xca, 0xd0, 0x37, 0x2c, 0x9d, 0xe8, 0xef, 0xce, 0x18, 0x9d, 0xd0, 0xa7, 0xcc, 0xd7, 0x09, 0xd6, 0x1f, 0x50, 0x23, 0xf0, 0xd1, 0x84, 0xe1, 0x1b, 0x77, 0x86, 0xfc, 0x39, 0x71, 0x67, 0x33, 0xa4, 0x3f, 0x5d, 0xf4, 0xfb, 0xc8, 0x63, 0x78, 0xe2, 0xce, 0x10, 0xbe, 0x65, 0xf8, 0x16, 0xe9, 0xd7, 0x33, 0x15, 0x4d, 0x36, 0xe6, 0xcf, 0x91, 0x9e,
|
||||
0xe0, 0xeb, 0xd4, 0xd2, 0xa4, 0x38, 0x34, 0x06, 0xf4, 0x1a, 0x16, 0x6c, 0x3d, 0xfd, 0x96, 0x69, 0x5d, 0xb3, 0xad, 0x25, 0xaa, 0x54, 0xd2, 0x52, 0x2d, 0x19, 0x28, 0xb4, 0x85, 0xa4, 0x12, 0xe9, 0x23, 0xa8, 0xd1, 0x30, 0xbf, 0x7b, 0xa3, 0x8b, 0xcc, 0xe0, 0x8d, 0x6a, 0xc9, 0xe2, 0x5f, 0xb7, 0x55, 0x38, 0x1e, 0xff, 0xa3, 0xd9, 0x52, 0x9e, 0x89, 0xad, 0xcb, 0x44, 0x6a, 0xee, 0x9b, 0xdc,
|
||||
0xb5, 0xa8, 0x94, 0xbe, 0xe6, 0xda, 0x87, 0x97, 0x7d, 0xfa, 0xd6, 0x6b, 0x3f, 0xde, 0x56, 0xbf, 0x54, 0xe6, 0x6e, 0xec, 0xd7, 0x51, 0x17, 0x0e, 0xaf, 0x24, 0x90, 0x38, 0x13, 0x69, 0x5d, 0x00, 0x57, 0xee, 0xef, 0x35, 0xc8, 0xa7, 0x07, 0x60, 0x90, 0x2a, 0x21, 0x6d, 0xeb, 0x70, 0x89, 0x61, 0x39, 0xa3, 0xd3, 0xf6, 0x1e, 0xcc, 0xee, 0xfe, 0x70, 0xcc, 0x10, 0x08, 0xcb, 0x89, 0xf2, 0x9a,
|
||||
0x1b, 0x09, 0xd2, 0x77, 0x6b, 0xaf, 0xca, 0xd2, 0x76, 0x9a, 0xf3, 0x09, 0x5d, 0xca, 0x39, 0xc8, 0x77, 0x9f, 0x3f, 0x7e, 0x88, 0x2d, 0xcb, 0xdc, 0xc1, 0xe9, 0x8b, 0x3c, 0x83, 0x8b, 0xed, 0x8c, 0xbe, 0x66, 0x4d, 0xfb, 0xc2, 0x72, 0x5c, 0x92, 0x65, 0x6f, 0x37, 0xc0, 0xd5, 0x07, 0x5a, 0x29, 0xe0, 0x20, 0x6d, 0xab, 0x8d, 0x03, 0x6b, 0x64, 0x1f, 0x4c, 0xdb, 0xe0, 0x34, 0xe0, 0x96, 0x12,
|
||||
0xb4, 0xde, 0x1b, 0xc8, 0x49, 0xcd, 0x94, 0xed, 0x44, 0xda, 0x01, 0xfc, 0xb4, 0x99, 0x15, 0xa8, 0xb7, 0x0c, 0xf4, 0xeb, 0xeb, 0xa7, 0xf7, 0x99, 0x6d, 0x75, 0xa1, 0x68, 0x39, 0xae, 0xa9, 0xbf, 0xa2, 0xa3, 0xaf, 0xdc, 0x0a, 0x78, 0x66, 0xf3, 0xde, 0xca, 0xfe, 0x64, 0x68, 0x6c, 0x59, 0x7b, 0xc7, 0xd9, 0x0f, 0x90, 0xe8, 0xed, 0xf0, 0x8f, 0xf0, 0x78, 0xd9, 0xa3, 0x99, 0x65, 0xaa, 0x57,
|
||||
0xd4, 0x16, 0xb9, 0x56, 0x47, 0x2a, 0x74, 0xdf, 0x0d, 0xe6, 0x2b, 0xd7, 0x75, 0x5f, 0x8e, 0x8e, 0xab, 0x8c, 0x39, 0x6c, 0xd1, 0xc9, 0x4a, 0x2d, 0x99, 0x73, 0xea, 0x74, 0x05, 0x17, 0x25, 0xf0, 0x58, 0xf0, 0x7f, 0x97, 0xc0, 0x07, 0xf2, 0x94, 0x89, 0x0a, 0x62, 0xc1, 0xef, 0xf5, 0x73, 0xd0, 0x53, 0x40, 0x55, 0x91, 0x95, 0xee, 0xfb, 0xd8, 0xbe, 0x9d, 0x76, 0xd4, 0xce, 0xa3, 0x71, 0xfe,
|
||||
0xb6, 0xbd, 0x98, 0xb2, 0xfe, 0x7c, 0x2b, 0x90, 0xbd, 0x1c, 0x1d, 0x4a, 0xd7, 0x1f, 0x25, 0x55, 0x60, 0x5b, 0xc7, 0x1e, 0xa4, 0x04, 0xb2, 0xae, 0xf5, 0x66, 0xfa, 0xc6, 0xcd, 0x5a, 0xbf, 0xdd, 0xba, 0x84, 0xec, 0x68, 0xfb, 0x0d, 0xad, 0xd2, 0x93, 0xf9, 0x0a, 0x94, 0x0e, 0x3d, 0x51, 0x2b, 0x7b, 0xe0, 0xac, 0x51, 0x00, 0x93, 0x81, 0xe5, 0x0e, 0x09, 0x6d, 0x7b, 0xb8, 0x64, 0x70, 0x33,
|
||||
0xa2, 0x48, 0x4f, 0xf7, 0xac, 0xdb, 0x69, 0x68, 0x6e, 0x9f, 0x05, 0xb9, 0xd3, 0x40, 0x6c, 0xfd, 0x64, 0x5d, 0xdb, 0xda, 0x75, 0x6f, 0x88, 0x02, 0xc7, 0x55, 0xe2, 0x83, 0xd0, 0x77, 0xd1, 0x5a, 0xe7, 0x41, 0x49, 0xca, 0x57, 0xb6, 0x73, 0x6d, 0xfd, 0x8c, 0xac, 0x6b, 0xd8, 0xf7, 0xc2, 0xf8, 0xb4, 0xcf, 0xeb, 0xd8, 0x5a, 0x94, 0x4b, 0xeb, 0x1a, 0xae, 0xad, 0xc5, 0xb8, 0x5c, 0x5a, 0x83,
|
||||
0xc4, 0xf2, 0xe2, 0x85, 0xdd, 0x1f, 0xd4, 0xde, 0x26, 0x7f, 0x16, 0x65, 0x7c, 0x29, 0x7d, 0x67, 0x8e, 0x85, 0x43, 0x90, 0x94, 0xfa, 0x92, 0xfe, 0x3d, 0x57, 0xf6, 0x57, 0x29, 0xdf, 0xfe, 0xb6, 0x39, 0x30, 0xde, 0x89, 0x68, 0xf5, 0x89, 0x7c, 0xb2, 0xb9, 0xf3, 0xe2, 0x85, 0xcd, 0x63, 0x1f, 0x26, 0xed, 0x4c, 0x6a, 0x60, 0x69, 0x10, 0xd0, 0xaf, 0x18, 0xb3, 0xad, 0xd2, 0x72, 0x22, 0x9a,
|
||||
0xdb, 0xca, 0x65, 0xc0, 0x57, 0x6a, 0xbd, 0xe4, 0x4e, 0x2e, 0xa4, 0xad, 0x47, 0x42, 0xec, 0x45, 0xb0, 0x38, 0x74, 0x60, 0x1e, 0xc1, 0xf5, 0xb5, 0xd3, 0x9f, 0x4c, 0x42, 0x21, 0x36, 0x70, 0xbf, 0xa6, 0x2c, 0xb3, 0xd5, 0x4f, 0xf0, 0xf3, 0x33, 0xd0, 0x77, 0xbf, 0x83, 0x9a, 0x67, 0x81, 0xd3, 0x41, 0x7a, 0x4c, 0x51, 0x8b, 0x71, 0x97, 0xa4, 0x17, 0x63, 0xf3, 0x3f, 0x16, 0xff, 0x03, 0xd8,
|
||||
0x33, 0xf7, 0x07, 0xc7, 0x18, 0x00, 0x00
|
||||
};
|
||||
|
||||
#endif // AsyncWebSerial_HTML_H
|
||||
Reference in New Issue
Block a user