
リビングのWindows PCは、テレビをディスプレイとして使っている。テレビには約2時間操作しないと自動で電源が切れる機能があり、寝落ちしたときには便利だ。
ただ、まだ見ているときまでリモコンを探して操作するのは面倒だった。そこで、SwitchBotに登録してある「入力切り替え」シーンを、Windows 11のタスクバーからワンクリックで実行できるようにした。
この記事では、SwitchBot OpenAPIを初めて使う人でも再現できるように、認証情報の作り方、接続確認、Scene IDの調べ方、シーン実行、タスクバーへの固定まで順番に説明する。
WindowsのタスクバーからSwitchBotを操作する仕組み
今回作るのは、Windows 11のタスクバーに置いたボタンからSwitchBotの手動シーンを実行する仕組みだ。最終的な流れは次のようになる。
Windows 11のタスクバー
↓
ショートカット
↓
VBS
↓
PowerShell
↓
SwitchBot OpenAPI v1.1
↓
SwitchBotの「入力切り替え」シーン
↓
Hub Miniからテレビへ赤外線送信
↓
テレビが操作を認識して無操作タイマー延長
MacではSwitchBotアプリから操作できるが、Windowsでは同じ感覚で使えるSwitchBotアプリが見当たらなかった。そこで今回は、WindowsのPowerShellからSwitchBot OpenAPIを呼び出すことにした。
テレビへ直接コマンドを送るのではなく、SwitchBotアプリで作成済みの手動シーンを呼び出す。Windows側で指定するScene IDを変えれば、テレビ電源、照明、エアコン、カーテンなど別のシーンにも応用できる。
SwitchBot APIをWindowsから使う準備
ここから実際の作業へ進む。最初にSwitchBotアプリでTokenとClient Secretを取得し、PowerShellで署名を作ってAPIへ接続できる状態にする。
SwitchBotで開発者向けオプションを有効にする
スマホのSwitchBotアプリを開き、次の順番で進む。
プロフィール
→ 設定(Preferences)
→ アプリバージョン
→ バージョン表示を複数回タップ
→ 開発者向けオプション
SwitchBot公式ヘルプでも、バージョン表示を複数回タップしてDeveloper Optionsを表示する手順が案内されている。表示された画面からTokenとClient Secretを控える。

TokenとClient Secretは、SwitchBotアカウントへAPIからアクセスするための秘密情報だ。パスワードと同じように扱い、ブログ、SNS、スクリーンショット、共有するスクリプト、公開リポジトリへ実値を載せない。
今回の素材には秘密情報を隠した開発者向けオプション画面がなかったため、その画面は掲載していない。画面を撮る場合は、TokenとClient Secretを完全に隠してから使う必要がある。
PowerShellでSwitchBot APIの認証情報を作る
SwitchBot OpenAPI v1.1は、Tokenをヘッダーへ入れるだけでは認証できない。リクエストごとに、次の3つをつなげた文字列を作る。
Token + 現在時刻(13桁のミリ秒Unix timestamp)+ nonce
nonceはリクエストごとに作るランダムな識別子だ。この連結文字列を、Client Secretを鍵にしてHMAC-SHA256で署名し、Base64へ変換する。
PowerShellでは、次のコードで認証用ヘッダーを作れる。
$token = "ここに自分のToken"
$secret = "ここに自分のClient Secret"
$nonce = [guid]::NewGuid().ToString()
$t = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds().ToString()
$data = $token + $t + $nonce
$hmac = New-Object System.Security.Cryptography.HMACSHA256
$hmac.Key = [Text.Encoding]::UTF8.GetBytes($secret)
$hash = $hmac.ComputeHash([Text.Encoding]::UTF8.GetBytes($data))
$sign = [Convert]::ToBase64String($hash)
$headers = @{
Authorization = $token
sign = $sign
nonce = $nonce
t = $t
}
最初の2行だけを、自分のTokenとClient Secretへ置き換える。コードは現在時刻とnonceを自動生成し、APIへ送るAuthorization、sign、nonce、tの4項目を$headersへまとめている。
SwitchBot API v1.1の公式ドキュメントにも、Token・時刻・nonceの連結とHMAC-SHA256署名が示されている。
まずデバイス一覧を取得してAPI接続を確認する
いきなりシーンを実行せず、最初にデバイス一覧を取得して認証が通るか確認した。
上の認証コードをPowerShellへ入力した後、次を実行する。
$devices = Invoke-RestMethod `
-Uri "https://api.switch-bot.com/v1.1/devices" `
-Method GET `
-Headers $headers
$devices | ConvertTo-Json -Depth 10
このコードは、SwitchBotアカウントに登録されているデバイス一覧を取得して、内容を読みやすいJSON形式で表示する。今回の環境ではPlug Mini、Bot、カーテンなどが一覧に出て、statusCode 100とsuccessを確認できた。
この一覧を取得できれば、Token、Client Secret、時刻、nonce、署名を使った認証は正常に動いている。ここで401やUnauthorizedになる場合は、先へ進む前にToken、Client Secret、署名コードを見直す。
デバイス一覧の実スクリーンショットは今回の素材に含まれていなかったため、本文の成功条件を基準に確認してほしい。
SwitchBotのシーン一覧からScene IDを調べる
API接続を確認できたら、次は手動シーンの一覧を取得する。認証ヘッダーを作り直してから、次を実行する。
$nonce = [guid]::NewGuid().ToString()
$t = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds().ToString()
$data = $token + $t + $nonce
$hmac = New-Object System.Security.Cryptography.HMACSHA256
$hmac.Key = [Text.Encoding]::UTF8.GetBytes($secret)
$sign = [Convert]::ToBase64String(
$hmac.ComputeHash([Text.Encoding]::UTF8.GetBytes($data))
)
$headers = @{
Authorization = $token
sign = $sign
nonce = $nonce
t = $t
}
$scenes = Invoke-RestMethod `
-Uri "https://api.switch-bot.com/v1.1/scenes" `
-Method GET `
-Headers $headers
$scenes | ConvertTo-Json -Depth 10
現在時刻とnonceはリクエストごとに新しくするため、シーン一覧を取得する前にも署名を作り直している。
今回の環境では「テレビ電源」「入力切り替え」「カーテン閉める」「カーテン開ける」など、SwitchBotアプリで作成済みのシーンが取得できた。

公開用画像ではScene IDを完全に隠している。自分のPowerShell画面ではsceneNameが「入力切り替え」になっている項目を探し、その項目のsceneIdを控える。Scene IDはユーザーごと・シーンごとに違うため、他人の記事に載っているIDをコピーしても動かない。
PowerShellからSwitchBotのシーンを実行する
認証とScene IDの確認ができたので、次はPowerShellから「入力切り替え」シーンをPOSTで実行する。
Scene IDを指定してシーンを実行する
次のコードの3か所を、自分のToken、Client Secret、Scene IDへ置き換える。
$token = "ここに自分のToken"
$secret = "ここに自分のClient Secret"
$sceneId = "ここに入力切り替えのScene ID"
$nonce = [guid]::NewGuid().ToString()
$t = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds().ToString()
$data = $token + $t + $nonce
$hmac = New-Object System.Security.Cryptography.HMACSHA256
$hmac.Key = [Text.Encoding]::UTF8.GetBytes($secret)
$hash = $hmac.ComputeHash([Text.Encoding]::UTF8.GetBytes($data))
$sign = [Convert]::ToBase64String($hash)
$headers = @{
Authorization = $token
sign = $sign
nonce = $nonce
t = $t
}
Invoke-RestMethod `
-Uri "https://api.switch-bot.com/v1.1/scenes/$sceneId/execute" `
-Method POST `
-Headers $headers `
-ContentType "application/json; charset=utf8" `
-Body "{}"
このコードは、実行時に新しい署名を作り、POST /v1.1/scenes/{sceneId}/executeへ空のJSON本文を送る。$sceneIdへ入れた手動シーンが、SwitchBotアプリから押したときと同じように実行される。
415 Unsupported Media Typeで一度失敗した
最初は、GETでデバイス一覧とシーン一覧を取得できたのに、POSTでシーンを実行するところだけ415 Unsupported Media Typeになった。

認証が通っていても、POSTするデータの形式がサーバーの想定と違えば415になる。今回は次の2行が不足していた。
-ContentType "application/json; charset=utf8" `
-Body "{}"
公式仕様でもPOSTのContent-Typeはapplication/json; charset=utf8とされている。上の2行を追加し、JSONを送るリクエストだと明示して再実行した。
statusCode 100 / successで動作確認
修正後はstatusCode 100とsuccessが返った。

この表示と同時に、実際のテレビで入力切り替えが動作した。ここで初めて、SwitchBotアプリを開かなくてもWindowsからシーンを実行できるところまで確認できた。
もしstatusCode 100なのに実機が動かない場合は、API認証よりもSwitchBotアプリ側のシーン内容やHub Miniからテレビへの赤外線到達を確認する段階になる。
毎回PowerShellを開かなくても実行できるようにする
APIの動作確認が終わったので、ここからはコードを普段使えるボタンにする。
動作確認したコードをps1ファイルに保存する
成功したシーン実行コードを、tv-input.ps1という名前で保存した。保存先は読者の環境ごとに違うので、自分が管理しやすいフォルダでよい。

このファイルにはTokenとClient Secretが入る。共有や公開をせず、OneDriveやGitなど意図せず同期・公開される場所へ置く場合も公開範囲を確認したい。
VBSを使ってPowerShell画面を非表示にする
ps1をショートカットから実行すると、PowerShellの黒い画面が表示される。普段使いでは邪魔なので、VBSからPowerShellを非表示で起動する構成にした。
tv-input.ps1と同じフォルダへ、次の内容をtv-input.vbsとして保存する。
Set shell = CreateObject("WScript.Shell")
shell.CurrentDirectory = CreateObject("Scripting.FileSystemObject").GetParentFolderName(WScript.ScriptFullName)
cmd = "powershell.exe -NoProfile -ExecutionPolicy Bypass -File .\tv-input.ps1"
shell.Run cmd, 0, False
shell.Runの第2引数を0にすることで、PowerShell画面を表示せずに実行する。Falseは処理の終了をVBSが待たない指定だ。
ExecutionPolicy Bypassはこの呼び出しだけに適用される。入手元不明のスクリプトを無条件で動かすためではなく、自分で内容を確認して作成したファイルだけを対象にする。
日本語フォルダ名で文字化けしてハマった
当初は、次のような日本語を含む絶対パスをVBSからPowerShellへ渡していた。
C:\Users\...\Documents\設定\SwitchBot\tv-input.ps1
ところが「設定」の部分が文字化けし、PowerShellがps1を見つけられなかった。
元のスクリーンショットにはWindowsユーザー名と個人パスが写っているため、公開記事では使用していない。最終的にはVBS自身が置かれているフォルダをCurrentDirectoryへ設定し、コード上の.\tv-input.ps1を相対パスとして呼ぶ形で解決した。
上に掲載したVBSコードが修正後の完成版だ。今後スクリプトや設定ファイルを置くフォルダは、最初から英数字だけの名前にすると文字コード由来のトラブルを避けやすい。
SwitchBotボタンをWindows 11のタスクバーへ配置する
ps1とVBSが動いたら、最後にショートカットを作ってタスクバーへ固定する。
VBSを実行するショートカットを作る
tv-input.vbsを右クリックし、ショートカットを作成する。今回はショートカット名を「テレビ延長」にしたが、読者の環境では「テレビ操作」など分かりやすい名前でよい。
ショートカットをダブルクリックし、PowerShell画面を出さずに入力切り替えが動くことを確認する。ここで動かなければ、タスクバーへ固定する前にVBSとps1が同じフォルダにあるか確認する。
テレビのアイコンへ変更する
ショートカットのプロパティから「アイコンの変更」を開く。Windows標準のC:\Windows\System32\imageres.dllには、テレビやモニターに見えるアイコンが入っている。

アイコン変更は必須ではないが、タスクバー上で何のボタンか分かりやすくなる。
タスクバーへピン留めする
作成したショートカットを右クリックし、「タスク バーにピン留めする」を選ぶ。

これで、タスクバーのテレビアイコンを1回クリックすると、VBS、PowerShell、SwitchBot APIを経由して「入力切り替え」シーンまで自動で実行される。
タスクバーから1クリックでテレビを延長できるようになった
リビングPCはテレビをモニターとして使っている。テレビは約2時間無操作だと自動で電源が切れる。寝落ちしたときには便利なので、この機能自体は無効にしたくなかった。
一方、まだ見ているときはリモコンを探して何か操作する必要があり、それが面倒だった。
今回のボタンを押すとSwitchBot Hub Miniから入力切り替えの赤外線が送られ、テレビが「操作された」と認識する。そのため、無操作タイマーを延長できた。

左から2番目のモニター風アイコンが今回追加したボタンだ。PCを操作している流れのままタスクバーを1回押すだけなので、当初の目的を達成できた。
リビングPC自体をAlexaから起動する仕組みも別記事で試している。テレビ操作だけでなく、PCの電源投入まで声で行いたい場合はこちらも参考になる。
今後はエアコンや照明もWindowsから操作したい
今回の仕組みは「入力切り替え」専用ではない。$sceneIdを別の手動シーンのIDへ変えれば、テレビ電源、エアコン、照明、カーテンなどにも応用できる。
今後はよく使う操作をWindows側へ追加したい。ただし、数十個のボタンをそのままタスクバーへ並べると使いにくい。
数が増えたら、テレビ、エアコン、照明、カーテンをまとめたSwitchBot用ランチャーやメニューを作り、タスクバーには入口を1個だけ置く方法も検討している。これは今回の記事では実装せず、第2弾の課題にする。





