Как постоянно отправлять данные от нескольких клиентов на сервер с помощью NodeMCU?

Я работаю над отправкой данных от нескольких клиентов на сервер, каждый из которых является NodeMCU. Мне удалось отправить данные за одну итерацию. Проблема возникает, когда я хочу, чтобы данные отправлялись повторно, чтобы при обновлении данных клиента эти новые данные также отражались на сервере.

Поскольку я использую несколько клиентов, я использовал MAC-адреса в качестве средства идентификации клиентов. Таким образом, сигналы, полученные от конкретного клиента, передаются на вывод на определенный вывод.

Чтобы отправлять данные постоянно, я попытался использовать бесконечный цикл: while(true), но он читает первого подключенного клиента даже при распознавании второго клиента.

Вот код моего сервера:

#include <ESP8266WiFi.h>
#define Max_Clients 5

extern "C" {
  #include <user_interface.h>
}

WiFiServer server(80); //Инициализируем сервер на порту 80
WiFiClient *clients[Max_Clients] = {NULL}; //Инициализация клиента(ов)
String inputs [Max_Clients] ={""}; //Инициализация для сохранения строки, полученной от клиентов

int32_t freq = 10000;

IPAddress remoteIP();

void setup() {
  pinMode(D1,OUTPUT); //Инициализация контактов для отображения вывода и ввода
  pinMode(D2,OUTPUT);
  pinMode(D3,OUTPUT);
  pinMode(A0,INPUT);
  Serial.begin(9600); //Начало связи между ESP8266-12E и окном монитора
  analogWriteFreq(freq);
  WiFi.mode(WIFI_AP); //Этот ESP8266-12E является точкой доступа
  WiFi.softAP("NodeMCU_js", "12345678"); //Укажите (SSID, пароль)
  IPAddress myIP = WiFi.softAPIP(); //Получаем IP сервера
  Serial.println("Server IP is: "); //Выводим IP в окно монитора
  Serial.println(myIP);
  server.begin(); //Запускаем HTTP-сервер
}

void loop() {
  WiFiClient client = server.available(); //Проверяем, подключился ли новый Клиент к серверу
  unsigned char number_client;
  struct station_info *stat_info;
  struct ip_addr *IPaddress;
  IPAddress address;
  int k=0;
  if (client) {  
    Serial.println("A new Client has connected :)");
   for (int i=0 ; i<Max_Clients ; ++i){ //Подтверждаем и настраиваем новых клиентов
    if (NULL == clients[i]){
      Serial.println(i);
      clients[i] = new WiFiClient(client); //в списке клиентов[i] ничего не означает, что это новый клиент
      break;
    }
   }

   while (true){ 
    delay(3000);
    number_client = wifi_softap_get_station_num();
    stat_info = wifi_softap_get_station_info();
    Serial.println();
    Serial.print("Total connected clients are = ");
    Serial.print(number_client);
    Serial.println();
    while (stat_info != NULL){
      for(int i=0 ; i<number_client ; ++i)  { //Для доступных клиентов
        if (NULL != clients[i]) {
          IPaddress = &stat_info->ip;
          address = IPaddress->addr;
          Serial.println();
          Serial.print("Client = ");
          Serial.print(i+1);
          Serial.println();
          Serial.print("Client IP Address = ");
          Serial.print(address);
          Serial.println();
          Serial.print("Client MAC Address = ");
          Serial.print(stat_info->bssid[0],HEX);
          Serial.print(":");
          Serial.print(stat_info->bssid[1],HEX);
          Serial.print(":");
          Serial.print(stat_info->bssid[2],HEX);
          Serial.print(":");
          Serial.print(stat_info->bssid[3],HEX);
          Serial.print(":");
          Serial.print(stat_info->bssid[4],HEX);
          Serial.print(":");
          Serial.print(stat_info->bssid[5],HEX);
          Serial.println();

          if (stat_info->bssid[0] == 0xDC && stat_info->bssid[1] == 0x4F && stat_info->bssid[2] == 0x22 && stat_info->bssid[3] == 0x17 && stat_info->bssid[4] == 0xEE && stat_info->bssid[5] == 0x95) {
            Serial.println("Compared MAC address successfully - 1 :)");
            String request1 = clients[i]->readStringUntil('\r');
            Serial.print("Client 1 asks: ");
            Serial.print(request1);
            inputs[i] = request1;
            int duty1 = request1.toInt();
            analogWrite(D1,duty1);
            clients[i]->flush();
            k++;
            clients[i]->print("From Central Server to Client 1 - 150\r");
          }

          if (stat_info->bssid[0] == 0xDC && stat_info->bssid[1] == 0x4F && stat_info->bssid[2] == 0x22 && stat_info->bssid[3] == 0x18 && stat_info->bssid[4] == 0x1F && stat_info->bssid[5] == 0x9D) {
            Serial.println("Compared MAC address successfully - 2 :)");
            String request2 = clients[i]->readStringUntil('\r');
            Serial.print("Client 2 asks: ");
            Serial.print(request2);
            inputs[i] = request2;
            int duty2 = request2.toInt();
            analogWrite(D2,duty2);
            clients[i]->flush();
            clients[i]->print("From Central Server to Client 2 - 200\r");
            k++;
            }

          if (stat_info->bssid[0] == 0xDC && stat_info->bssid[1] == 0x4F && stat_info->bssid[2] == 0x22 && stat_info->bssid[3] == 0x18 && stat_info->bssid[4] == 0xB && stat_info->bssid[5] == 0x71) {
            Serial.println("Compared MAC address successfully - 3 :)");
            String request3 = clients[i]->readStringUntil('\r');
            Serial.print("Client 3 asks: ");
            Serial.print(request3);
            inputs[i] = request3;
            int duty3 = request3.toInt();
            analogWrite(D3,duty3);
            clients[i]->flush();
            k++;
            clients[i]->print("From Central Server to Client 3 - 250\r");
          }

        if (k == 0){
            Serial.println();
            Serial.println("Client not recognised.");
          }  

          stat_info = STAILQ_NEXT(stat_info, next);
          Serial.println();
        }
       }
      }
     }
    }
   } // аннулируем закрытие цикла

Вот мой клиентский код:

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>

char ssid[] = "NodeMCU_js";
char password[] = "12345678";

WiFiClient client; // Создает клиент, который может подключаться к указанному IP-адресу и порту в Интернете, как определено в client.connect().
IPAddress server(192,168,4,1);

void setup() {
  pinMode(A0,INPUT);
  pinMode(D6,OUTPUT);
  WiFi.persistent(false);
  WiFi.mode(WIFI_STA);
  Serial.begin(9600); //Последовательное соединение
  WiFi.begin(ssid,password); //Подключение к Wi-Fi
  while (WiFi.status() != WL_CONNECTED) { //Ждем завершения подключения Wi-Fi
    delay(500);
    Serial.println("Connecting...");    
  }
  Serial.println("Connected.");
  client.connect(server, 80);   // Соединение с сервером
}

void loop() {
  if(WiFi.status() == WL_CONNECTED){ //Проверяем статус подключения Wi-Fi
    while(true){
      int duty = analogRead(A0);
      client.print(String(duty)+"\r"); //Сообщение клиента серверу
      String answer = client.readStringUntil('\r'); //Чтение ответа с сервера
      Serial.print("Central Server: 200"); //Печать ответа
      Serial.print(answer);
     }
   } else {
     Serial.println("Error in WiFi connection");   
   }
}

Пожалуйста, предложите решение. Заранее спасибо.

, 👍0

Обсуждение

Как вы думаете, почему существует связь между клиентом, возвращаемым веб-сервером, и номером клиентской станции из программной точки доступа?, @Juraj

Один из моих nodeMCU — это сервер. Я не использую какой-либо веб-сервер., @Dingodudesir

извини, Wi-Fi-сервер, @Juraj

wifi_softap_get_station_num() — это количество станций, если я правильно понимаю, @Juraj

Именно так. Количество клиентов, подключенных к серверу., @Dingodudesir

но все подключены к точке доступа из настройки(), @Juraj

Я проверял и не работает., @RobertoFRey


2 ответа


0

Очень важно, чтобы либо loop() возвращал значение, либо чтобы вы вызывали yield() или delay() в своем обработчике loop().

Ваш клиентский код в том виде, в котором он написан, этого не делает.

Вам вообще не нужен while(true). Уберите его и оставьте его тело в операторе if. loop() будет постоянно вводиться повторно, и ваш код продолжит выполняться. loop() уже является бесконечным циклом.

Оставление while(true) внутри loop() означает, что loop() никогда не возвращается. Если он не возвращается, SDK не может выполнить определенные функции обслуживания, необходимые для его правильной работы. В частности, сетевые функции могут перестать работать правильно, поэтому ваш вызов client.readStringUntil() может работать неправильно.

,

При удалении while(true) программа выполняется нормально, но не работает вечно. Мне это нужно, потому что сигналы analogRead() будут меняться, и я хочу наблюдать изменения в выводе без необходимости повторного запуска кода., @Dingodudesir

Происходит что-то странное, если он не продолжает работать. Вся цель loop() — вызываться снова и снова, в бесконечном цикле. Попробуйте сделать отладку, поместите несколько Serial.println() внутрь loop(), чтобы подтвердить, что на самом деле происходит. Нет никакого способа, чтобы он когда-либо работал правильно, если у вас есть while(true) внутри loop()., @romkey

Есть ли альтернатива while(true)? Есть ли другой способ создать бесконечный цикл внутри void(loop)? Я прошел программу несколько раз и не нашел никаких зацепок вообще., @Dingodudesir

loop() — это бесконечный цикл. Если нет, то где-то что-то сломалось. Вы пробовали поставить отладку Serial.println()s, чтобы подтвердить, что вы не повторно входите в loop() после того, как он возвращается? Если что-то настолько сломано, что loop() не повторно входит, лучше не делать предположений о том, что работает. Итак, что-то вроде: недействительный цикл() { Serial.println("вошел в цикл"); if(WiFi.status() == WL_CONNECTED){ //Проверка статуса подключения WiFi Serial.println("Wi-Fi подключен"); int duty = analogRead(A0); ... (комментарии слишком короткие, чтобы вместить весь код), @romkey

Я это сделал. Цикл больше не запускается., @Dingodudesir


1

Я нашел ошибку. if(client) должен быть закрыт перед while(stat_info), иначе цикл будет запущен только в том случае, если будет найден новый клиент. Сейчас все работает отлично. Спасибо всем за предложения. :)

,