0
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

KLab EngineerAdvent Calendar 2023

Day 4

仕事部屋の電灯を操作するキーボードショートカット = Switchbot Bot を Mac の Shortcutsで操る 〜Shortcuts 小ねた 2/2〜

Last updated at Posted at 2023-12-03

3行まとめ

  • Switchbot API を使って Switchbot Bot を操る Mac の "ショートカット" を作った
  • Mac の Shortcuts には WebAPI リクエストを発行するのに必要な機能を備えたアクションが用意されてる
  • Mac の Shortcuts ではアクション間のデータのやり取りに JSON (やリスト)が使えて便利

きっかけ

在宅勤務が日常と化したころから、仕事部屋の環境をこまごまいじってきました。そんな改善ねたの1つに天井のシーリングライト用の壁面スイッチに、Switchbot Botを取り付けた、というのがあります。これは夕方の時間帯のミーティング中などで席を外したくないけど部屋の明かりをつけたいと思うことが度々あったので、取り付けました。
Switchbot Bot はスマホのアプリから操作することができます。なのでアプリをインストールしたスマホが手元にあれば、席をたたずとも部屋の明かりをつけることができるようになりました。けれど、スマホを開いてアプリ立ち上げてアイコンクリックするのって、やっぱちょっと手間なんですよね。特にミーティング中に活発に議論してるときなどは、わずらわしかったりします。
Mac の中から Switchbot Bot を操作できれば、手間が少し減ります。そしてそれがキーボードショートカット一発で済めば手間がすごく減ります。ということで調べてみたところわりあい簡単に実現できました。

How

キーボードショートカットを Mac に仕込むのは、昨日の記事でも使用した Shortcuts を使います。
Switchbot Bot をスマホアプリを使わずに操作するのは、Switchbot が用意してくれている Web API を使えばできそうです。親切にもいくつかの言語のサンプルも用意されています(さすがに AppleScript のサンプルはありませんでした)。この中のどれかの言語のスクリプトを Shortcuts のアクションとして実行できれば、ほとんどコピペで済ませられそうです。
最近の Mac では AppleScript の他に Javascript も標準でサポートしています。なので Sortcuts の中でも Javascript が使えるのですが、それ以外にもシェルスクリプトや Python、Perl も使えます。今回は手慣れていてサンプルコードもある Python3 を使うことにしました。

事前準備

Switchbot Bot は同じ部屋の中からスマホで操作する分には Bluetooth で操作できるので、Switchbot の Hub2 や Hub Mini は不要だったりします。しかしスマートスピーカーなどから操作するためにはインターネットから部屋の中の Switchbot Bot にリーチするために中継してくれる Hub2 か Hub Mini が必要になります。
Switchbot API を使用して Switchbot Bot を操作する上でも、Hub2/ Hub Mini による中継が必要になります。ですので、事前に Hub2/ Hub Mini と Switchbot Bot を接続しておく必要があります。「ボットをハブミニ/ハブ2に接続する方法」に従って準備しておいてください。

To

Switchbot API を通じて Switchbot デバイスを操作するためには

  1. API リクエストを発行する際の認証データ
  2. 操作する対象デバイスのデバイスID

の2つが必要になります。1つ目の認証データに関しては次の Step0 で取得します。2つ目の操作するデバイスのデバイスIDは、Switchbot API を使ってデバイスの一覧を取得しないとわからないので、"ショートカット"を作成する過程で動作テストがてら取得します。

Step0: Switchbot の Web API リクエストに必要なトークンとクライアントシークレットを取得する

Switchbot の Web API にリクエストを送信する上で必要になるトークンとクライアントシークレットを取得します。こちらのページにやり方が掲載されていますので取得し、控えておきます。

Step1: ショートカットを作成して認証データを生成するスクリプトを追加する

今回の “ショートカット” は、昨日の記事で作成したものより少し複雑で、コアの処理を2段階に分けています。1段階目は Web API にリクエストを送信する際に必要な認証データを Python で生成します。そして生成した認証データを使って2段階目で Web API にリクエストを送信します。1段階目で生成した認証データは JSON 形式にして2段階目のアクションに渡します。

ということで早速作成していきます。まずは新しい “ショートカット” を作成し、「シェルスクリプト」のアクションを追加します。「シェル」の部分は「Python3(/usr/bin/python3)」に変更します。

image26.png

ちなみに「シェル」の部分で選択できるインタプリタの候補には /usr/bin/python3 だけではなく HomeBrew でインストールした /usr/local/bin/python3 もリストされていました。ちょっとびっくりです。

コードの部分には以下のコードを入力してください。ほとんど Switchbot API の README.md のサンプルコードのままですが、 print() 文で出力する認証データを JSON 形式に変更してます。
9行目の token と 11行目の secret 変数に入れる値は、Step0 で取得したものに書き換えてください。

import json
import time
import hashlib
import hmac
import base64
import uuid


# open token
token = 'XXXXXXXXXXXXXXXXXXX'
# secret key 
secret = WWWWWWWWWWWWWWWW
nonce = uuid.uuid4()
t = int(round(time.time() * 1000))
string_to_sign = '{}{}{}'.format(token, t, nonce)


string_to_sign = bytes(string_to_sign, 'utf-8')
secret = bytes(secret, 'utf-8')
sign = base64.b64encode(hmac.new(secret, msg=string_to_sign, digestmod=hashlib.sha256).digest())


print(json.dumps({ 
    'Authorization': token,
    't': str(t),
    'sign': str(sign, 'utf-8'),
    'nonce': str(nonce),
}))

一旦ここまでで動作テストをします。結果として↓のように JSON が出力されていれば成功です。

image38.png

Step2: Web API リクエストを発行するアクションを追加する

Step1 で生成した認証データを使って Switchbot API へリクエストを発行するアクションを追加します。
「web」カテゴリの中から「URLの内容を取得」アクションを追加してください。

image19.png

リクエストする Web API のアドレスの設定は一旦おいておいて、先にヘッダの設定をしてしまいます。
「表示を増やす」をクリックして表示される「ヘッダ」をクリックします。

image30.png

Switchbot API にリクエストを送信する上で必要なヘッダを以下のように設定していきます。

キー
Content-Type application/json; charset=utf8 で固定
Authorization Step1 の python スクリプトの実行結果の JSON の Authorization の値
t Step1 の python スクリプトの実行結果の JSON の t の値
sign Step1 の python スクリプトの実行結果の JSON の sign の値
nonce Step1 の python スクリプトの実行結果の JSON の nonce の値

左下の + アイコンをクリックするとヘッダが追加されるので、それぞれキーと値を設定していきます。 python スクリプトの実行結果をヘッダの値に設定するには、値欄でマウスを右クリックして「変数を挿入」→「シェルスクリプトの結果」を選択します。

image3.png

表示されたメニューの中にある「種類」から「辞書」を選択します。

image14.png

「入手」は「辞書」を選択し、「キーの値を取得」にはヘッダのキーと同じ文字列を指定します。つまり例えば「Authorization」ヘッダの値には、「シェルスクリプトの結果」の JSON の中の「Authorization」項の値を使用します。

image36.png

ちょっとめんどくさいですが、すべてのヘッダの設定を済ませます。最終的には以下のようになっていればOKです。

image33.png

Step3: Switchbot Bot のデバイスID を取得する

さて Switchbot Bot を操作するために API リクエストする上では、「どの」 デバイスを操作したいのかを指定する必要があります。Switchbot API ではデバイスIDを使って指定します。なので操作対象の Switchbot Bot のデバイスIDを取得する必要があります。デバイスIDを取得するためには自分のデバイスの一覧を取得する API リクエストをする必要があります。ということで、動作確認がてらデバイスの一覧を取得します。

Step2 で追加した「URLの内容を取得」アクションの上部にある「シェルスクリプトの結果の内容を取得」の「シェルスクリプトの結果」の部分を右クリックして表示されるメニューの中から「消去」を選択します。

image22.png

すると「シェルスクリプトの結果」の部分が「URL」に変わりますので

image32.png

そこをクリックして

https://api.switch-bot.com/v1.1/devices

と入れます。この状態で "ショートカット"を実行してください。すると以下のような警告メッセージが表示されますので、「常に許可」を選択します。

image2.png

問題なくリクエストが受け付けられれば、以下のように Web API の実行結果が返ってきます。

image21.png

これは自分のアカウントに紐づいているデバイスの一覧が JSON 形式でリストされたものです。ちょっと見にくいですが、この中から今回操作したい Switchbot Bot の deviceId を見つけてください。そしてその デバイスID をメモしておきます。

Step4: ショートカットを完成させる

Switchbot Bot を操作するための Web API の URL は以下になります。

https://api.switch-bot.com/v1.1/devices/{deviceId}/commands

{deviceId} の部分は Step3 でメモした Switchbot Bot のデバイスIDに置き換えます。

「URLの内容を取得」アクションに先程設定した https://api.switch-bot.com/v1.1/devices の URLを上記の URL に置き換えます。さらに「方法」を「POST」に変更してください。

image15.png

すると、「本文を要求」という項目が増えて、その下に request body を入力する欄が表示されます。(「JSON」の部分はそのままにしておきます。)

image18.png

Switchbot API のマニュアルの例に従って以下のようにキーと種類と値を設定します。

image29.png

ここでは command の「値」を press にしてますが、壁面スイッチの種類によっては turnOn に変更してください。

この状態で "ショートカット"を実行すると、問題なければ Switchbot Bot が動作するはずです。

動作が確認できたら、Switchbot API のリクエスト結果をデスクトップ通知に表示する部分を追加します。

(昨日の記事を参考にして)「通知を表示」アクションを追加し、「こんにちわ」を右クリックして表示されるメニューの中から「URLの内容」を選択します。

image10.png

「URLの内容」に変わった箇所を、今度は左クリックして表示されるメニューの中の「種類」から「辞書」を選択します。

image5.png

「入手」は「辞書」のままにしておき、下部の「キーの値を取得」の欄に message と入力します。

image6.png

ショートカットを実行すれば、Switchbot API へのリクエスト結果がデスクトップ通知に表示されます。

image1.png

最後に、昨日の記事を参考にしてキーボードショートカットなどを追加すれば、Switchbot Bot を操作するキーボードショートカットは完成です。

まとめ

今回は外部の Web API と連携する "ショートカット" を作成しました。今回の例のように「URLの内容を取得」アクションでは、POSTメソッドが使えたり、送信データに JSON が使えるので、REST 的 Web API との連携が実現できます。またスクリプトアクションを使うことで、標準のアクションだけでは難しいような複雑な計算もでき、連携させたい外部のサービスの仕様にも簡単に合致させられます。
アクション間のデータのやり取りにも JSON を活用することで、複数のデータを効率的にやり取りできました。Shortcuts では JSON だけではなくリストも扱えるので、複雑な処理を実現する下地が揃っています。アイデア次第で色々なことができそうです。

こぼれ話

今回のネタでは扱いませんでしたが、Shortcuts では辞書(JSON)だけでなくリストも扱えます。リスト化されたデータに対して、いわゆる foreach 的な動作をする「各項目を繰り返す」アクションが用意されているので、"ショートカット" の中でデータ処理する上ではリスト化しておくと便利です。
"ショートカット"に追加したスクリプトから処理結果をリストとして次のアクションに渡すことを考えた場合、どういう形に整形して渡せばいいのか分からなかったので少々実験してみたところ、JSON のリストを辞書の値としたものを渡せば良さそうでした。つまり、以下のような JSON です。

{
  "a": [
    "hoge",
    "fuga",
    "foo",
    "bar"
  ]
}

この a 項目の値を「リストから項目を取得」アクションを使って Shortcuts のリストに変換します。

image.png

JSON のリストを辞書の値にして返すのは無駄のように見えるんですが、辞書の値にせずに生の JSON リストをスクリプトから返すと↓のようにエラーになってしまうので、苦肉の策です。

image.png

ちなみに、↑の例では「結果を表示」アクションを使ってシェルスクリプトの実行結果を受け取っていますが、受け取るアクションを何も置かずに、生の JSON リストを返すスクリプトのアクションのみの状態にして "ショートカット" を実行すると↓のようになりました1

image.png

  1. Intel Mac / Mac OS 13.6.1(22G313)/ Shortcuts バージョン6.0(1505.3.1.1)

0
3
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
0
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?