0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Doorbellが鳴ったらSlack通知するMVPを作ったら、仕様の沼にハマった話

0
Last updated at Posted at 2026-09-28

はじめに

Uadd2728という会社でアルバイトをしている @Tomo-2728 です。
業務の一環として、「玄関のGoogle Nest Doorbell(第3世代)が鳴ったら、Slackに『来客がありました』と通知する」というシンプルなシステムを作成しました。

※本記事では、Nest固有の連携部分に絞って解説します。

TL;DR

  • Nestの「本物のチャイムイベント」を外部で受け取るには、自前Webhookだけでは無理で、公式の SDM API + Cloud Pub/Sub を通すのが必須でした。
  • 認証・組織ポリシー・重複通知・7日で切れる認可…と沼だらけ。ハマりどころと解決策をまとめました。

作ったもの(MVP)

要件は非常にシンプルです。

  1. 来客がピンポンを押す。
  2. 指定したSlackチャンネルに「来客がありました」と自動で投稿される。

インターホンの音には気づかなくてもSlackの通知には気づく、そんな人向けに開発しました。

スクリーンショット 2026-09-15 13.51.25.png

今回はMVP(Minimum Viable Product)として、「ステータスを変える」「画像も一緒に送る」などの追加機能はPhase 2として封印し、まずは「鳴ったら通知」を完成させることを最優先にしました。

技術スタック

  • 言語/FW: Python 3.13 / [FastAPI
  • 通信: httpx
  • インフラ/API: Google Smart Device Management API(SDM API) / Cloud Pub/Sub / Cloud Run(OIDC認証)
  • 通知先: Slack Incoming Webhook

当初は「自前でWebhookを立ててSlackに流すだけ」と考えていましたが、Google Nestの「本物のチャイムイベント」を外部で受け取るには、公式のSDM APIを通すしかないことが分かりました。

システムの全体像:どこで何が動くのか

コードに入る前に、まず「登場人物がそれぞれどこで動いているのか」を掴んでおくと、後がぐっと楽になります。私自身、ここが最初モヤっとしていました。

architecture_vertical.png

実際のデータの流れはこうです。

  1. ドアベルが押される → SDM がイベントを Pub/Sub トピックに publish
  2. Pub/Sub サブスクが relay の POST /sdm/pubsub に push(後述のOIDCで認証)
  3. relay が中身(base64)をデコードし、「ドアベルのチャイムか?」を判定
  4. チャイムなら Slack Incoming Webhook に {"text": "来客がありました"} をPOST

relay がやっているのは「受けて・見分けて・投げる」だけ。とても薄い中継役です。

開発の事前準備

同じシステムを開発するにあたり、公式ドキュメントから読み取りづらい「事前準備の罠」として、以下の条件を満たしている必要があります。

  • Google アカウント: Google Workspace等の組織アカウントではなく、個人の @gmail.com アカウントが必須です。
  • Device Access Console の登録: 登録時に一度きりの $5 の課金 が必要です。
  • 権限: Google Cloudのプロジェクトオーナーである必要はなく、
    「Google Homeの管理者」であれば認可(OAuth)を通すことが可能です。

Claude Codeで活用した機能

今回のAI開発では、単にコードを書かせるだけでなく、以下の機能をフル活用しました。(こちらのZenn記事を参考にさせていただきました)

実践でハマった実装の沼と解決策

沼1:1回のピンポンでSlack通知が3〜4回来る

今回いちばんの難所でした。実機で1回しか押していないのに、Slackに複数回通知が来ます。

【解決策】
公式ドキュメントを精読し、SDMのイベントには eventThreadState(STARTED / UPDATED / ENDED)という仕様があることを発見しました。
1回の押下でも「検知の開始・画像の更新・終了」として複数回データが送られてくるのが正常な挙動でした。実装側で最初の一報である STARTED のものだけを処理し、重複を排除することで無事解決しました。

実装コード例
# STARTED(最初の一報)だけ通知。UPDATED/ENDED は同じ押下の続報なので無視する
_NOTIFIABLE_THREAD_STATES = (None, "STARTED")

def is_doorbell_chime(sdm_event: dict) -> bool:
    events = sdm_event.get("resourceUpdate", {}).get("events", {})
    if DOORBELL_CHIME_EVENT not in events:
        return False
    return sdm_event.get("eventThreadState") in _NOTIFIABLE_THREAD_STATES

沼2:動いた!と思ったら、7日後に通知が止まる(OAuth「テスト中」の罠)

デプロイまで終えて「完成!」と思った1週間後、ぱたっと通知が来なくなりました。実機で押しても無反応。ログを追うと、SDMからのイベント自体が届いていません。原因はOAuthアプリの「公開ステータス」でした。

oauth.png

OAuthアプリが 「テスト中(Testing)」 のままだと、Googleの仕様で 認可(リフレッシュトークン)が7日で失効します。つまり「テスト中」で運用している限り、7日ごとに手動で再認可しないと通知が止まるのです。

【解決策】:OAuthアプリを「本番公開(In production)」に切り替える。
これで認可が失効しなくなり、通知が止まらなくなりました。

これからの展望(Phase 2)

MVPは完成し、現在は Cloud Run 上で OIDC 認証を挟んだ構成により常時稼働しています。次に取り組みたいのは「画像付き通知」です。実は前述の eventThreadState の ENDED イベントにはカメラ画像の情報が含まれているため、これを利用する想定です。

おわりに

ピンポンをSlackに流すだけの小さな仕組みですが、認証・課金・テスト・責務分離など、学びの多いプロジェクトになりました。ここまで読んでいただきありがとうございました!

【PR】新潟で一緒に働きませんか?

私がアルバイトをしている Uadd2728では、AI技術や新しい開発手法に興味があるメンバーを募集しています!
現在は新潟で、対面で一緒に働ける方を優先して採用中です。
少しでも気になった方は、ぜひ採用ページを覗いてみてください。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?