1

I'm trying to connect an Adafruit Huzzah ESP8266 with Slack.

I'm facing an issue with the connection I'd like some help or tips on. I'm able to get a connection sometimes, but sometimes during the initial step where I'm making the first connection, I get errors and it completely fails, repeating the connect/disconnect over and over again.

The error I get is usually this:

ssl->need_bytes=16432 > 6859

My Troubleshooting So Far

As per this github issue: https://github.com/esp8266/Arduino/issues/1375

My understanding is that the error is caused by Slack's SSL certificate being too large. This makes sense, but sometimes my code (see below) actually works which is why I'm confused.

When it does work, it usually fails a couple times at first, before maintaining a consistent ping with Slack. At that point, it works as expected, and I can send commands from Slack to the board without fail.

Slack command to ESP8266

Does anyone have an idea why this sometimes works, and sometimes doesn't?

I'm assuming it has something to do with the SSL certificate size being too large, but if that was the case why wouldn't it fail each time, but work sometimes?

Any help is greatly appreciated.


Errors in Serial Monitor

Here's what I see in the Serial Monitor log:

⸮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

My Sketch Code

The Sketch file I'm compiling using the Arduino IDE.
Note: be sure to update Wifi + Slack Bot Token if testing 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" // If Slack changes their SSL fingerprint, you would need to update this

#define WIFI_SSID       ""
#define WIFI_PASSWORD   ""

String SLACK_BOT_TOKEN = ""; // Get token by creating new bot integration at https://my.slack.com/services/new/bot 

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

ESP8266WiFiMulti WiFiMulti;
WebSocketsClient webSocket;

long nextCmdId = 1;
bool connected = false;

//Timezone Settings
const int timezone = 9;     
const int dst = 0; //daylight savings

/**
  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() {
  // Step 1: Find WebSocket address via 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("\\/", "/");

  // Step 2: Open WebSocket connection and register event handler
  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);
  }

  //setup network time protocol (ntp)
  configTime(timezone * 3600, dst, "pool.ntp.org", "time.nist.gov"); //configtime is esp8266 function

  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) {
    // Send ping every 5 seconds, to keep the connection alive
    if (millis() - lastPing > 5000) {
      sendPing();
      lastPing = millis();
    }
  } else {
    // Try to connect / reconnect to slack
    connected = connectToSlack();
    if (!connected) {
      delay(500);
    }
  }
}
7
  • it probably works sometimes becuase you happen to have enough RAM at that moment. You can try reducing RAM usage with the F() macro on long stings, and removing any libs you don't need. The sure-fire way is to proxy the request to slack using something like a php server with a smaller SSL cert; you then talk to the PHP box instead of slack, and it relay's the request/response back to the ESP.
    – dandavis
    Commented Apr 16, 2017 at 21:51
  • @dandavis - I think you're spot on. Reducing the amount of code in the Sketch and testing again makes it more reliable, but simply not enough still to ensure 100% bulletproof. The response back from Slack is simply too large to handle. I'm just going to use a Raspberry Pi to communicate with Slack, and then send the commands down to an Arduino.
    – Axel
    Commented Apr 19, 2017 at 23:00
  • @Axel, the PI actually also has GPIO pins (3.3V!) and should be able to handle basic I/O, so you might even consider letting out the Arduino.
    – aaa
    Commented Feb 19, 2018 at 18:12
  • @Paul - I actually ended up using a Raspberry PI Zero W which ended up having the memory requirements that could handle my API calls, and all the other functionality built such as WIFI and GPIO pins. Not bad for a $10 board.
    – Axel
    Commented Feb 20, 2018 at 20:44
  • @Axel Arduino's are development boards for microcontrollers which is a quite different thing. If you're going to mass produce, using microcontrollers (the chip on the Arduino itself) works very well (stable, reliable, cheap, small).
    – aaa
    Commented Feb 21, 2018 at 7:57

1 Answer 1

2

replace rtm.start with rtm.connect as per April 2017 Recent Updates log

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.