CIでビルドが終わると光るゴーファーを作る

## これは何か
CIでビルドの開始や完了したとき、CIからURLを叩くと通知してくれるデバイスです。
ブランチ名とビルド開始、成功、失敗を表示してくれます。

- [すべての写真はこちら](https://photos.app.goo.gl/6GHy4HdUathKcG6J2)
- [動画はこちら](https://photos.app.goo.gl/VxdWpq93nFTKG1lV2)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/55138/bb3cc1e0-d8e3-afac-2e55-b94ca6287581.png)

## どうやって動いているのか？
CIがURLを叩いてから、通知されるまで流れは簡単に次のようになります。

- CIがGoogle Cloud FunctionsのURLを叩く
  - ブランチ名と、ビルドの開始、成功、失敗のいずれかのフラグを送ります
- Google Cloud Functionsからsakura.ioのIncoming WebhookのAPIを叩きます
- sakura.ioの通信モジュールを繋げたArduinoからデバイスを制御します
  - LCDにブランチ名とビルド状況を表示します
  - RGB LEDをビルド状況に応じて光らせます

![image.png](https://qiita-image-store.s3.amazonaws.com/0/55138/4024d071-f8eb-2841-eea6-c2598d2994c8.png)


## 使われているパーツ
  - [sakura.ioのモジュール](https://sakura.io/product/module_lte.html)
  - [sakura.ioのArduinoのシールド](https://sakura.io/product/arduino.html)
  - [Arduino Uno](https://store.arduino.cc/usa/arduino-uno-rev3)
  - Arduino用シールド基盤
    - [Arduino用バニラシールド基板ver.2](https://www.switch-science.com/catalog/990/)
    - [フルカラーLED（OSTBMCZ2C1D CathodeCOM）](https://www.sengoku.co.jp/mod/sgk_cart/detail.php?code=EEHD-4TTS)
    - 抵抗 100Ωx2、150Ωx1
    - L字ピンヘッダ
    - ピンヘッダ
  - キャラクタ液晶(20x4)：[AitendoのSPIキャラクタ液晶キットの基盤で代替可能](http://www.aitendo.com/product/14622)
    - [STNキャラクタ液晶モジュール（20x4）](http://www.aitendo.com/product/15637)
  - キャラクタ液晶のSPI化モジュール
    - [８ビットシフトレジスタ SN74HC595N](http://www.aitendo.com/product/2439)
    - 丸ピンソケット（SN74HC595N用）
    - 両面ユニバーサル基板
    - 可変抵抗 1kΩ x2
  - ネジ類
    - 3mm round screws and nuts(for LCD)
    - 2mm tapping screws(for body)
    - 1.5mmのピン
    - etc...
  - 透明なゴーファー人形
    - 3Dプリンター（[筆者が使っているのはこれ](https://www.amazon.co.jp/gp/product/B01CRNV038)）
    - パテ
    - サンドペーパー
    - サーフェイサー
    - [シリコンゴム](https://www.amazon.co.jp/gp/product/B004P1SK8E)
    - [透明なレジン（ホビーキャストNX 透明）](https://www.amazon.co.jp/gp/product/B00AFRRELG)
    - [離型剤](https://www.amazon.co.jp/gp/product/B00KSX5PNQ)

## 筐体を3Dプリンターで印刷する
[Gopherフィギュアを作る](https://qiita.com/cattaka/items/ff96446cc60c8e06d4e0)で紹介したもののベースのデータを使用します。
3Dデータはここにあります。

https://github.com/cattaka/CiNotifier/tree/master/body

![image.png](https://qiita-image-store.s3.amazonaws.com/0/55138/27b1f47b-a665-c3bd-7254-3dafc605c164.png)


## Building Hardware
**キャラクタ液晶のSPI化モジュール**と**Arduino用のシールド基盤**の２つを作ります。

### 透明のゴーファーフィギュアを作る
次のデータから3Dプリンターでゴーファーを印刷します。後述の枠を使うためには高さが7cmになるようにスケールさせてください。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/55138/9e21e5d7-af4d-0a52-e69a-0e04dd76e61b.png)

https://github.com/cattaka/go-gopher-model/blob/master/go_gopher_high.stl

サンドペーパーとパテ、サーフェイサーを使い表面を整えます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/55138/d1ef136d-40ee-3c26-dc2c-902b985c0225.png)

シリコンゴムで型を取るための枠を作りますが、シリコンゴムを流し込むための枠が必要です。これも3Dプリンターで作りましょう。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/55138/c7538515-b96f-df93-45a1-f6001d4a7abe.png)

https://github.com/cattaka/go-gopher-model/tree/master/BoxForGopher

ゴーファーを固定用の土台に接着します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/55138/643295b7-2bcd-405b-6ae5-8d9d1f9c23b3.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/55138/9dbf2bf4-5efc-312e-56ab-c5692f14dfb7.png)

準備ができたらシリコンゴムを流し込み、後ろ半身の型を取ります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/55138/b4961895-bac7-ff24-1eb8-0aa1d960bf19.png)

シリコンゴムが十分に硬化したら、ネジを外して、合わせ目用の部品を取り払います。
そして合わせ目になる場所に離型剤を塗布します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/55138/96849587-a595-8519-5ef5-02f4a047a9f8.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/55138/d49c4ef0-863f-f94f-bca0-9462a9d5e57e.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/55138/4fd1182e-f8ee-be5c-0ae9-d8638a3b2be0.png)

前半身側にシリコンゴムを流します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/55138/f12d9b14-1fc4-4005-ca99-d8d12228de15.png)

シリコンゴムが十分に硬化したら、分解し、両側に離型剤を塗ります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/55138/c18b5190-6fd6-7d85-b817-bfb2342d1ea9.png)

これで型が完成しました。

透明のレジンを使い、ゴーファーを錬成します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/55138/4e6c5eeb-3c36-60d5-52b9-a63b24eacfbb.png)

かなり前に買った古いレジンを使ったため濁ってしまいましたが、ゴーファーが錬成できました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/55138/5ff1881c-e6a2-a10b-3ccb-34fc5e99336f.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/55138/d02f26aa-0766-1055-1e6f-dc993c105c1c.png)

筐体へ固定するためのネジ穴を20mm間隔で２つ空けます。
正確に20mm間隔にするには3Dプリンターで治具を作るといいでしょう。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/55138/8acff96f-2ef0-961d-4251-4eea5d1000e9.png)

穴が空いたら固定用のピンを刺します。
これで透明のゴーファーフィギュアが完成しました。


### キャラクタ液晶のSPI化モジュール
この部品はLCDをSPIで制御するために必要です。
SPIを使わない場合は各自でコードと回路を調整してください。
[AitendoのSPIキャラクタ液晶キットの基盤](http://www.aitendo.com/product/14622)を使うこともできます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/55138/c53b6bee-7e8e-61b8-975a-99f8761cb7d8.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/55138/9c15f74b-7c38-6280-98ae-fe9aba397c92.png)


### Arduino用のシールド基盤
ArduinoにLEDとLCDを繋ぐための回路を、シールド基盤として作ります。
もし、Arduino LeonardoのようにSPIのピンアサインが違うものを使う場合は回路を適宜修正してください。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/55138/06bd408f-11d8-6115-c62b-b46372e7bf06.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/55138/29c4233c-2ba4-f859-02b7-b378e19f5333.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/55138/dce741ce-4f6c-1a4b-2ab4-cab59f2d9970.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/55138/af3ecf18-781e-76ab-5558-1109bb61b707.png)

回路ができたら[ArduinoのSPIを使ったLiquidCrystalのサンプル](https://playground.arduino.cc/Main/LiquidCrystal)のスケッチで動作確認をしましょう

![image.png](https://qiita-image-store.s3.amazonaws.com/0/55138/ccf50884-fb10-051f-db64-dd0c97e94005.png)


### sakura.ioのDIPスイッチの設定
SPIを使います。
5Vに設定し、CS(Chip Select)は9番PINを設定します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/55138/b8e30c42-6555-ada1-c7e9-b097e46a2f3f.png)


### 組み立て
LCDのケース上部に固定します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/55138/8ea1afdb-3c3e-6997-70f9-13536dc7aaec.png)

Arduinoをケース下部に固定します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/55138/2caf503a-b8c5-626f-c920-d75b47252d79.png)

Arduinoにsakura.ioの通信モジュールを刺し、その上にsakura.ioの通信モジュールを、その上に作成したシールド基盤を刺します。
そしてLCDとシールド基盤を繋ぎます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/55138/7d9ab5d5-23a3-f01a-15a4-d73ee3672e4a.png)

ケースを閉じ、ゴーファーを載せてハードウェアは完成です。


## ソフトウェアのインストールと設定
ソフトウェアをインストールする場所はGoogle Cloud FunctionsとArduinoの２つがあります。また、sakura.ioの設定が必要になります。

すべてのソースコードは https://github.com/cattaka/CiNotifier にあるのでクローンしてください。

### sakura.ioの設定
https://sakura.io/ からログインしてコンソールを開きます。
自分のsakura.ioの通信モジュールのデバイスを登録します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/55138/0d37dc0b-edfd-addf-2d71-d83810518b12.png)

Incoming Webhookを作成します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/55138/346f005e-cd69-5c52-4bbb-0b757696e30a.png)

ダッシュボードで追加したモジュールのIDと、Incoming WebhookのUUIDは後述のsettings.jsonに記述します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/55138/7fcca1c7-7235-6f07-d9a5-4ec72ec2ad7e.png)



### Arduinoへの書き込み
次のスケッチをArduino IDEなどでArduinoに書き込んでください。特に修正する必要はありません。

https://github.com/cattaka/CiNotifier/tree/master/arduino/CiNotifier


### Google Cloud Functionsへのデプロイ
Google Cloud Functionsの始め方は[公式のドキュメント](https://cloud.google.com/functions/docs/tutorials/http)を参照してください。次のソースコードを開いてください。

https://github.com/cattaka/CiNotifier/tree/master/CloudFunctions

**settings.json.sample**を**settings.json**という名前でコピーし、必要な箇所を修正してください。

settings.json

```json
{
  "passphrase": "foobar"
  "webhook_token": "hogehoge-fuga-fuga-fuga-hogehogefuga",
  "module_ids": [
    "hogefugahoge"
  ]
}
```

- passphrase：アクセス制御に使います。自由に指定してください。
- webhook_token：sakura.ioのIncoming Webhookに表示されているUUIDを指定してください
- module_ids：あなたのsakura.ioのモジュールのidを指定してください。複数台可。

動作確認は次のスクリプトで行なえます。このときデバイスが組み立てられて電源が入っていれば、LEDやLCDの動作も確認できます。

```sh
$ node test_run.js <passphrase> <branch_name> <build_state>
```

動作確認ができればGoogle Cloud Functionsにデプロイしましょう。

```sh
$ gcloud beta functions deploy \
  ci_notifier \
  --trigger-http
```

デプロイが完了すればURLを叩いて動作確認をしましょう。
URLのパラメータのpassphrase、branch_name、build_stateは適宜指定してください。

```
$ curl https://<your-project-location>.cloudfunctions.net/ci_notifier?passphrase=<your-passphrase>&branch_name=<branch_name>&build_state=<build_state>
```

おめでとうございます！
後はCIのビルドフローの中にURLを叩く処理を入れるだけです。


## 通信内容の解説
sakura.ioのIncoming WebhookはHTTPのPOSTを使い、メッセージを通信モジュールに送ることができます。また通信モジュールにはメッセージのチャネルが複数あり、何番のチャネルに送るか指定します。一度のPOSTで小さなデータ(最大8byte)を含んだメッセージを16個まで送ることができます。

このデバイスでは**ブランチ名の断片を送る用のチャネル**と、**ビルド状況を送る用のチャネル**と、**光り方を指定する用のチャネル**の３つを使用しています。

### ブランチ名の断片を送る用のチャネル
sakura.ioのIncoming Webhookは１つのメッセージで8byteしか送れません。しかしブランチ名は軽く8byteを超えます。またLCDの表示文字数の問題で、長すぎても表示できません。なので[適当に短く](https://github.com/cattaka/CiNotifier/blob/9682e6527e3c78939746cbf8cffaa3ed793b6b22/CloudFunctions/index.js#L134-L158)した後、[8byteごとに分割](https://github.com/cattaka/CiNotifier/blob/9682e6527e3c78939746cbf8cffaa3ed793b6b22/CloudFunctions/index.js#L80-L92)して複数のメッセージに分けて送ります。
Arduino側で受信したデータは一旦バッファに保持し、まだ表示はしません。

### ビルド状況を送る用のチャネル
ビルドの状況は**開始**、**成功**、**失敗**の３つを、LCDに表示する3文字で送ります。Arduino側ではこれを受信したときに、保持したバッファからブランチ名と、ビルド状況をLCDに表示します。

### 光り方を指定する用のチャネル
ビルドの成功や失敗で光り方をいろいろ変えたいけど、Arduino側にハードコーディングしてしまうと後で変えるのが大変です。
8byteのメッセージの中で頑張って表現します。
8bit(=1 byte)を次のように分割します。

- 1-2 bit：Green
- 3-4 bit：Blue
- 5-6 bit：Red
- 7-8 bit：光る時間。２進数で (n+1)*250 msec。250msec〜1000msec。

これを繋げて光り方を変えます。
たとえば、黄色で250msで３回点滅させた後、２秒間光らせる場合は、

- 0x3C = 0b00111100 = {表示時間: 250ms, 赤:100%、緑:100%、青:0%}
- 0x00 = 0b00000000 = {表示時間: 250ms, 赤:  0%、緑:  0%、青:0%}
- 0x3C = 0b00111100 = {表示時間: 250ms, 赤:100%、緑:100%、青:0%}
- 0x00 = 0b00000000 = {表示時間: 250ms, 赤:  0%、緑:  0%、青:0%}
- 0x3C = 0b00111100 = {表示時間: 250ms, 赤:100%、緑:100%、青:0%}
- 0x00 = 0b00000000 = {表示時間: 250ms, 赤:  0%、緑:  0%、青:0%}
- 0xFC = 0b11111100 = {表示時間:1000ms, 赤:100%、緑:100%、青:0%}
- 0xFC = 0b11111100 = {表示時間:1000ms, 赤:100%、緑:100%、青:0%}

であるので、これを連結して "3C003C003C00FCFC" の文字列で送ります。
[この辺りのコード](https://github.com/cattaka/CiNotifier/blob/9682e6527e3c78939746cbf8cffaa3ed793b6b22/CloudFunctions/index.js#L4-L37)がそれになります。


### おわりに
ビルド時間を待つのは退屈なものです。
このデバイスがあればビルド時間を待つ時間も退屈しなくなるでしょう。
なにせゴーファーは可愛いですから。
それでは皆さん、良いビルドを。