ESP32 で作るSlack通知ボタン

Wed, 25 Dec 2019


この記事は Fusic その 2 Advent Calendar 2019 25 日目の記事です。

はじめに

カレンダーの最終日ですが、気負わず普通の記事を書こうと思います。

今回は Wifi 搭載のマイコン ESP32 を使って、簡単な Slack 通知ができるボタンを作ってみたいと思います。

使用機器

環境構築手順

Arduino IDE のインストール

  1. ここ からOSにあったものを選んでダウンロード
  2. 解凍
  3. 起動

img

こんな画面が出たらOK

ESP32 開発ボード用のライブラリを追加

  1. Arduino IDE を起動
  2. メニューから Arduino - Preferences... を選択
  3. Additional Board Manager URLs に https://dl.espressif.com/dl/package_esp32_index.json を追加
  4. メニューから Tools - Board - Boards Manager... を選択
  5. Esp32 で検索
  6. esp32 by Espressif Systems をインストール

img

開発ボードと接続するためのシリアルポートの準備

  1. Arduino IDE のメニューから Tools - Port - /dev/cu.SLAB_USBtoUART を選択できるか確認(Macの場合)
  2. 多分普通は無いので https://jp.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers をインストール
  3. インストール後は、セキュリティとプライバシーで実行許可を与える必要があると思う(再起動も必要かも)

※ ボードを接続した状態じゃないと「ポート」のリストに表示されないので注意

Slack 通知ボタンとして使用する

ひとまずインターネットに接続する

まずはESP32をインターネットの海に出航させます。 といっても、サンプルコードがあるので全くもって難しいことは有りません。

また、ESP32はWifiモジュールが搭載されているので、電源さえ投入すれば今回のサンプルコードは動作します。

#include <WiFiClientSecure.h>	// HTTPS接続が可能なWifiクライアントを利用可能にするためのライブラリ

const char* ssid     = "ssid";	// SSID
const char* password = "password";		// Wifi パスワード
const char* host = "fusic.co.jp";		// 試しに接続するホスト名

void setup() {
  // 前回と同じ
  Serial.begin(115200);
  pinMode(26,INPUT);
  pinMode(25,OUTPUT);

  Serial.print("Connecting to ");
  Serial.println(ssid);
  // Wifi 接続
  WiFi.begin(ssid, password);
  // ステータスが connected になるまで待機
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  // 接続情報をコンソールに表示
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  // サーバーへ接続するためのクライアントを作成
  WiFiClientSecure client;
  // ポート番号443を指定して接続
  const int httpPort = 443;
  if (!client.connect(host, httpPort)) {
      Serial.println("connection failed");
      return;
  }
  // HP トップのコンテンツを取得
  String url = "/";
  Serial.print("Requesting URL: ");
  Serial.println(url);
  // HTTP のリクエストを作成
  client.print(String("GET ") + url + " HTTP/1.1\r\n" +
    "Host: " + host + "\r\n" +
    "Connection: close\r\n\r\n");
  unsigned long timeout = millis();
  // コンテンツの取得を待機
  while (client.available() == 0) {
    // 5s でタイムアウト
    if (millis() - timeout > 5000) {
      Serial.println(">>> Client Timeout !");
      client.stop();
      return;
    }
  }

  // 取得したコンテンツをバッファから取り出して表示
  while(client.available()) {
    String line = client.readStringUntil('\r');
    Serial.print(line);
  }

  Serial.println();
  Serial.println("closing connection");
}

void loop() {
  int old = LOW;
  int input = digitalRead(26);
  if (old != input) {
    old = input;
  }
  
  if (input == LOW) {
    digitalWrite(25,HIGH);
    
  } else {
    digitalWrite(25,LOW);
  }
}

このコードを書き込んでシリアルコンソールを見ると、FusicのコーポレートサイトのTOPのHTMLデータが表示されます。

<!DOCTYPE html>
<html>
  <head lang="ja">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

<meta name="keywords" content="Fusic,システム開発,システム運用,アジャイル開発,採用情報,ITコンサルティング,福岡,九州,ベンチャー">

・・・

スイッチが押されたらSlackにメッセージを投稿する

無事にWifiに接続できたので、今回はSlackにメッセージを投稿します。 もうここまできたら、ほぼ馴染み深いプログラムの世界です。

ソースコードは下記になります。
色々と書いていますが、大事なのは send_data() の部分です。
とは言え、ここはただHTTPのPOSTをしているだけなので、特に細かい説明はしません。
(相変わらずSlackのpayloadの仕様は面倒くさいですね)

#include <WiFiClientSecure.h>

const char* ssid     = "ssid";
const char* password = "password";
const char* host = "hooks.slack.com";
const char* hook_path = "自分のIncomingWebHooksのPathを設定する";
const int httpsPort = 443;

const int BLUE_LED = 13;
const int GREEN_LED = 12;
const int RED_LED = 14;

void setup() {
  Serial.begin(115200);
  pinMode(25,INPUT);
  pinMode(26,INPUT);
  pinMode(27,INPUT);
  pinMode(33,INPUT);
  pinMode(32,INPUT);
  pinMode(13,OUTPUT);
  pinMode(12,OUTPUT);
  pinMode(14,OUTPUT);

  // Wifi Setting
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  int wifi_status = 0;
  while (WiFi.status() != WL_CONNECTED) {
    delay(100);
    if (wifi_status == 0) {
      digitalWrite(BLUE_LED, HIGH);
      wifi_status = 1;
    } else {
      digitalWrite(BLUE_LED, LOW);
      wifi_status = 0;
    }
  }

  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  digitalWrite(BLUE_LED, HIGH);
  wifi_status = 1;
}

void error_led(int num) {
    for(int i = 0; i < num; i++) {
    digitalWrite(RED_LED, HIGH);
    delay(300);
    digitalWrite(RED_LED, LOW);
    delay(300);
  }
}

void send_data(String message) {
  // Use WiFiClientSecure class to create TLS connection
  WiFiClientSecure client;
  Serial.print("connecting to ");
  Serial.println(host);
  if (!client.connect(host, httpsPort)) {
    Serial.println("connection failed");
    error_led(3);
    return;
  }

  Serial.print("requesting URL: ");
  Serial.println(hook_path);

  client.print(String("POST ") + hook_path + " HTTP/1.1\r\n" +
      "Host: " + host + "\r\n" +
      "User-Agent: ESP32Client\r\n" +
      "Content-Type: application/json\r\n" +
      "Content-Length: "+ String(message.length()) +"\r\n\r\n" +
      message+"\r\n\r\n");

  Serial.println("request sent");
  while (client.connected()) {
    String line = client.readStringUntil('\n');
    if (line == "\r") {
      Serial.println("headers received");
      break;
    }
  }
  String line = client.readString();
  Serial.println("reply was:");
  Serial.println("==========");
  Serial.println(line);
  Serial.println("==========");
  Serial.println("closing connection");
}

void loop() {
  int white_button = digitalRead(25);
  int blue_button = digitalRead(26);
  int red_button = digitalRead(27);
  int gray_button = digitalRead(33);
  int black_button = digitalRead(32);

  if (blue_button == LOW) {
    digitalWrite(GREEN_LED, HIGH);
    send_data("{\"text\":\"Result: :apple:\",\"blocks\":[],\"attachments\":[{\"color\":\"#00FF00\",\"blocks\":[{\"type\":\"section\",\"text\":{\"type\":\"mrkdwn\",\"text\":\"A message *with some bold text* and _some italicized text_.\"}}]}]}");
    digitalWrite(GREEN_LED, LOW);
  }
  
  delay(100);
}

結果

こちらがボタンを押す前。

img

こちらが今回組み上げた回路です。今後のためにスイッチを増やしているので、ごちゃごちゃしています。
Wifiに接続している時は青色のLEDを点灯させて、接続状態がひと目で分かるようにしています。
この状態で青色のボタンを押すと、Slackにメッセージを投稿する処理が発火します。

img

写真だとわかりにくいですが、通信中は緑色のLEDを点灯させています。

img

数秒くらいで、Slackにメッセージが投稿されます。

img

無事にボタンを押すと Slack に通知が飛ぶ Slack 通知ボタンができました。

まとめ

今日は ESP32 を使って Slack 通知ボタンを作ってみました。 「ボタンを押すと」のところを別のセンサーにしてみたり、「Slackに通知」の部分を別のAPIにしてみたりすれば、可能性は無限大ですね。

それでは良いお年を!


← back