(本サイトは、アフィリエイト広告を利用しています)

SwitchBot APIのWebhookでホームオートメーションをより賢く スマートホームでIoTをもっと活用するために

IoT・スマートホーム

筆者テック大家さんは「SwtichBotの推し活」をしているようなもの。

時々そんな風に感じる今日このごろ。みなさま、いかがお過ごしでしょうか。

推し活の甲斐あってか(!)当ブログ「テック大家さん」の最近の人気記事もSwtichBotのWeb API の以下の記事になっているようです(2024年6月末現在)。

ご覧頂いているみなさま、どうもありがとうございます。

SwtichBot社は、スマートホームをよりスマートにするために、彼らの製品に対するWeb API の仕様を公開しています。プログラマーが使う機能です。これによりプログラマーは、スマートホームを賢いものにシステム構築出るのです。

前回の記事では、このSwtichbot Web APIについて概要を述べました。彼らが公開しているWeb APIの機能を理解し、それを使うとSwitchBot機器に対してどのような操作ができるのか。そんな内容でWeb APIの仕様全体を網羅的に説明した記事になっています。

今日の記事は、前回の記事の中にも登場したWebhookについて、より詳しく見ていきます。SwitchBot Web APIのなかでもWebhookはちょっと独特です。インターネット技術としての「Webhook」を理解している方は、SwitchBot Web API に登場するWebhoookの使い道に関してピンと来るかも知れません。

一方、あまり詳しくない方はWeb APIの仕様書を見てもどのように使えばいいかわからないでしょう。そんなWebhookに詳しくないあなたにお届けします。SwitchBot Web API のWebhookを集中的に解説する内容になっております。

それでは、行ってみよう!

SwtichBot製品群について、より詳しく知りたい方は以下の記事も合わせてご覧下さい。

Webhookとは?

ここでは手始めに「Webhook」という技術を概念的に理解しておきましょう。

一般に、Web API (REST APIなど)を公開しているサービスがあった時に、プログラマーはそれを使った機能を実装するでしょう。そのサービスが何か有益な情報を提供しており、それを利用したアプリを開発する、といったシナリオです。

具体的な例で考えましょう。天気予報の情報を提供するWeb APIがあって、プログラマーは、明日の天気の情報を表示するアプリを作っていたとします。

天気予報はサーバーにあるからアプリはHTTPSのクライアント機能をつかってサーバーから天気情報を取得することになります。

ところで、明日の天気予報は、現在の天気の状態によって変わることがありますね。朝方明日の天気予報を確認すると「晴れ」予報だった。でも、同じ日の夕方確認すると、明日の天気予報は「晴れのち雨」になっている、なんてこともありえます。

そこでプログラマーは、明日の天気予報が変更になった場合はアプリの表示を更新しようと考えます。ただし、明日の天気予報がいつ変わるかわかりません

ならば、とプログラマーはWeb APIを定期的に呼び出すことにします。例えば、1分に一度Web API を呼び出してつねにその時の最新情報をアプリに表示しようと考えたわけです。

このようなやり方を一般的に「ポーリング」(Polling)と言います。

機能的にはポーリングは動作します。

ですが、1分毎、という時間間隔は適切でしょうか。

サーバー側で状態が変わったとしても、最悪1分間は古い情報がアプリに表示されることになります。天気予報程度ならそれでも良いでしょう。でも、もっとリアルタイム性が求められるような状況もありえます。よりリアルタイム性を求めると、サーバーを呼び出す頻度を上げることになります。1秒とか、0.5秒など、場合によってはそのような頻度でサーバーを呼び出したくなるケースもあるのではないでしょうか。

ところがポーリングを行っても、多くの場合同じデータが返ってくる可能性もあります。天気予報などは1日になんども更新されるような情報ではありませんね。とすると、ほとんどの呼び出しで中身が変わらない情報を取得することになります。変更がないにも関わらず何度もサーバーを呼び出すわけです。この行為は、かなり無駄ですよね。

モバイルアプリならば、ユーザーはパケ代も余計にかかるでしょう。Web API を提供するサーバー側にしても、無駄な応答のたびにCPU パワーを使います。昨今の従量制のクラウドサービスを利用しているサーバーならばその分支払いが増える。経済的にもこのアプローチは非効率なのです。

これがポーリングの問題点です。

そこで考えられたのがWebhookという技術です。

サーバー上でなにか情報の更新があった場合に、変更のタイミングでサーバー側からクライアントに教えてあげましょう、ということです。

これなら、アプリはポーリングせずとも、待っていれば変更をサーバーのほうから教えてくれます。無駄なAPI呼び出しを実装する必要はなくなるはずです。これがWebhookでやりたいことです。

めでたしめでたし…と言いたいところですが、ことはそんなに簡単ではありませんでした。

Webhookという名前にある「Web」というのがクセモノです。

Webhookにおける通知は「Web」、つまり、HTTP/HTTPSで行うという発想なのです。ということは、通知を受ける方(クライアントアプリ)がWebサーバーの機能を持っていなければならないわけです。別の言い方をすると、通知のための通信においてはクライアント・サーバーの役割が逆になってしまうのです。

これを実現するのはちょっと敷居が高い話になります。解決案の一つは後述します。

SwitchBot Webhookでできること

前章の内容で、Webhookの一般的な仕組みは理解できたはずです。ここでは、SwitchBotのWeb APIで定義されているWebhookについて見ていきます。

SwitchBotのWebhookについては2段階で使用します。

  • Configuration
  • 通知待ち

Configuration として、SwtichBotクラウドに対して、どのURLで通知を受け取るかを設定する必要があります。Web API 仕様では、Configure Webhook の項で説明されています。

以下のようなエンドポイントに対して、

POST https://api.switch-bot.com/v1.1/webhook/setupWebhook

以下のようなJSONをbodyに設定して呼び出します。すると、これ以降、SwtichBotの機器でなにか変化があった場合に、指定したURL(この例では、https://my-switchbot-client-example.com/webhook)が呼び出される、という仕組みです。

{
    "action":"setupWebhook",
    "url": "https://my-switchbot-client-example.com/webhook",
    "deviceList":"ALL"
}

一度、WebhookのURLをSwitchBotクラウドに登録してしまえば、あとは通知待ちの状態になります。

SwitchBot機器になにか変化があるとSwitchBotクラウドは、Webhookで登録したURLを呼び出します。上の例の場合は、"https://my-switchbot-client-example.com/webhook"が呼び出されます。

このとき、my-switchbot-client-example.comのサーバーは、Web API 仕様書の Receive events from webhookにある機器の応じた通知情報をJSONで受け取ることになります。

例えば、SwitchBotの開閉センサーの場合はどうでしょう。

ドアの開閉操作があった場合にセンサーが検知し機器の内部状態に変化があったケースを考えます。この場合、my-switchbot-client-example.comサーバーは、以下のようなJSONがbodyに含まれるようなHTTPSリクエストを受け取るとことになります。

{
    "eventType": "changeReport",
    "eventVersion": "1",
    "context": {
        "deviceType": "WoContact",
        "deviceMac": DEVICE_MAC_ADDR,
        "detectionState": "NOT_DETECTED",
        "doorMode":"OUT_DOOR",
        "brightness": "dim",
        "openState": "open",
        "timeOfSample": 123456789
    }
}

SwitchBot開閉センサーはドアの開閉状態(openState)以外にも、明るさ(brigtness)や人の動きも(detectionState)も検出します。そのため、上記のJSONではそれらのフィールドが含まれているわけです。

図にすると以下のようなイメージです。

実際に使ってみる

さて、前章までの説明でわかるように、Webhookを使ってSwitchBotの機器からの通知を受けようとするとサーバーの実装が必要になります。

しかし、モバイルアプリやWebアプリのようにそれ自身がサーバーになれない、または、サーバーを実装したとしてもネットワークの接続方法により、インターネットからそのサーバーへの接続が達成できない、という可能性があります。

とくに、モバイルネットワークやホームネットワークにアプリがつながっている場合、そのネットワークからサーバーへの到達は可能です。しかし、逆向きの接続、つまり、外部のネットワーク(インターネット)からローカルネットワークのサーバーに接続するためにはNATの設定などが必要となり現実的ではありません。(NATについては、当ブログ記事「建物内ネットワークにサーバーを立てる」でも解説しています)。

そこで筆者は、WebアプリなどのクライアントアプリでもSwitchBotのWebhookを利用した通知を受け取る、ちょっとしたトリックを思いつきました。

それは、FirebaseというGoogleクラウドの仕組みを利用するものです。

Firebase FunctionsでSwtichBotのWebhookを受け取るエンドポイントを作ります。そして、SwitchBotクラウドから受けた通知に含まれるJSONをそのまま、まるっとFirestoreのデータベースに機器毎の情報として登録します。

通知を受けたいクライアント(モバイルでもWebアプリでも構いません)は、Firestoreのクライアントとして、データベースの更新通知を受けるようにするというものです。

全体図は以下のようになります。

以下では、その内容をご紹介します。

Firebase Functionsで”Hook”する

Firebase FunctionsはHTTPSトリガーにより動作するプログラムをサーバーレスで作れるプラットフォームです。サーバープログラム全体をどこかのサーバーにデプロイするのではありません。特定のHTTPSリクエストを処理するための単一のコードのみをGoogleクラウドに置いておくと、リクエストに応じて実行されるという仕組みです。

Firebase Functionsでは、単一コードをデプロイするとその機能に応じたエンドポイント(URL)を作ってくれます。このURLをSwitchBotのWebhookの設定(https://api.switch-bot.com/v1.1/webhook/setupWebhook)で登録しておくのです。これでSwitchBotの機器で何かしらのイベントが発生するたびにFirebase Functionsのコードが呼び出されるようになります。

例えば、以下のようなコードを使います。

少しコードの説明をしましょう。

このコードはTypeScriptで書かれており、Firebase FunctionsのSDKを使っています。

関数「switchbotWebHookHandler」が、SwitchBot Webhookのイベントを受け取るFirebase Functionsの関数です。SwitchBotクラウドは、どの機器のイベントに対しても、SwitchbotWebhookEvent(8行目)およびSwitchbotWebhookContextBase(14行目)で定義されているような形式のJSONを送ってくれます。これは、SwtichBot Web APの仕様(Webhookの項)をみればわかります。

そこでこの情報を元に、機器の機器ID(deviceId)を取り出しています(29行目)。

そして、32行目にあるように、Firestore上で"/Notifies"というデータベースのコレクションの下にデータを書き込みます。このとき、機器ごとのデータが保存されるように、deviceIdをキーにしてSwitchBotクラウドから受け取ったJSONをそのまま書き込むような実装をしています。

Firestore経由で変更を受け取る

上記のように実装すると、SwitchBotのイベントが発生するたびに、Firestoreにデータが書き込まれます。

Firestoreのコンソール画面をみると以下のような感じでデータが書き込まれていることがわかります(deviceId/deviceMacは隠しています)。

Notifiesコレクションの下に機器ごとのドキュメントが保存されるイメージです。

よって、クライアント(例えば、Webアプリ)で以下のように観察したいdeviceIdに対して、変更を受け取ることができます。(FirebaseのJavaScriptのクライアントSDKを使用しています)

onSnapshot(doc(collection(db, 'Notifies'), deviceId), (doc) => {
  if (doc.exists()) {
    const data = doc.data(); // ここで利用する...
  }
});

最後に注意点を一つ。

SwtichBotの製品はすべて単体で動作し、スマホとつながる「スマート」な機器です。ところが、Web APIやここでお話したWebhookを使うためには「ハブ」と呼ばれる商品が必要になります。SwitchBot製品はたいていそれ単体ではインターネットに繋がりません。ハブを介してネットにつなげる仕組みになっています。そのため、Web API のようなネット接続を前提とした機能を使う場合に「ハブ」が必要になるというわけです。

実際に上のような機能をお試しになる場合は、ご注意下さい。

詳しくは、以下の記事も合わせてご覧下さい。

メールマガジンにて本サイト(Tech Landlordテック大家さん)の更新情報をご連絡します。
本サイトのプライバシーポリシーをご確認の上、是非メールアドレスをご登録下さい!


プロフィール

テック大家さん
ソフトエンジニア兼不動産オーナー。
某超有名日本メーカーにおいてソフトウエア開発畑を30年近く勤務。
かつてはWindowsのアプリ開発や、組み込み機器のソフト開発を行う。プロジェクトマネジメント・オフショア開発・要件管理などの経験あり。現在は、個人開発で、JavaScript/TypeScript/React/Express、PHP/Laravel、Firebase、Google cloud、Arduino(C++)などでプログラミングを楽しむ。
サラリーマンの傍ら不動産経営を始め、現在、1棟モノの賃貸4物件を東京・神奈川に所有。夫婦でおよそ20年の賃貸経営の実績。
最近の物件では、入居者向けフリーWiFiなど、テック系の設備はDIYで自ら構築。
海外MBA取得。