ラズパイとSwiftでSlackに投稿ボタンをつくろう！

![Raspbian-10](https://img.shields.io/badge/Raspbian-10-brightgreen) ![Swift-5.1.5](https://img.shields.io/badge/Swift-5.1.5-brightgreen) ![SwiftyGPIO-1.3.1](https://img.shields.io/badge/SwiftyGPIO-1.3.1-brightgreen)

## はじめに
最近ラズパイをさわり始めました。せっかくなので Swift とラズパイで Slack で今日は休む旨を伝えるボタンを作りたいと思います！

こんな感じです。

![bot_user](https://user-images.githubusercontent.com/34936885/101289147-05b7ee00-383e-11eb-9c0d-f9c51d0267da.gif)

## 必要なもの
今回必要なものは下記です。

* microSD カード
* Raspberry Pi 3 Model  
なんとなく３買いましたが４の方がいいと思います（４の場合電源は USB-C です）。
* マイクロ USB 電源コード
* 10 K の抵抗×1
* スイッチ×1
* オスーメスジャンバ線×3
* ブレッドボード

具体的なのは下記参照  
[MacでラズパイのLチカしてみたー必要なもの](https://www.am10.blog/?p=247#toc2)

## ラズパイ設定
OS のインストールや SSH 接続までは下記参照  
[MacでラズパイのLチカしてみたーSD 準備](https://www.am10.blog/?p=247#toc3)

## Swift のインストール
ラズパイに Swift をインストールします！手順は簡単です。

ラズパイに SSH 接続して下記コマンドを実行します。

```
# Swift-Armのインストール
$ curl -s https://packagecloud.io/install/repositories/swift-arm/release/script.deb.sh | sudo bash
 
# Swift のインストール
$ sudo apt-get install swift5
```

最初の curl コマンドで OS を調べて適切なものを色々インストールしてくれます。

インストール後に下記コマンドを実行してバージョンが表示されれば成功です。

```
$ swift --version
```

> Swift version 5.1.5 (swift-5.1.5-RELEASE)  
> Target: armv6-unknown-linux-gnueabihf

参考：[Raspberry Pi で Swift を使えるようにする【Swift 5】 - Swift-Arm の入手](https://qiita.com/treastrain/items/70235b092219c5a35ff5#swift-arm-%E3%81%AE%E5%85%A5%E6%89%8B)

ついでに vim もインストールしておきます（ソース書くとき使います）。

```
$ sudo apt-get install vim
```

## Slack 準備
Slack に投稿にはトークンが必要なので準備します。

1. [Slack API](https://api.slack.com/apps?new_app=1) にアクセスし App Name と Workspace を入力し Create App をクリックする。

    <img width="300" alt="create_app" src="https://user-images.githubusercontent.com/34936885/98470783-6ea24b00-222b-11eb-968a-6c5cf6da476d.png">

1. 左側メニューの OAuth & Permissions をクリックする。
1. Scopes -> Bot Token Scopes に chat:write を追加する。
1. OAuth & Permissions ページの上部にある Install App to Workspace をクリックする。
1. インストール後下記が表示されるのでトークンをコピーする。

    <img width="300" alt="token" src="https://user-images.githubusercontent.com/34936885/98470821-94c7eb00-222b-11eb-88b4-43ec6054b8d9.png">

1. Slack の投稿したいチャンネルにアプリを追加する。

    <img width="150" alt="add_app" src="https://user-images.githubusercontent.com/34936885/98470826-9db8bc80-222b-11eb-989e-c318fb357c06.png">

## 配線
![GPIO](https://user-images.githubusercontent.com/34936885/98434729-8d162280-2115-11eb-977c-65f473f97a89.png)

[公式ドキュメントから引用](https://www.raspberrypi.org/documentation/usage/gpio/README.md)

配線は下記です（上の図を参考にどうぞ）。

1. ブレッドボードの j30 にジャンバ線１のオスを挿す。
1. ブレッドボードの j28 にジャンバ線２のオスを挿す。
1. ブレッドボードの j23 にジャンバ線３のオスを挿す。
1. 抵抗をブレッドボードの i23 と i28 に挿す。
1. ボタンをブレッドボードの f30, e30, f28, e28 に挿す。
1. ジャンバ線１のメスをラズパイの 3.3V に挿す。
1. ジャンバ線２のメスをラズパイの GPIO9 に挿す。
1. ジャンバ線３のメスをラズパイの GPIO11 横の GND に挿す。

## ラズパイ準備
いよいよ Swift でコードを書いていきます。

1. SSH 接続する。
1. 下記コマンドで必要なものを準備する。

    ```
    // ディレクトリ作成
    $ mkdir SlackPost

    // ディレクトリに移動
    $ cd SlackPost

    // プロジェクト初期化
    $ swift package init --type executable

    // Package.swift編集
    $ vim Package.swift
    ```

1. i と入力し入力モードにする。
1. 下記を追記する。

    ```swift
    // 省略
    dependencies: [
        .package(url: "https://github.com/uraimo/SwiftyGPIO.git", from: "1.0.0") // ここ追加
    // 省略
    targets: [
        .target(name: "SlackPost", dependencies: ["SwiftyGPIO"]), // ここ追加
    // 省略
    ```

1. 下記コマンドを実行する。

    ```
    $ vim Sources/SlackPost/main.swift
    ```

1. i と入力し入力モードにする。
1. 下記のようにソースを記述する。

    ```swift
    import Foundation
    import FoundationNetworking
    import SwiftyGPIO

    extension String {
        
        var urlEncoded: String {
            let charset = CharacterSet.alphanumerics.union(.init(charactersIn: "!$&'()*+,;=/?-._~"))
            let removed = removingPercentEncoding ?? self
            return removed.addingPercentEncoding(withAllowedCharacters: charset) ?? removed
        }
    }

    func postMessage(channel: String, text: String) {
        let token = "調べたトークン"
        var request = URLRequest(url: URL(string: "https://slack.com/api/chat.postMessage")!)
        var components = URLComponents(url: request.url!, resolvingAgainstBaseURL: true)
        components?.percentEncodedQuery = "token=\(token)&channel=\(channel)&text=\(text)".urlEncoded
        request.url = components?.url
        let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
            if let error = error {
                print("error: \(error.localizedDescription)")
                return
            }
            if let data = data, let textData = String(data: data, encoding: .utf8) {
                print(textData)
            }
        }
        task.resume()
    }

    let gpios = SwiftyGPIO.GPIOs(for: .RaspberryPi3)
    var gp = gpios[.P9]!
    gp.direction = .IN
    var before = 0
    while true {
        let now = gp.value
        if before == 0 && now == 1 {
            print("Push!!!")
            postMessage(channel: "#random", text: "ぽんぽんぺいんで今日休みます:dizzy_face")
        }
        Thread.sleep(forTimeInterval: 0.1)
        before = now
    }
    ```

## 起動
投稿ボタン起動！！

1. ラズパイに SSH 接続する。
1. 下記コマンドで起動する。

    ```
    # ビルド
    $ swift build

    # 実行
    $ swift run
    ```

これでボタンを押せば Slack に投稿できます！（終了する場合は ctrl + C）

![bot](https://user-images.githubusercontent.com/34936885/101289139-f20c8780-383d-11eb-8237-c7b9dec63020.gif)

## ちょっと改良
このままだとボットが休むことを伝えることになります。休む場合は自分で伝えるべきでしょう！

[Slack API](https://api.slack.com/apps) の OAuth & Permissions ページにアクセスし Scopes の User Token Scopes に chat:write を追加し App の reinstall を行います。

<img width="300" alt="scope" src="https://user-images.githubusercontent.com/34936885/101288924-7b22bf00-383c-11eb-8e50-e4f38d781880.png">

下記のように OAuth Access Token が発行されるのでこのトークンを使うようにします。

<img width="300" alt="token" src="https://user-images.githubusercontent.com/34936885/101288932-81b13680-383c-11eb-8bb5-6d0193125244.png">

起動!!

![bot_user](https://user-images.githubusercontent.com/34936885/101289147-05b7ee00-383e-11eb-9c0d-f9c51d0267da.gif)

無事自分の口で休むことを伝えることができるようになりました:clap:

## おわりに
これで朝起きたらボタン一つで休めるようになりました:relaxed:

私が言いたかったのは Swift でできるのは iOS, Mac アプリを作ることだけじゃない！！！ということです:sunglasses:

## 参考
* [Slack API-chat.postMessage](https://api.slack.com/methods/chat.postMessage)
* [Raspberry Pi で Swift を使えるようにする【Swift 5】 - Swift-Arm の入手](https://qiita.com/treastrain/items/70235b092219c5a35ff5)