ESP8266 + Slack (ssl->need_bytes=16432 > 6859)

esp8266 web

Я пытаюсь подключить Adafruit Huzzah ESP8266 к Slack.

У меня возникла проблема с подключением, и мне нужна помощь или совет. Мне иногда удается установить соединение, но иногда на начальном этапе, когда я устанавливаю первое соединение, возникают ошибки, и оно полностью терпит неудачу, повторяя соединение/разъединение снова и снова.

Обычно я получаю следующую ошибку:

ssl->need_bytes=16432 > 6859

Устранение неполадок на данный момент

Согласно этой проблеме с github: https://github.com/esp8266/Arduino/issues/1375

Насколько я понимаю, ошибка вызвана слишком большим SSL-сертификатом Slack. Это имеет смысл, но иногда мой код (см. ниже) действительно работает, поэтому я запутался.

Когда это работает, обычно сначала пару раз происходит сбой, прежде чем поддерживать постоянный пинг со Slack. В этот момент он работает так, как ожидалось, и я могу безошибочно отправлять команды из Slack на плату.

Slack-команда для ESP8266

Кто-нибудь знает, почему это иногда работает, а иногда нет?

Я предполагаю, что это как-то связано со слишком большим размером SSL-сертификата, но если это так, то почему бы ему не сбоить каждый раз, а иногда работать?

Любая помощь приветствуется.


Ошибки в Serial Monitor

Вот что я вижу в журнале Serial Monitor:

⸮scandone
f r0, scandone
f r0, scandone
state: 0 -> 2 (b0)
state: 2 -> 3 (0)
state: 3 -> 5 (10)
add 0
aid 7
cnt 

connected with 2WIRE952, channel 3
dhcp client start...
ip:192.168.1.73,mask:255.255.255.0,gw:192.168.1.254

Waiting for time sync
please start sntp first !
.please start sntp first !
.Sun Apr 16 06:57:35 2017

Time is synced
ssl->need_bytes=16432 > 6859
WebSocket Host=mpmulti-4pcb.slack-msgs.com Path=/websocket/Z5ZDermv9h2Q7HL88ukG5ddIvY--zrBAVCN4423KOy5t_6wN3AW859grAYCYr6L-0l0leeXA3AhlO1VmIxcCopS1pJ-IkrVOdmel50tgcA7hBJwEIkpI-biYnraTFc88K4F6wqL3TE_gi1jU0SJHhR6_aD5435yE8FRALEflTkY=
[WebSocket] Connected to: /websocket/Z5ZDermv9h2Q7HL88ukG5ddIvY--zrBAVCN4423KOy5t_6wN3AW859grAYCYr6L-0l0leeXA3AhlO1VmIxcCopS1pJ-IkrVOdmel50tgcA7hBJwEIkpI-biYnraTFc88K4F6wqL3TE_gi1jU0SJHhR6_aD5435yE8FRALEflTkY=
[WebSocket] Disconnected :-( 
ssl->need_bytes=16432 > 6859
WebSocket Host=mpmulti-eavp.slack-msgs.com Path=/websocket/HjuUTJUL4ghmBCthwdFxOYNWD0wGjWbCgQZwnum546F5Nj8rrJ7LJgeyVOLqSv9sBHtkZBrCBLyxdM2oMB85-GXGwtIgg9anVYFL66vMB8yEN9Xout7OMmqlEewZsL7n2vqJyvx_qAnQ9M8UwOnZwETkNYJ51XrUvR6EjIAvAQE=
[WebSocket] Connected to: /websocket/HjuUTJUL4ghmBCthwdFxOYNWD0wGjWbCgQZwnum546F5Nj8rrJ7LJgeyVOLqSv9sBHtkZBrCBLyxdM2oMB85-GXGwtIgg9anVYFL66vMB8yEN9Xout7OMmqlEewZsL7n2vqJyvx_qAnQ9M8UwOnZwETkNYJ51XrUvR6EjIAvAQE=
[WebSocket] Disconnected :-( 
ssl->need_bytes=8496 > 6859

Мой код скетча

Файл Sketch, который я компилирую с помощью Arduino IDE.
Примечание: обязательно обновите Wifi + Slack Bot Token при тестировании 8-)

#include <Arduino.h>

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

#include <WebSocketsClient.h>
#include <ArduinoJson.h>

#define SLACK_SSL_FINGERPRINT "AC 95 5A 58 B8 4E 0B CD B3 97 D2 88 68 F5 CA C1 0A 81 E3 6E" // Если Slack изменит свой отпечаток SSL, вам нужно будет обновить это

#define WIFI_SSID       ""
#define WIFI_PASSWORD   ""

String SLACK_BOT_TOKEN = ""; // Получите токен, создав новую интеграцию с ботом на https://my.slack.com/services/new/bot

#define WORD_SEPERATORS "., \"'()[]<>;:-+&?!\n\t"

ESP8266WiFiMulti WiFiMulti;
WebSocketsClient webSocket;

long nextCmdId = 1;
bool connected = false;

//Настройки часового пояса
const int timezone = 9;     
const int dst = 0; //дневного сбережения

/**
  Sends a ping message to Slack. Call this function immediately after establishing
  the WebSocket connection, and then every 5 seconds to keep the connection alive.
*/
void sendPing() {
  DynamicJsonBuffer jsonBuffer;
  JsonObject& root = jsonBuffer.createObject();
  root["type"] = "ping";
  root["id"] = nextCmdId++;
  String json;
  root.printTo(json);
  webSocket.sendTXT(json);
}



/**
  Looks for color names in the incoming slack messages and
  animates the ring accordingly. You can include several
  colors in a single message, e.g. `red blue zebra black yellow rainbow`
*/
void processSlackMessage(char *payload) {
  char *nextWord = NULL;
  bool zebra = false;
  for (nextWord = strtok(payload, WORD_SEPERATORS); nextWord; nextWord = strtok(NULL, WORD_SEPERATORS)) {
    if (strcasecmp(nextWord, "red") == 0) {
      Serial.printf("Yay! Its red.");
    }

  }
}

/**
  Called on each web socket event. Handles disconnection, and also
  incoming messages from slack.
*/
void webSocketEvent(WStype_t type, uint8_t *payload, size_t len) {
  switch (type) {
    case WStype_DISCONNECTED:
      Serial.printf("[WebSocket] Disconnected :-( \n");
      connected = false;
      break;

    case WStype_CONNECTED:
      Serial.printf("[WebSocket] Connected to: %s\n", payload);
      sendPing();
      break;

    case WStype_TEXT:
      Serial.printf("[WebSocket] Message: %s\n", payload);
      processSlackMessage((char*)payload);
      break;
  }
}

/**
  Establishes a bot connection to Slack:
  1. Performs a REST call to get the WebSocket URL
  2. Conencts the WebSocket
  Returns true if the connection was established successfully.
*/
bool connectToSlack() {
  // Шаг 1: Найдите адрес WebSocket через RTM API (https://api.slack.com/methods/rtm.start)
  HTTPClient http;
  http.begin("https://slack.com/api/rtm.start?token=" + SLACK_BOT_TOKEN, SLACK_SSL_FINGERPRINT);
  int httpCode = http.GET();

  if (httpCode != HTTP_CODE_OK) {
    Serial.printf("HTTP GET failed with code %d\n", httpCode);
    return false;
  }

  WiFiClient *client = http.getStreamPtr();
  client->find("wss:\\/\\/");
  String host = client->readStringUntil('\\');
  String path = client->readStringUntil('"');
  path.replace("\\/", "/");

  // Шаг 2: Откройте соединение WebSocket и зарегистрируйте обработчик событий
  Serial.println("WebSocket Host=" + host + " Path=" + path);
  webSocket.beginSSL(host, 443, path, "", "");
  webSocket.onEvent(webSocketEvent);
  return true;
}

void setup() {
  Serial.begin(115200);
  Serial.setDebugOutput(true);

  WiFiMulti.addAP(WIFI_SSID, WIFI_PASSWORD);
  while (WiFiMulti.run() != WL_CONNECTED) {
    delay(500);
  }

  //настраиваем протокол сетевого времени (ntp)
  configTime(timezone * 3600, dst, "pool.ntp.org", "time.nist.gov"); //configtime — это функция esp8266

  Serial.println("\nWaiting for time sync");
  while (!time(nullptr)) {
    Serial.print(".");
    delay(1000);
  }
  Serial.println("Time is synced");

  delay(500);
}

unsigned long lastPing = 0;

/**
  Sends a ping every 5 seconds, and handles reconnections
*/
void loop() {
  webSocket.loop();

  if (connected) {
    // Отправлять ping каждые 5 секунд, чтобы поддерживать соединение
    if (millis() - lastPing > 5000) {
      sendPing();
      lastPing = millis();
    }
  } else {
    // Пытаемся подключиться/переподключиться к slack
    connected = connectToSlack();
    if (!connected) {
      delay(500);
    }
  }
}

, 👍1

Обсуждение

это, вероятно, работает _иногда_, потому что в этот момент у вас достаточно оперативной памяти. Вы можете попробовать уменьшить использование оперативной памяти с помощью макроса F() для длинных строк и удалить все ненужные вам библиотеки. Надежный способ - передать запрос в slack, используя что-то вроде php-сервера с меньшим SSL-сертификатом; затем вы говорите с блоком PHP вместо slack, и он передает запрос/ответ обратно в ESP., @dandavis

@dandavis - я думаю, ты попал в точку. Уменьшение количества кода в Sketch и повторное тестирование делают его более надежным, но все же этого недостаточно для обеспечения 100% надежности. Ответ от Slack просто слишком велик для обработки. Я просто собираюсь использовать Raspberry Pi для связи со Slack, а затем отправлять команды на Arduino., @Axel

@Axel, PI на самом деле также имеет контакты GPIO (3,3 В!) И должен иметь возможность обрабатывать базовые операции ввода-вывода, так что вы можете даже рассмотреть возможность выпуска Arduino., @Paul

@Paul - Я фактически закончил тем, что использовал Raspberry PI Zero W, который в конечном итоге имел требования к памяти, которые могли обрабатывать мои вызовы API, и все другие встроенные функции, такие как контакты WIFI и GPIO. Неплохо для доски за 10 долларов., @Axel

@Axel Arduino - это платы для разработки микроконтроллеров, а это совсем другое. Если вы собираетесь производить массово, использование микроконтроллеров (чип на самой Arduino) работает очень хорошо (стабильно, надежно, дешево, мало)., @Paul

@Paul - я понимаю разницу. Но возвращаясь к теме моего вопроса: плата Arduino, которую я использовал, не имела требований к памяти для проекта, который я создавал. Моя проблема не имела ничего общего с наличием контактов GPIO 3,3 В, как указано в вашем первом комментарии. Я уже знал, что у Arduino есть такие: P, @Axel

Кроме того, это не для массового производства. Это был разовый проект для личного пользования ;), @Axel


1 ответ


2

замените rtm.start на rtm.connect согласно журналу последних обновлений за апрель 2017 г.

,