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.
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);
}
}
}
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.