Skip to content

Instantly share code, notes, and snippets.

@libbymiller
Last active January 29, 2019 17:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save libbymiller/e3511c16d1590467171d9e157c6218b1 to your computer and use it in GitHub Desktop.
Save libbymiller/e3511c16d1590467171d9e157c6218b1 to your computer and use it in GitHub Desktop.
Slackwobbler - anywhere - updated to new ArduinoJson and improved by Tim
/**
Arduino Real-Time Slack Bot
Copyright (C) 2016, Uri Shaked.
Licensed under the MIT License
https://github.com/urish/arduino-slack-bot
Bodged to use WiFiManager and a servo by libby.
Instructions:
* Install CH340G Driver (no need for Linux) https://wiki.wemos.cc/downloads
* set up Arduino environment for ESP 8266: https://chewett.co.uk/blog/937/configuring-wemos-d1-mini-pro-esp8266-arduino-ide/
* add this library: https://github.com/tzapu/WiFiManager
* add latest ArduinJson - 6.7.0
* update line 39 with SLACK_BOT_TOKEN
WiFiManager gives you a wifi portal to connect to (called 'wobbler') if it doesn't find its last wifi network.
You connect to it, a browser captive portal window should launch, and you can add your wifi details there.
*/
#include <Arduino.h>
#include <WiFiManager.h>
//https://github.com/tzapu/WiFiManager
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266HTTPClient.h>
#include <WebSocketsClient.h>
#include <ArduinoJson.h>
#define NAME "wobbler"
#define SLACK_SSL_FINGERPRINT "C1 0D 53 49 D2 3E E5 2B A2 61 D5 9E 6F 99 0D 3D FD 8B B2 B3" // If Slack changes their SSL fingerprint, you would need to update this
#define SLACK_BOT_TOKEN "xxxxx" // Get token by creating new bot integration at https://my.slack.com/services/new/bot
#define LEDS_PIN D2
#define LEDS_NUMPIXELS 24
#define WORD_SEPERATORS "., \"'()[]<>;:-+&?!\n\t"
ESP8266WiFiMulti WiFiMulti;
WebSocketsClient webSocket;
long nextCmdId = 1;
bool connected = false;
#include <Servo.h>
Servo myservo; // create servo object to control a servo
int pos = 0; // variable to store the servo position
/**
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() {
DynamicJsonDocument jsonBuffer;
JsonObject root = jsonBuffer.to<JsonObject>();
root["type"] = "ping";
root["id"] = nextCmdId++;
String json = "";
serializeJson(jsonBuffer, json);
webSocket.sendTXT(json);
}
/**
Looks for names in the incoming slack messages
*/
void processSlackMessage(char *payload) {
StaticJsonDocument<200> doc;
deserializeJson(doc, payload);
JsonObject root = doc.as<JsonObject>();
if(root["type"] == "message") {
const char *message = root["text"];
char *nextWord = NULL;
for (nextWord = strtok((char *) message, WORD_SEPERATORS); nextWord; nextWord = strtok(NULL, WORD_SEPERATORS)) {
//Serial.println(nextWord);
if (strcasecmp(nextWord, "wordtomatch") == 0 ||
strcasecmp(nextWord, "@here") == 0) {
Serial.println("match!!!");
myservo.write(0);
delay(200);
myservo.write(180);
delay(200);
myservo.write(0);
delay(200);
myservo.write(180);
delay(200);
myservo.write(0);
}
}
}
}
/**
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.connect)
HTTPClient http;
http.begin("https://slack.com/api/rtm.connect?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);
//wemos D1 pinout: https://escapequotes.net/esp8266-wemos-d1-mini-pins-and-diagram/
// we are using IO5 -> D1
myservo.attach(5);
WiFiManager wifiManager;
// Try to connnect to the previously configured wifi network - or project a
// configuration portal temporarily.
//
wifiManager.autoConnect(NAME);
Serial.println("connected");
configTime(3 * 3600, 0, "pool.ntp.org", "time.nist.gov");
}
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);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment