Да.Спасибо за пример и подсказки. А в коде у Вас есть комментарий "В корень SPIFFS надо загрузить веб приложение" - что подразумевается html с js ?
Основное различие в том, что синхронный сервер работает в цикле loop и нужно следить чтобы HandleServer не блокировал работу Wifi, т.е. если у вас имеется внутри долгий по времени (более 40-50мс) обработчик, то надо будет прерывать его, вставляя в код yield() или delay(0) для нормальной работы wifi сети. Асинхронный сервер работает в своем отдельном цикле и самостоятельно прерывается для нормальной работы wifi сети. Ну и как по мне, ESPAsyncWebServer более богат функционалом и удобен в использовании. В любом случае, обе библиотеки - рабочий инструмент, так что выбор за вами.И еще вопрос. Для синхронного сервера есть библиотека WebSocketsServer.h - она аналогична плагину websockets для асинхронного вебсервера? Так как документации практически нет, либо смотреть по исходникам библиотеки, с минимумом комментариев на английском, либо разбираться по примерам реализации чужого кода. А примеров работы с вебсокетами для асинхронного вебсервера не особо много.
Правда непонятно в чем принципиальные преимущества асинхронного сервера над синхронным?
#include <Arduino.h>
#include <ESPAsyncWebServer.h>
#include <ArduinoJson.h>
#define NUM_PTR_FUN 3
const uint8_t interval_1 = 50; //ms.
const uint16_t interval_2 = 500; //ms.
uint32_t timer_1 = 0;
uint32_t timer_2 = 0;
uint32_t freeHeap = 0;
bool sendFreeHeap = false;
bool needToUpdateStates = false;
IPAddress ipAP{192, 168, 4, 1};
AsyncWebServer server(80);
AsyncWebSocket ws1("/ws");
// Отправка состояний кнопок (GPIO)
void sendStates(AsyncWebSocketClient * client = NULL){
StaticJsonBuffer<200> jsonBuffer; // создаем буфер
JsonArray& root = jsonBuffer.createArray(); //создаем ссылку на массив
root.add(0); // добавляем элемент в корневой массив
JsonArray& states = root.createNestedArray(); // создаем ссылку на вложенный массив
states.add(digitalRead(0)); // и добавляем туда данные
states.add(digitalRead(2));
states.add(digitalRead(4));
states.add(digitalRead(5));
size_t len = root.measureLength(); // записываем длину массива
AsyncWebSocketMessageBuffer * buffer = ws1.makeBuffer(len); // создаем буфер для отправки данных
if (buffer) {
root.printTo((char *)buffer->get(), len + 1); // если буфер успешно создан то записывем туда данные
if (client) {
client->text(buffer); // если клиент указан то отправляем содержимое буфера клиенту
} else {
ws1.textAll(buffer); // если клиент не указан то отправляем содержимое буфера всем подключеным клиентам
}
}
}
// Обработчик управления GPIO с веб интерфейса
void H_pinChange(JsonVariant payload, AsyncWebSocketClient * client){
digitalWrite(payload,!digitalRead(payload));
needToUpdateStates = true;
}
// Обработчик управления free heap с веб интерфейса
void H_freeHeap(JsonVariant payload, AsyncWebSocketClient * client){
sendFreeHeap = payload;
}
// Обработчик управления получения ID с веб интерфейса
void H_getChipId(JsonVariant payload, AsyncWebSocketClient * client){
StaticJsonBuffer<50> jsonBuffer;
JsonArray& root = jsonBuffer.createArray();
root.add(payload);
root.add(ESP.getChipId());
size_t len = root.measureLength();
AsyncWebSocketMessageBuffer * buffer = ws1.makeBuffer(len);
if (buffer) {
root.printTo((char *)buffer->get(), len + 1);
client->text(buffer);
}
}
// массив указателей на функции обработчиков
void (*arrFnPtr[NUM_PTR_FUN])(JsonVariant payload, AsyncWebSocketClient * client) = {
H_pinChange, // [0] - управление GPIO
H_freeHeap, // [1] - отправлять free heap (да\нет)
H_getChipId // [2] - получить ID
// дальше можно дописывать для добавления новых обработчиков, при этом необходимо увеличить NUM_PTR_FUN до нужного размера
};
// Парсер входящих ws сообщений
// Число в первой ячейке массива(root[0]), является индексом указателя на функцию
// таким образом парсер определяет какую функцию-обработчик использовать
void readJsonData(const char *data, AsyncWebSocketClient * client){
Serial.printf("from ws data: %s client: %u\n", data, client->id());
DynamicJsonBuffer jsonBuffer;
JsonArray& root = jsonBuffer.parseArray(data);
if(root.success()){
arrFnPtr[root[0].as<uint8_t>()](root[1].as<JsonVariant>(),client);
}
}
// Приемник ws сообщений (упрощенный на 1 фрейм)
void onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len) {
if(type == WS_EVT_CONNECT){
Serial.printf("client id: %u connected\n", client->id());
sendStates(client);
} else if(type == WS_EVT_DATA){
AwsFrameInfo * info = (AwsFrameInfo*)arg;
data[info->len] = '\0';
readJsonData((char*)data,client);
}
}
// Обработчик несуществующей страницы
void notFound(AsyncWebServerRequest *request) {
request->send(404, "text/plain", "Not found");
}
// Инициализация сервера
void serverInit(){
ws1.onEvent(onWsEvent);
server.addHandler(&ws1);
server.serveStatic("/", SPIFFS, "/").setCacheControl("max-age=31536000");
server.onNotFound(notFound);
server.begin();
}
// Инициализация wifi сети
void wifiInit(){
WiFi.mode(WIFI_AP);
WiFi.softAPConfig(ipAP, ipAP, IPAddress(255, 255, 255, 0));
WiFi.softAP("espAP", "");
}
void setup() {
Serial.begin(115200);
Serial.println();
pinMode(0,OUTPUT);
pinMode(2,OUTPUT);
pinMode(4,OUTPUT);
pinMode(5,OUTPUT);
SPIFFS.begin();
wifiInit();
serverInit();
}
void loop() {
if(millis()>timer_1){
timer_1 = millis()+interval_1;
if(needToUpdateStates){
sendStates();
needToUpdateStates = false;
}
}
yield();
if(millis()>timer_2){
timer_2 = millis()+interval_2;
ws1.printfAll("[3,%lu]",millis());
if(sendFreeHeap){
freeHeap = ESP.getFreeHeap();
ws1.printfAll("[1,%u]",freeHeap);
}
}
yield();
}
<script>
import { onMount } from 'svelte';
const buttons = [0,2,4,5]
let states = [255,255,255,255]
let uptime = undefined
let timeIs = "unknown"
let showFreeHeap = false
let freeHeap = "unknown"
let online = false
let ws = ""
let chipInfo = undefined
onMount(() => { // WS-клиент + обработчик сообщений
let startWs = () => {
ws = new WebSocket('ws://' + document.location.host + '/ws', ['arduino']);
//ws = new WebSocket('ws://192.168.4.1/ws');
ws.onopen = e => online = true
ws.onclose = e => online = false
ws.onerror = e => online = false
ws.onmessage = e => {
console.log("from esp: ", e.data)
let jsonStr = IsValidJSONString(e.data)
if(jsonStr){
switch (jsonStr[0]){
case 0:
states = jsonStr[1]
break
case 1:
freeHeap = jsonStr[1]
break
case 2:
chipInfo = jsonStr[1]
break
case 3:
uptime = jsonStr[1]
break
}
}
}
}
let check = () => {
if (!ws || ws.readyState != 1) {
ws.close()
online = false
startWs()
}
}
let IsValidJSONString =(str)=> {
let jsonS
try {
jsonS = JSON.parse(str);
} catch (e) {
return false;
}
return jsonS;
}
startWs();
setInterval(check, 5000);
});
let bClick = (i)=>{
let str = "[0,"+i+"]"
ws.send(str);
}
let getChipId = ()=>{
ws.send("[2,2]")
}
let toggleFreeHeap = ()=>{
let str = "[1,["+showFreeHeap+"]]"
ws.send(str)
}
$: {if(uptime != undefined){
let d, h, m, s;
s = Math.floor(uptime / 1000);
m = Math.floor(s / 60);
s = s % 60;
h = Math.floor(m / 60);
m = m % 60;
d = Math.floor(h / 24);
h = h % 24;
h += d * 24;
timeIs = h + ':' + m + ':' + s;
}else{
timeIs = "unknown"
}
}
</script>
<!--HTML----------------------------------------------------- -->
<header>
<h1 class={online ? "c-green":"c-red"}>{online ? "online":"offline"}</h1>
{#if online}
<h1>Uptime: {timeIs}</h1>
{/if}
{#if showFreeHeap}
<h1>Free heap: {freeHeap} bytes</h1>
{/if}
<input type="checkbox" bind:checked={showFreeHeap} on:change={toggleFreeHeap} disabled={online ? false:true}>
show free heap
</header><hr>
<main>
{#each buttons as b, i}
<button class={(!online || states[i] == 255) ? "c-gray":(states[i] == 0) ? "c-red":"c-green"} on:click={()=>bClick(b)}>Gpio {b}</button><br>
{/each}
<hr>
{#if chipInfo == undefined}
<button class="c-gray" on:click={getChipId}>Get chip ID</button>
{:else}
<h1>ChipId: {chipInfo}</h1>
{/if}
</main>
<!--STYLE---------------------------------------------------- -->
<style>
:global(body){
font-size: 26px;
font-weight: bolder;
}
button{
margin: 10px;
font-size: 32px;
border-radius: 8px;
font-weight: bolder;
border: none;
}
input{
width: 40px;
height: 30px;
font-size:26px;
font-weight: bolder;
white-space: pre;
}
.c-red{
background-color: red;
}
.c-green{
background-color: green;
}
.c-gray{
background-color: silver;
}
</style>
import App from './App.svelte';
const app = new App({
target: document.body
});
export default app;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width,initial-scale=1'>
<title>example</title>
<link rel='icon' type='image/png' href='/favicon.png'>
<script defer src='/bundle.js'></script>
</head>
<body>
</body>
</html>
Делал примеры с асинхронным веб-сервером, пробовал подключаться со стационарного компьютера и телефона одновременно, все работает. По мануалам при реализации softAP на ESP возможно подключение 5 клиентов.Добрый день, я новичок, и не могу понять как организовать подключение к esp8266 нескольких телефонов, 1 подключил через сокет, пробую подключиться с другого устройства так всё зависает
Да, походу я накосячил и забыл раскоментить 1 строку и закометить другую.Спасибо, запустил. получилось. А такой вопрос, попробовал скетч переделать под подключение к роутеру, но походу при компиляции в bundle.js попадает IP-адрес программной точки доступа 192.168.4.1 и соединение websocket не поднимается. Я попробовал установить svelte, но на втором этапе
npx degit sveltejs/template my-svelte-project
сыпет ошибки. Еще такой вопрос, почему то перестает обновляться информация на веб-странице, при этом управление выводом со страницы работает
ws = new WebSocket('ws://' + document.location.host + '/ws', ['arduino']);
//ws = new WebSocket('ws://192.168.4.1/ws');
Кажись была такая проблема, попробуйте установить gitnpx degit sveltejs/template my-svelte-project сыпет ошибки.
Я не пробовал, но json 5 подключается в библиотеку сервера, поэтому скорее всего не получится собрать проект. На стороне клиента (js) проблем не будет json строка она и Африке jsonEvgeniyS, а такой вопрос. Если я в скетче Ардуино изменю работу с json с версии 5 на версию 6, не нужно перекомпилировать файлы js?
Тоже заметил, пока не знаю почему, писал все это на "скорую руку". Первое что приходит на ум: заменить в loop yield() на delay(20), напримерЕще такой вопрос, почему то перестает обновляться информация на веб-странице, при этом управление выводом со страницы работает