Доброго времени суток! Пока что эксперементальный веб.сервер, основан на websocket. Задача такова: На страничку выводится две конопки вкл/выкл. Этими кнопками можно подавать 0 или 1 на соответсвующие выходы. Так же есть два простых таймера на millis, которые должны управлять этими кнопками. А теперь самое главное! Хочу что бы выводилось время которое осталось до включения таймера. Так сказать обратный отсчет.
Никак не получается отправить две строки с данными в функцию onMessage джава скипта.
Строки 182 и 197, каша получается. Джава должен их как то различать.
index.html:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8" , name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<br>
GPIO25 <button id="button1"><span id="state1">%STATE1%</span></button> до включения осталось...
<span id="dateTime1"></span>
<br>
<br>
GPIO26 <button id="button2"><span id="state2">%STATE2%</span></button> до включения осталось...
<span id="dateTime2"></span>
<script src="script.js"></script>
</body>
</html>
script.js:
var gateway = [ICODE]ws://${window.location.hostname}/ws[/ICODE];
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) {
// let data = event.data.split(',');
// document.getElementById("dateTime1").innerHTML = data[0];
// document.getElementById("dateTime2").innerHTML = data[1];
switch (event.data) {
case '0': document.getElementById("state1").innerHTML = "OFF"; document.getElementById('button1').style.backgroundColor = "#c90411"; break
case '1': document.getElementById("state1").innerHTML = "ON "; document.getElementById('button1').style.backgroundColor = "#04b50a"; break
case '2': document.getElementById("state2").innerHTML = "OFF"; document.getElementById('button2').style.backgroundColor = "#c90411"; break
case '3': document.getElementById("state2").innerHTML = "ON "; document.getElementById('button2').style.backgroundColor = "#04b50a"; break
}
}
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'); }
main.ccp:
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <SPIFFS.h>
// Задаем сетевые настройки
const char *ssid = "name";
const char *password = "pass";
AsyncWebServer server(80); // Запускаем асинхронный веб-сервер на 80 порту
AsyncWebSocket ws("/ws"); // Создаём объект, который будет обрабатывать websocket-ы:
// Объявляем GPIO.
#define ledPin1 25 // Таймер1
#define ledPin2 26 // Таймер2
// Переменные хранения времени (unsigned long)
uint32_t timer1, timer2;
// На всех выводах GPIO по умолчанию устанавливаем 0.
bool ledState1 = false, ledState2 = false;
// Задаем время для таймеров
int32_t t1 = 5 / 1000L; // Продолжительность работы для 1го таймера 5 сек.
int32_t t11= 15 / 1000L; // Переодичность включения для 1го таймера 15 сек.
int32_t t2 = 3 / 1000L; // Продолжительность работы для 2го таймера 3 сек.
int32_t t22 = 10 / 1000L; // Переодичность включения для 2го таймера 15 сек.
// Создаем Websocket сервер
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) // Слушаем сообщения от js, если toggle1 = 0, то выполняем код ниже.
{
ledState1 = !ledState1; // Установим значение переменной ledState = 1, но если кнопка не нажата тогда ledState = 0
ws.textAll(String(ledState1)); // Уведомляем клиентов о переключении кнопки.
}
if (strcmp((char *)data, "toggle2") == 0)
{
ledState2 = !ledState2;
ws.textAll(String(ledState2 + 2));
}
}
}
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 клиент #%u подключен с %s\n", client->id(), client->remoteIP().toString().c_str());
break;
case WS_EVT_DISCONNECT: // когда клиент вышел из системы
Serial.printf("WebSocket клиент #%u отключен\n", client->id());
break;
case WS_EVT_DATA: // обработка полученных данных
handleWebSocketMessage(arg, data, len);
break;
case WS_EVT_PONG: // в ответ на запрос ping
case WS_EVT_ERROR: // при получении ошибки от клиента
break;
}
}
// Функция processor() заменяет все заполнители между символами %---%, в HTML-тексте фактическими значениями.
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";
}
}
return String();
}
// ----------------------------------------------------------------
// Инициализация
// ----------------------------------------------------------------
void initSPIFFS()
{
if (!SPIFFS.begin())
{
Serial.println("При монтировании SPIFFS произошла ошибка");
while (1)
;
}
}
void initWiFi()
{
WiFi.begin(ssid, password);
Serial.print("Подключаемся к WiFi...");
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(1000);
}
Serial.println();
Serial.printf("Подключился к сети %s\n", ssid);
Serial.print("ESP32 IP адрес: ");
Serial.println(WiFi.localIP());
}
void initWebServer()
{
server.begin();
}
void initWebSocket()
{
ws.onEvent(onEvent);
server.addHandler(&ws);
}
void setup()
{
// Зададим скорость последовательного порта.
Serial.begin(115200);
delay(1000);
initSPIFFS(); // Инициализация SPIFFS
initWiFi(); // Инициализация WiFi
initWebServer(); // Инициализация Web сервера
initWebSocket(); // Инициализация Websocket
// Объявим GPIO выходы (по умолчанию LOW)
pinMode(ledPin1, OUTPUT);
digitalWrite(ledPin1, LOW);
pinMode(ledPin2, OUTPUT);
digitalWrite(ledPin2, LOW);
// Маршрут до корневого каталога веб страницы
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
{ request->send(SPIFFS, "/index.html", "text/html", false, processor); });
server.on("/script.js", HTTP_GET, [](AsyncWebServerRequest *request)
{ request->send(SPIFFS, "/script.js", "text/javascript"); });
}
void loop()
{
digitalWrite(ledPin1, ledState1);
digitalWrite(ledPin2, ledState2);
// ############################ Таймер №1 ####################################
if (millis() / 1000L - timer1 >= (ledState1 ? t1 : t11)) // 5 сек-продолжительность, 15 сек-периодичность
{
timer1 = millis() / 1000L; // количество секунд с момента старта
ledState1 = !ledState1;
digitalWrite(ledPin1, ledState1); // Подаем на GPIO25, высокий/низкий уровень
// Serial.println(timer3); // Выводим количество секунд с момента включения
}
// Вывод обратного отсчета времени
int8_t timeleft1 = (t11 - (millis() / 1000L - timer1)); // Создаем переменную timeleft1, обратного остчета времени (где 15, это период)
if (!ledState1) // если таймер выключен (период ожидания), то..
{
Serial.println(timeleft1); // то выводим обратный остчет до включения таймера
ws.textAll(String(timeleft1)); // отправляем данные в JavaScript
}
// ############################ Таймер №2 ####################################
if (millis() / 1000L - timer2 >= (ledState2 ? t2 : t22)) // 5 сек-продолжительность, 10 сек-периодичность
{
timer2 = millis() / 1000L; // количество секунд с момента старта
ledState2 = !ledState2;
digitalWrite(ledPin2, ledState2); // Подаем на GPIO26, высокий/низкий уровень
}
// Вывод обратного отсчета времени
int8_t timeleft2 = (t22 - (millis() / 1000L - timer2));
if (!ledState2)
{
ws.textAll(String(timeleft2)); // отправляем данные в JavaScript
}
}
Строки 182 и 197, каша получается. Джава должен их как то различать.
Изменено: