Запуск WebServerSecure и PubSubClient на ESP8266

Я написал скетч для ESP8266. Этот скетч считывает некоторые данные датчика и публикует их через MQTT. Кроме того, я хочу, чтобы веб-сервер предоставлял те же данные, что и веб-служба HTML или JSON.

Публикация MQTT запускается через таймер TaskScheduler.

Обе функции, MQTT и веб-сервер, работают сами по себе, но, к сожалению, не вместе. Вот упрощенный набросок:

#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <ESP8266WebServerSecure.h>
#include <PubSubClient.h>
#include <TaskScheduler.h>

#include <My_WLAN.h>                          // provices connection to local WLAN and network settings

const char DNS_NAME[] = "myserver.local";
const int  HTTPS_PORT = 443;                  // HTTPS
const char MQTT_SVR[] = "myserver.local";
const unsigned int MQTT_PORT = 8883;          // MQTTS

WiFiClientSecure  wifiClient;
PubSubClient      mqttClient(wifiClient);     // MQTT client instance
ESP8266WebServerSecure  server(HTTPS_PORT);   // web server instance

void t1Callback(void);                        // callback method prototypes
Task              t1(60000, TASK_FOREVER, &t1Callback);   // main loop task
Scheduler         timer;                      // task scheduler

static const uint8_t SVR_FINGERPRINT[20] PROGMEM = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20 };

static const char deviceCert[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
[... certificate ...]
-----END CERTIFICATE-----
)EOF";

static const char deviceKey[] PROGMEM = R"EOF(
-----BEGIN RSA PRIVATE KEY-----
[... key ...]
-----END RSA PRIVATE KEY-----
)EOF";


/* *****************************
      MQTT_connect
 * *****************************/
void MQTT_connect()
{
  int attempt = 0;
  /* loop until reconnected */
  while (!mqttClient.connected() && attempt < 10) {
    attempt++;
    Serial.print("Attempting MQTT connection ("); Serial.print(attempt); Serial.print(")...");

    mqttClient.setServer(MQTT_SVR, MQTT_PORT);

    if (mqttClient.connect(DNS_NAME)) {
      Serial.println("success");

    } else {
      Serial.print("failed, status code = "); Serial.print(mqttClient.state());
      Serial.println(". - Try again in 5 seconds...");
      delay(5000);
    }
  }
}


/* *****************************
      Web Server handleRoot
 * *****************************/
void handleRoot() {
  digitalWrite(LED_BUILTIN, LOW); // on

  Serial.println("WebServer ROOT");
  server.send(200, "text/html", "WebServer ROOT");

  digitalWrite(LED_BUILTIN, HIGH); // off
}

/* *****************************
      Web Server handleNotFound
 * *****************************/
void handleNotFound() {
  digitalWrite(LED_BUILTIN, LOW); // on

  String message = "File not found\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET) ? "GET" : "POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";

  for (uint8_t i = 0; i < server.args(); i++) {
    message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
  }

  server.send(404, "text/plain", message);

  digitalWrite(LED_BUILTIN, HIGH); // off
}


/* *************************
      MQTT_publish_something
 * *************************/
void MQTT_publish_something() {
  digitalWrite(LED_BUILTIN, LOW); // on

  char payload[30] = "some_payload_data";

  if (!mqttClient.publish("MQTT/Test", payload, true)) {  // retain message
    Serial.println("MQTT message lost!");
  }

  digitalWrite(LED_BUILTIN, HIGH); // off
}


/* *************************
   t1: main timer (callback)
 * *************************/
void t1Callback() {
  my.WiFi_connect();    // check and re-connect to WLAN (in My_WLAN.h)

  if (WiFi.status() == WL_CONNECTED) {
    MQTT_connect();

    MQTT_publish_something();
  }
}


/* *************************
      setup
 * *************************/
void setup() {
  pinMode(LED_BUILTIN, OUTPUT);     // internal LED
  digitalWrite(LED_BUILTIN, HIGH);  // off

  /* -----------------------
        open Serial        |
     ----------------------- */
  Serial.begin(74880);
  while (!Serial);   // wait for Serial being ready

  /* -----------------------
        connect to WLAN    |
     ----------------------- */
  my.WiFi_connect();  // this is connecting to WLAN & error handling (in My_WLAN.h)
  wifiClient.setFingerprint(SVR_FINGERPRINT);

  /* -----------------------
        set mDNS           |
     ----------------------- */
  if (MDNS.begin(DNS_NAME)) {
    Serial.printf("mDNS responder started for %s\n", DNS_NAME);
    MDNS.addService("https", "tcp", HTTPS_PORT);   // add service to MDNS-SD
    MDNS.addService("mqtt",  "tcp", MQTT_PORT);
  } else
    Serial.println("Error setting up mDNS responder!");

  /* -----------------------
        start HTTPS server |
     ----------------------- */
  server.getServer().setRSACert(new X509List(deviceCert), new PrivateKey(deviceKey));

  server.on("/", handleRoot);                 // standard HTML root
  server.onNotFound(handleNotFound);
  server.begin();

  Serial.println("HTTPS server started.");
  Serial.println();


  /* -----------------------
        start timer        |
     ----------------------- */
  timer.init();
  timer.addTask(t1);
  // line 177:
  timer.enableAll();
}

void loop() {
  MDNS.update();

  // line 184:
  server.handleClient();

  mqttClient.loop();

  timer.execute();
}

Запуск MQTT работает нормально и публикует данные (я использую брокера mosquitto). Запуск веб-сервера (https://...) также работает нормально, если закомментировать строку 177 (так что MQTT не заводиться).

Когда обе функции активны, как только первое сообщение MQTT было отправлено, веб-сервер больше не отвечает. Я получаю PR_END_OF_FILE_ERROR в FF и ERR_CONNECTION_CLOSED в Chrome.

Я предполагаю, что эти библиотеки как-то путаются между собой, или что-то путается с сертификатами. Однако отпечаток пальца принадлежит серверу, на котором работает mosquitto, а сертификат X509 принадлежит веб-серверу, работающему на ESP8266. Это две разные машины и никак не связаны друг с другом.

Приветствуются любые идеи.


person Thomas Z    schedule 20.04.2020    source источник
comment
Не прямой ответ на ваш вопрос, но почему бы не разместить веб-сервер в другом месте? Правило IOT № 1: пусть датчики чувствуют, пусть что-то еще сообщает. У меня есть несколько датчиков, публикующих свои показания, но я поместил свой веб-сервер на свой сервер Docker. У меня есть еще один контейнер Docker, который собирает данные, а затем делает их доступными в виде API. Затем HTML-страница считывает данные через JQuery: github.com/john2exonets/MqttAPIServer   -  person JD Allen    schedule 20.04.2020
comment
Спасибо, Джей Ди Аллен, у меня тоже была эта идея, и это было бы допустимым альтернативным решением. Но разве нельзя запустить оба на одной машине, а если нет, то почему?   -  person Thomas Z    schedule 22.04.2020
comment
Конечно, вы можете запустить и то, и другое на одной машине... но в первый раз, когда вам нужно будет перетащить этот датчик с того места, где он был, просто чтобы записать какой-то новый код, чтобы добавить пробел на веб-страницу, вы быстро понимаете причины. чтобы датчики реагировали и не делали ничего лишнего ;) Примерно после четырех раз, когда мне пришлось подниматься и извлекать узел датчика/веб-сервера, я решил упростить себе жизнь и разделить часть веб-сервера на контейнер Docker, где Я мог вносить все изменения, которые мне нравились, сидя за своим столом ;)   -  person JD Allen    schedule 22.04.2020


Ответы (1)


Я подозреваю, что обе библиотеки используют порт 443, и у вас может быть только один прослушиватель на данном порту. Я попытался создать объект BearSSL::ESP8266WebServerSecure с альтернативными портами, такими как 80 и 8443, но не могу заставить их работать. Хуже того, не существует способа остановить прослушиватель после запуска объекта BearSSL::ESP8266WebServerSecure, поэтому его нельзя выпустить для последующего повторного использования.

В итоге я использовал HTTP для получения учетных данных WiFi, а затем HTTPS. Не очень удовлетворительное решение, но оно работает.

person Sapient Hetero    schedule 20.01.2021