この記事は、CircleCI Advent Calendar 2022 12日目の記事です。
さて、我が家では一部スマートホーム化が進んでいます。照明のオンオフ、気温や湿度の管理、人の出入りの監視などです。音声やスマホアプリから操作しているので、現在の状態や、なぜそうしたのかというエビデンスがどこにも残っていません。誰が照明をつけたのか、いつからついているのか、消していいのかの判断に困るわけです。これらの問題を解決するためにInfrastructure as Code(IaC)を使用して、コードでインフラの状態を管理していきたいと思います。
とりあえず簡単なところで照明のスイッチからIaC化していきたいと思います。
やりたいこと
GitHubにコードをPush → CircleCIがAPIをキック → 照明オンオフ
必要なもの
- SwitchBot Bot
- GitHubリポジトリ
- CircleCIのアカウント
SwitchBot Botの設定
SwitchBotはトークンとシークレットがあれば、API経由で操作することができます。
Getting Startedの手順に従ってトークンとシークレットが取得できました。以下が実際に行った手順
- SwitbhBot Appをダウンロードし、お手持ちのスマートフォンにインストールしてください。
- SwitchBotアカウントと作成し、ログインしてください。
- アプリを開いて、プロフィール > 設定と移動し、「アプリバージョン」を10回タップしてください。
- 「開発者向けオプション」が出てくるので、そこをタップするとトークンとクライアントシークレットが表示されます。メモしておいてください。
操作対象のデバイスIDを取得します。
token='メモしたトークン' secret='メモしたクライアントシークレット' t=$(date +%s%3N) nonce=$(uuidgen) sign=$(echo -n "$token$t$nonce" | openssl dgst -binary -sha256 -hmac "$secret" | base64) curl -Ss -H "Authorization: $token" -H "t: $t" -H "nonce: $nonce" -H "sign: $sign" https://api.switch-bot.com/v1.1/devices
以下のようなJSON文字列が返ってくるので、操作対象のdeviceIdをメモ。
{
"statusCode": 100,
"body": {
"deviceList": [
{
"deviceId": "XXXXXXXXXXXX",
"deviceName": "Device 1",
"deviceType": "Hub Mini",
"hubDeviceId": "000000000000"
},
{
"deviceId": "XXXXXXXXXXXX",
"deviceName": "SwitchBot Bot",
"deviceType": "Bot",
"enableCloudService": true,
"hubDeviceId": "XXXXXXXXXXXX"
},
...
]
},
"message": "success"
}
GitHubの設定
適当なリポジトリを用意して手元にClone。
CircleCIのワークフローは以下のようにしました。.circleci/config.ymlに保存します。
version: 2.1
jobs:
generate-sign:
docker:
- image: cimg/base:2022.11
working_directory: ~/workspace
steps:
- run: |
t=$(date +%s%3N)
nonce=$(< /proc/sys/kernel/random/uuid)
sign=$(echo -n "$TOKEN$t$nonce" | openssl dgst -binary -sha256 -hmac "$SECRET" | base64)
echo "export T=$t" >> sign-output
echo "export NONCE=$nonce" >> sign-output
echo "export SIGN=$sign" >> sign-output
- persist_to_workspace:
root: ~/workspace
paths:
- sign-output
bot-action:
docker:
- image: cimg/base:2022.11
working_directory: ~/workspace
steps:
- checkout
- attach_workspace:
at: ~/workspace
- run: |
source ./bot.conf
source ./sign-output
curl -X POST \
-H "Content-Type: application/json; charset=utf8" \
-H "Authorization: $TOKEN" \
-H "t: $T" \
-H "sign: $SIGN" \
-H "nonce: $NONCE" \
-d '{"command": "'$command'", "paramter": "default", "commandType": "default"}' \
"https://api.switch-bot.com/v1.1/devices/$BOT_DEVICE_ID/commands"
workflows:
version: 2
bot-action:
jobs:
- generate-sign
- bot-action:
requires:
- generate-sign
ジョブを簡単に説明すると、generate-signというジョブでAPIの認証情報を生成しています。認証情報はsign-outputというファイルに保存して、bot-action側でsourceすることで認証情報の受け渡しを行なっています。
そのうちカーテンとか開けたくなるかもしれないので、認証情報生成のジョブは分けておきました。
bot-actionではsign-output以外にもリポジトリに含まれるbot.confというファイルをsourceしています。これはbot-actionで実行するコマンドを指定します。
command=turnOn # command=turnOff # command=press
bot.confの中身はbashが解釈できる変数である必要があるので、=の前後にはスペースを入れないでください。指定できるコマンドは以下で確認できます。
ここまできたら.circleci/config.ymlとbot.confをGitHubにPushしておきます。
CircleCIの設定
GitHubと連携するのでGitHubアカウントでCircleCIにログインしました。
GitHubと連携するとGitHubの設定で作成したリポジトリが見えると思います。「Set Up Project」から「Fastest:Use the .circleci/config.yml in my repo」を選択し、「From which branch」に「main」といれて、セットアップを完了します。
連携が完了するといきなりワークフローが動き出しますが、CircleCIに環境変数を設定していないのでコケますね。「Project Settings」を開くと左メニューに「Environment Variables」というのがあるので、そこから環境変数を設定していきます。
「Add Environment Variable」をポチると環境変数を追加していけるので以下の表の通り3つ環境変数を作っていきます。
| Name | Value |
|---|---|
| TOKEN | メモしたトークン |
| SECRET | メモしたクライアントシークレット |
| BOT_DEVICE_ID | メモしたdeviceId |
FailedしたジョブをRerunしてあげると完走します。
実際に動いてる動画は以下より
まとめ
自宅のインフラ環境をIaCで管理できるようになりました。こんな感じでエビデンスを残すことができます。

Pull Requestを利用するのも面白いかもしれないですね。
画像を見てお気づきかもしれませんが、照明を消したログがありませんね?つい癖で手作業してしまいました。こうなるとリポジトリの状態と照明の状態が狂ってしまうので気をつけなければいけません。IaCあるあるだと思います。こうなった場合は、コードを変更するわけにはいかないのでgit commit --allow-emptyで変更のないままCommitしておきます。
