WebSocket - кнопка управления светодиодом.
- Войдите на сайт для отправки комментариев
Доброго времени суток!
Колекционирую интересные решения, что-бы позже использовать в своих пректах. На этот раз решил повторить этот интересный урок https://randomnerdtutorials.com/esp32-websocket-server-arduino/. Но с небольшой модернизацией. Добавил вторую кнопку и реализовал на SPIFFS. Поправил код, всё работает но остался один косяк. Кнопки срабатывают, светодиоды отрабатывают корректно. НО! статус состояния кнопок срабатывает сразу на обе кнопки. Как будто они запаралелены. Например, включаешь первый светодиод, статус показывает что обо светодиода включились, хотя по факту как и положено включился только один. Бьюсь уже пару дней, никак не получается найти выход.
HTML:
<!DOCTYPE HTML><html> <head> <meta content="text/html;charset=utf-8" http-equiv="Content-Type"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" href="data:,"> <title>ESP Web Server</title> <link rel="stylesheet" href="style.css"> <script src="script.js"></script> </head> <body> <div class="topnav"> <h1>ESP WebSocket Server</h1> </div> <div class="content"> <div class="card"> <h2>Вывод - GPIO 32</h2> <p class="state">состояние: <span id="state1">%STATE1%</span></p> <p><button id="button1" class="button">Кнопка 1</button></p> <h2>Вывод - GPIO 33</h2> <p class="state">состояние: <span id="state2">%STATE2%</span></p> <!--Текущее состояние GPIO--> <p><button id="button2" class="button">Кнопка 2</button></p> <!--Кнопка для переключения состояния GPIO--> </div> </div> </body> </html>
Скетч:
// Import required libraries #include <WiFi.h> #include <AsyncTCP.h> #include <ESPAsyncWebServer.h> #include <SPIFFS.h> //#include <DHT.h> //#include <BH1750.h> //#include <Adafruit_Sensor.h> //#include <Adafruit_BME280.h> //#include <Wire.h> //#include <OneWire.h> // Задаем сетевые настройки const char* ssid = "Uname"; const char* password = "Pass"; IPAddress local_IP(192, 168, 1, 68); // Задаем статический IP-адрес: IPAddress gateway(192, 168, 1, 102); // Задаем IP-адрес сетевого шлюза: IPAddress subnet(255, 255, 255, 0); // Задаем маску сети: IPAddress primaryDNS(8, 8, 8, 8); // Основной ДНС (опционально) IPAddress secondaryDNS(8, 8, 4, 4); // Резервный ДНС (опционально) AsyncWebServer server(80); AsyncWebSocket ws("/ws"); bool ledState1 = 0; bool ledState2 = 0; const int ledPin1 = 32; const int ledPin2 = 33; // Уведомляем клиентов о текущем состоянии светодиода void notifyClients1() { ws.textAll(String(ledState1)); } void notifyClients2() { ws.textAll(String(ledState2)); } /* функция обратного вызова, которая запускается всякий раз, когда мы получаем новые данные от клиентов по протоколу WebSocket. Если мы получаем сообщение “toggle”, мы переключаем значение переменной ledState. Кроме того, мы уведомляем всех клиентов, вызывая функцию notifyClients (). Таким образом, все клиенты получают уведомление об изменении и соответствующим образом обновляют интерфейс.*/ void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) { AwsFrameInfo *info = (AwsFrameInfo*)arg; if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) { data[len] = 0; if (strcmp((char*)data, "toggle1") == 0) { ledState1 = !ledState1; notifyClients1(); } if (strcmp((char*)data, "toggle2") == 0) { ledState2 = !ledState2; notifyClients2(); } } } // Настройка прослушивателя событий для обработки различных асинхронных шагов протокола WebSocket void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) { switch (type) { case WS_EVT_CONNECT: // когда клиент вошел в систему Serial.printf("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str()); break; case WS_EVT_DISCONNECT: // когда клиент вышел из системы Serial.printf("WebSocket client #%u disconnected\n", client->id()); break; case WS_EVT_DATA: // при получении пакета данных от клиента handleWebSocketMessage(arg, data, len); break; case WS_EVT_PONG: // в ответ на запрос ping case WS_EVT_ERROR: // при получении ошибки от клиента break; } } // Инициализация WebSocket void initWebSocket() { ws.onEvent(onEvent); server.addHandler(&ws); } String processor(const String& var) { Serial.println(var); if (var == "STATE1") { if (ledState1) { return "ON"; } else { return "OFF"; } } if (var == "STATE2") { if (ledState2) { return "ON"; } else { return "OFF"; } } } void setup() { // Serial port for debugging purposes Serial.begin(115200); pinMode(ledPin1, OUTPUT); digitalWrite(ledPin1, LOW); pinMode(ledPin2, OUTPUT); digitalWrite(ledPin2, LOW); // Настраиваем статический IP-адрес: if (!WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS)) { Serial.println("Режим клиента не удалось настроить"); } if (!SPIFFS.begin()) { Serial.println("An Error has occurred while mounting SPIFFS"); return; } // Connect to Wi-Fi WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.println("Connecting to WiFi.."); } // Print ESP Local IP Address Serial.println(WiFi.localIP()); initWebSocket(); // Route for root / web page server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) { request->send(SPIFFS, "/index.html", "text/html"); }); server.on("/style.css", HTTP_GET, [](AsyncWebServerRequest * request) { request->send(SPIFFS, "/style.css", "text/css"); }); server.on("/script.js", HTTP_GET, [](AsyncWebServerRequest * request) { request->send(SPIFFS, "/script.js", "text/javascript"); }); // Start server server.begin(); } void loop() { ws.cleanupClients(); digitalWrite(ledPin1, ledState1); digitalWrite(ledPin2, ledState2); }
Java scrypt:
var gateway = `ws://${window.location.hostname}/ws`; var websocket; window.addEventListener('load', onLoad); function initWebSocket() { console.log('Trying to open a WebSocket connection...'); websocket = new WebSocket(gateway); websocket.onopen = onOpen; websocket.onclose = onClose; websocket.onmessage = onMessage; } function onOpen(event) { console.log('Connection opened'); } function onClose(event) { console.log('Connection closed'); setTimeout(initWebSocket, 2000); } function onMessage(event) { var state1; if (event.data == "1"){ state1 = "ON"; document.getElementById('button1').style.backgroundColor = "#04b50a"; } else{ state1 = "OFF"; document.getElementById('button1').style.backgroundColor = "#c90411"; } document.getElementById('state1').innerHTML = state1; //---- var state2; if (event.data == "1"){ state2 = "ON"; document.getElementById('button2').style.backgroundColor = "#04b50a"; } else{ state2 = "OFF"; document.getElementById('button2').style.backgroundColor = "#c90411"; } document.getElementById('state2').innerHTML = state2; } function onLoad(event) { initWebSocket(); initButton(); } function initButton() { document.getElementById('button1').addEventListener('click', toggle1); document.getElementById('button2').addEventListener('click', toggle2); } function toggle1(){ websocket.send('toggle1'); } function toggle2(){ websocket.send('toggle2'); }
Спасибо!
Так у тебя нету никакого разделения между уведомлениями о состоянии пинов.
да вроде есть.
045
if
(info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) {
046
data[len] = 0;
047
if
(strcmp((
char
*)data,
"toggle1"
) == 0) {
048
ledState1 = !ledState1;
049
notifyClients1();
050
}
051
if
(strcmp((
char
*)data,
"toggle2"
) == 0) {
052
ledState2 = !ledState2;
053
notifyClients2();
054
}
055
}
Условие там правда мутное...
Уведомления стр.31 и 35. Одинаковые, без различения кнопок. Коим хером в джаве различат к какой кнопке оно относится?
Уведомления стр.31 и 35. Одинаковые, без различения кнопок. Коим хером в джаве различат к какой кнопке оно относится?
getElementById(
'button1'
) Разве не то?
нет.
21
function onMessage(event) {
22
var state1;
23
if
(event.data ==
"1"
){
24
state1 =
"ON"
;
25
document.getElementById(
'button1'
).style.backgroundColor =
"#04b50a"
;
26
}
27
else
{
28
state1 =
"OFF"
;
29
document.getElementById(
'button1'
).style.backgroundColor =
"#c90411"
;
30
}
31
document.getElementById(
'state1'
).innerHTML = state1;
32
//----
33
var state2;
34
if
(event.data ==
"1"
){
35
state2 =
"ON"
;
36
document.getElementById(
'button2'
).style.backgroundColor =
"#04b50a"
;
в event.data приезжает "1", и оба условия стр.23 и 34 срабатывают. Надо както отличать, когда приезжает "1" для одной, а когда для второй кнопки.
Проще всего
034
void
notifyClients2() {
035
ws.textAll(String(ledState2+2));
Тогда для кнопки 1 будут по старому ехать 1 и 0, а для второй кнопки - 2 и 3.
Ну и
32
//----
33
var state2;
34
if
(event.data ==
"3"
){
35
state2 =
"ON"
;
36
document.getElementById(
'button2'
).style.backgroundColor =
"#04b50a"
;
Спасибо от всей души! Довольно четко объяснили. Сработало! Только вот статус показывает либо по одной кнопке, либо по другой. Если вкючены обе, то статус "включено" сработает лишь на одной из двух.
Может ты попытаешься разобраться в собственном коде? Проблема - ерунда, если ты умеешь читать код. А если не умеешь, то зачем вообще лезть? Учиться нужно по порядку.
Да надо то вчера и сразу! )
Решение:
Собственно кусок кода
Java script