WifiClient и aREST на esp32 – цикл до получения новых инструкций?
Я создал простой скетч для esp32, на котором размещен REST API, доступ к которому можно получить через HTTP. На основании инструкций, полученных от клиента, esp32 управляет некоторыми неопикселями с помощью различных написанных мной анимаций.
Все работало так, как ожидалось, пока я не добрался до анимации, которая выполняется в цикле while. Цикл разрывается при обнаружении нового клиента, чтобы светильник мог переключать функции. Однако, когда обнаруживается новый клиент, клиент, кажется, отбрасывается или потребляется, и я просто возвращаюсь к функции цикла(), пока не сделаю второй HTTP-запрос, а затем отобразятся изменения.
Я уверен, это что-то очевидное, но что я сделал не так?
Код:
#include "WiFi.h"
#include "FastLED.h"
#include "aREST.h"
#include "ArduinoJson.h"
#define NUM_LEDS 64
#define DATA_PIN 18
CRGB leds[NUM_LEDS];
int LED_COUNT = 64;
int MAX_BRIGHTNESS = 200;
const char* ssid = "wifi";
const char* password = "password";
aREST rest = aREST();
WiFiServer server(80);
WiFiClient client;
void setup() {
FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, LED_COUNT);
flashAll(CRGB::Black);
// Привязываем URL-адреса к функциям обработки
rest.function("random-strobe", randomStrobe);
rest.function("solid-color", solidColor);
rest.function("reset", reset);
// Подключаемся к Wi-Fi и ждем подключения, чтобы продолжить
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
flashAll(CRGB::Cyan);
delay(500);
flashAll(CRGB::Black);
delay(500);
}
server.begin();
flashAll(CRGB::Green);
delay(2000);
flashAll(CRGB::Black);
}
void loop() {
if (checkForTask()) {
rest.handle(client);
}
}
boolean checkForTask() {
// Я попробовал сделать это переназначение условным
// когда глобальный клиент имеет значение false, но это не помогло
//if (!client) { client = server.available(); }
client = server.available();
if (client) {
return true;
}
return false;
}
int randomStrobe(String params){
client.println("HTTP/1.1 200 OK");
client.println("Content-type:application/json");
client.println();
client.stop();
StaticJsonDocument<200> jsonDoc;
Serial.println(params);
Serial.println("params recieved. parsing...");
auto error = deserializeJson(jsonDoc, params);
if (!error) {
// некоторые настройки
while(!checkForTask()){
// делаем что-то здесь
}
return 0;
}
}
@shadowkrazee, 👍0
Обсуждение2 ответа
Лучший ответ:
Хорошо, мне удалось решить проблему благодаря общему указанию @juraj.
Теперь у меня есть ДВА экземпляра WifiClient:
WiFiClient client;
WiFiClient newClient;
Это позволяет мне использовать экземпляр newClient для проверки наличия нового клиента:
boolean checkForTask() {
newClient = server.available();
if (newClient) {
Serial.println("new client detected.");
return true;
}
return false;
}
и переназначать экземпляр основного клиента только тогда, когда действительно обнаружен новый клиент:
void loop() {
if (!newClient.connected()) {
checkForTask();
} else {
client = newClient;
runTask();
}
}
Похоже, что это работает без каких-либо заметных побочных эффектов или дополнительного использования ресурсов, но если есть более эффективный способ добиться этого, поделитесь. Спасибо!
В своем ответе я показываю более простое решение, @Juraj
server.available()
не возвращает уже «заявленное» соединение снова. Он возвращает новое соединение или пустой объект WiFiClient.
Ядро WiFi-библиотеки Arduino esp8266 и esp32 закрывает базовое соединение, если освобождается последний ссылающийся экземпляр WiFiClient. Присвоение пустого объекта WiFiClient освобождает предыдущую ссылку на базовый сокет, и если это была последняя ссылка, библиотека закрывает сокет.
Вы получаете клиент с server.available()
в checkForTask()
, а затем снова вызываете server.available()
. Он возвращает пустой объект WiFiClient, и вы назначаете его своему объекту WiFiClient. Библиотека закрывает указанное соединение.
Решение состоит в том, чтобы не проверять server.available
до тех пор, пока WiFiClient не станет действительным.
if (!client) {
client = server.available();
}
Спасибо за помощь. Как я могу проверить наличие нового клиента для выхода из цикла, а затем выполнить инструкции клиента? Как должен выглядеть метод checkForTask()? (Я подозреваю, что условие «если» просто нужно пересмотреть, хотя вы должны отметить, что клиент объявлен глобально и должен быть «уничтожен» только путем переназначения, если я правильно понимаю.) У меня больше опыта работы с другими языки, но мой C++ ограничен Arduino. извините, если я упускаю что-то очевидное., @shadowkrazee
@shadowkrazee, я отредактировал ответ. Я не понимаю, почему я не увидел, что «клиент» является глобальным. Я решил все подобные ловушки с сетевыми библиотеками в своем проекте с сервером Telnet и веб-сервером в библиотеках Wi-Fi и Ethernet https://github.com/jandrassy/Regulator/blob/8262f28b7452df0b75aa6c5a7bc676e14cd0cd26/Regulator/Telnet.ino#L23, @Juraj
- ESP32 - "Детектор Браунаута был активирован" при запуске Wi-Fi
- Контакты RX и TX на esp32
- Максимальное количество подключений точки доступа ESP32: 4 или 10?
- Почему OTA не работает с платой ESP32-CAM Ai-Thinker?
- ESP32 открывает "captive portal" при подключении
- Аналоговое чтение не работает при использовании WiFi
- Автоматическая веб-страница ESP32 AP
- Чтение данных из Google Таблиц с помощью Nodemcu
«Я пытался сделать это переназначение условным», как?, @Jaromanda X
@JaromandaX Что-то вроде: if (client) {...} else { client = server.available(); if (client) {...} - я не смог найти хорошей документации по проверке клиента без этой части переназначения, но я уверен, что есть лучший способ.., @shadowkrazee
@Юрай, правда, я не понимаю, чем это отличается от того, что есть у меня. не могли бы вы уточнить?, @shadowkrazee