6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

esp8266でSlackBotを作ってIFTTTからのメッセージを待ち受けする

Posted at

esp8266のSlackBotをIFTTT経由で操作する

背景

GoogleHomeからesp8266を制御しようとしたときに、IFTTT-Slack経由が一番ラクにできそうだったのでトライしてみた。

用意するもの

esp8266(WROOM02)

参考サイトをみてSlackBotをつくる

Arduino(ESP8266)にSlack Botを乗せてみた

ちょっとだけトラブル発生

参考サイト通りにやると人間の投稿には反応できるけど、IFTTTからのメッセージには反応してくれない。
シリアルログをみるとIFTTTからのメッセージは添付扱いになっているため、すこし階層が深くなっている模様。

対策版

かなりやっつけだけど「root["attachments"][0]["pretext"]」でIFTTTからのメッセージを参照できた。
ソースコードは以下。

// https://github.com/urish/arduino-slack-bot

#include <Arduino.h>
#include <Hash.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266HTTPClient.h>
#include <WebSocketsClient.h>
#include <ArduinoJson.h>
#include <Servo.h>

#define WIFI_SSID "あなたのSSID"
#define WIFI_PASSWORD "あなたのWIFIパスワード"

#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 SLACK_BOT_TOKEN "スラックボットのTOKEN"
#define DEFAULT_CHANNEL "チャンネルID?"

ESP8266WiFiMulti WiFiMulti;
WebSocketsClient webSocket;

long nextCmdId = 1;
bool connected = false;
bool helloSaid = false;

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);
      break;

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

void processSlackMessage(char *payload) {
  StaticJsonBuffer<2000> jsonBuffer;
  JsonObject& root = jsonBuffer.parseObject(payload);
  if (!root.success()) {
    Serial.println("[Json] Parse failed");
    return;
  }

  if(root.containsKey("type")) {
    if(strcmp("hello", root["type"]) == 0) {
      helloSaid = true;
    } else if (strcmp("message", root["type"]) == 0) {
      if(root.containsKey("attachments")) {
        if(strcmp("IFTTT経由メッセージのキーワード", root["attachments"][0]["pretext"]) == 0) {
          // キーワードを見つけたときの処理
        }
      }else if(root.containsKey("text")) {
        if(strcmp("通常メッセージのキーワード", root["text"]) == 0) {
          // キーワードを見つけたときの処理
        }
      }
    }
  }
}

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 sendPing() {
  DynamicJsonBuffer jsonBuffer;
  JsonObject& root = jsonBuffer.createObject();
  root["type"] = "ping";
  root["id"] = nextCmdId++;
  String json;
  root.printTo(json);
  webSocket.sendTXT(json);
}

void sendMessage() {
  DynamicJsonBuffer jsonBuffer;
  JsonObject& root = jsonBuffer.createObject();
  root["type"] = "message";
  root["channel"] = DEFAULT_CHANNEL;
  root["text"] = "fuga";
  String json;
  root.printTo(json);
  webSocket.sendTXT(json);
}

void setup() {
  servo.attach(servoPin);
  servo.write(angle);
  Serial.begin(9600);
  while (!Serial) {
    delay(100);
  }
  Serial.setDebugOutput(true);

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

  configTime(3 * 3600, 0, "pool.ntp.org", "time.nist.gov");
}

unsigned long lastPing = 0;

void loop() {
  webSocket.loop();

  if (connected) {
    // Send ping every 5 seconds, to keep the connection alive
    if (millis() - lastPing > 5000) {
      if(helloSaid) {
        sendPing();
      }
      lastPing = millis();
    }
  } else {
    // Try to connect / reconnect to slack
    connected = connectToSlack();
    if (!connected) {
      delay(3000);
    }
    lastPing = millis();
  }
}
6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?