スマートフォンから家電のスイッチを操作できるガジェットがSwitchBotです。
SwitchBot
DelphiのTHTTPClientを使ってSwitchBotをSwitchBot Hub経由で利用しようと思います。
THTTPClientはXE8で実装されましたのでそれ以降のDelphiでお試しください。
最初に用意するもの
- Switchbot
- SwitchBot Hub (Hub miniまたはHub Plus)
- スマートフォンのSwitchBotアプリ
SwithBot HubはHub miniで十分です。違いについては以下のサイトに詳しく書かれています。
【迷っている方必見!】SwitchBot Hub MiniとPlusの違いを比較レビューで紹介
SwitchBotがスマホのアプリからHub経由で利用できるようにします。
設置方法については,以下のサイトが詳しいです。
意外に簡単!Switch Bot(スイッチボット)の設定・設置方法
SwitchBot Hubの設定では,Wifiの設定が必要になります。
SwitchBotをAPI経由で動かすための手順は以下のサイトから学びました。
SwitchBotをHub経由でAPIから操作する
SwitchBotのAPIの利用方法はGitHubに公式サイトがあります。
OpenWonderLabs/SwitchBotAPI - GitHub
認証用トークンの取得
SwitchBotのWeb APIを利用するためには認証用トークンが必要です。スマートフォンのSwitchBotアプリから取得します。
SwitchBotアプリの**設定
を表示し,アプリバージョン
を10回タップすると表示されます。
表示された開発者向けオプション
**で認証用トークンを確認できます。
SwitchBotのクラウドサービスをオンにする
アプリからAPIから操作するために,利用予定のSwitchBotの「クラウドサービス」をオンにします。
SwitchBotアプリで,操作するSwitchBotの**設定
を開いて,クラウドサービス
**をオンにします。
Delphiでアプリケーションを作る
ここからDelphiでの作業になります。
DeviceIDを取得する
Windows VCLアプリケーションを新規作成し,フォームに3つのTButtonとTMemoを貼り付けます。
以下のUnitを保存して,プロジェクトに追加します。
uSwitchbot.pas
unit uSwitchbot;
interface
(*
OpenWonderLabsのSwitchBotのAPIをHub経由で利用する
p_kato 2021/05/17
press以外のコマンドについてはGitHub参照
https://github.com/OpenWonderLabs/SwitchBotAPI
実際の利用方法については
SwitchBotをHub経由でAPIから操作する
https://qiita.com/itouuuuuuuuu/items/874cd992f473f30de45b
が参考になります。
特に,
・認証用トークンの取得
・クラウドサービスをオンにする
が大切です。
*)
function SwitchBotDeviceListGet(AAuthToken:string):string; // AAuthTokenで登録されたデバイスの一覧を返す
function SwitchBotsFromDeviceList(AData:string):string; // DeviceIDGetの返す文字列を解析し,デバイス名=デバイスIDを返す。複数ある場合は複数行を返す
function SwitchBotDeviceStatusString(AAuthToken,ADeviceID:string):string; // ADeviceIDのステータスを返す
function SwitchBotDeviceStatusBool(AAuthToken,ADeviceID:string):boolean; // ADeviceIDのステータスを真偽で返す
function SwitchBotDevicePressString(AAuthToken,ADeviceID:string):string; // ADeviceIDにPressを送る 結果を文字列で受け取る
function SwitchBotDevicePressBool(AAuthToken,ADeviceID:string):boolean; // ADeviceIDの電源が入っているかを返す
implementation
uses
System.Classes, System.SysUtils,
System.Net.URLClient, System.Net.HttpClient,
System.RegularExpressions;
const
SwitchBotURI:string='https://api.switch-bot.com/v1.0/devices'; // SwitchBot API の既定URI
function SwitchBotHeaders(AAuthToken:string):TNetHeaders; // SwitchBot APIで利用するヘッダ
begin
Result := [ TNameValuePair.Create('Content-Type' , 'application/json; charset=utf8'), //
TNameValuePair.Create('Authorization', AAuthToken)];
end;
function SwitchBotDeviceListGet(AAuthToken:string):string; // 登録したデバイスの一覧を返す
var
ResponseContent: TMemoryStream;
HTTPClient:THttpClient;
Headers: TNetHeaders;
st:TStringList;
begin
Result:='';
HTTPClient:=THttpClient.Create;
ResponseContent := TMemoryStream.Create;
st:=TStringList.Create;
try
Headers:=SwitchBotHeaders(AAuthToken);
HTTPClient.Get(SwitchBotURI, ResponseContent,Headers);
st.LoadFromStream(ResponseContent,TEncoding.UTF8);
Result:=st.Text;
finally
st.Free;
ResponseContent.Free;
HTTPClient.Free;
end;
end;
function SwitchBotsFromDeviceList(AData:string):string; // DeviceIDGetの返す文字列を解析し,デバイス名=デバイスIDを返す。複数ある場合は複数行を返す
var
regex: TRegEx;
match: TMatch;
s:string;
begin
regex:=TRegEx.Create('\{"deviceId":"([0-9A-F]+)","deviceName":"([^"]*)","deviceType":"Bot","enableCloudService":true,"hubDeviceId":"([0-9a-fA-F]+)"\}');
match:=regex.Match(AData);
while match.Success do begin
s:= s+match.groups[2].Value+'='+match.groups[1].Value+#13#10;
match := match.NextMatch();
end;
Result:=s;
end;
function SwitchBotDeviceStatusString(AAuthToken,ADeviceID:string):string; // ADeviceIDのステータスを返す
var
HTTPClient:THttpClient;
ResponseContent: TMemoryStream;
Headers: TNetHeaders;
st:TStringList;
begin
Result:='';
HTTPClient:=THttpClient.Create;
ResponseContent := TMemoryStream.Create;
st:=TStringList.Create;
try
Headers:=SwitchBotHeaders(AAuthToken);
HTTPClient.Get(SwitchBotURI+'/'+ADeviceID+'/status', ResponseContent,Headers);
st.LoadFromStream(ResponseContent,TEncoding.UTF8);
Result:=st.Text;
finally
st.Free;
ResponseContent.Free;
HTTPClient.Free;
end;
end;
function SwitchBotDeviceStatusBool(AAuthToken,ADeviceID:string):boolean; // ADeviceIDの電源が入っているかを返す
begin
Result:=pos('"power":"on"',SwitchBotDeviceStatusString(AAuthToken,ADeviceID))<>-1;
end;
// SwitchBotDeviceCommand SwitchBotに命令を送る
procedure BinaryWrite(AStream:TStream;AEncoding:TEncoding;Value:string); // POSTするDataをTStreamに格納する
var
Bytes: TBytes;
begin
Bytes := AEncoding.GetBytes(Value);
AStream.WriteBuffer(Bytes, Length(Bytes));
end;
function SwitchBotDeviceCommand(AAuthToken,ADeviceID,ASource:string):string; // 汎用のコマンド
var
HTTPClient:THttpClient;
ResponseContent: TMemoryStream;
Source: TMemoryStream;
Headers: TNetHeaders;
st:TStringList;
begin
Result:='';
HTTPClient:=THttpClient.Create;
ResponseContent := TMemoryStream.Create;
Source:=TMemoryStream.Create;
BinaryWrite(Source,TEncoding.UTF8,ASource);
Source.Position:=0;
st:=TStringList.Create;
try
Headers:=SwitchBotHeaders(AAuthToken);
HTTPClient.Post(SwitchBotURI+'/'+ADeviceID+'/commands', Source, ResponseContent, Headers);
st.LoadFromStream(ResponseContent,TEncoding.UTF8);
Result:=st.Text;
finally
st.Free;
Source.Free;
ResponseContent.Free;
HTTPClient.Free;
end;
end;
function SwitchBotDevicePressString(AAuthToken,ADeviceID:string):string;
var
r:string;
begin
// BotにPressを送る コマンドについてはGitHub参照 他のコマンドもこの方法で拡張できるはず
Result:=SwitchBotDeviceCommand(AAuthToken,ADeviceID,'{"command":"press","parameter":"default","commandType":"command"}');
end;
const
SwitchBotCommandSuccess='{"statusCode":100,"body":{},"message":"success"}'; // コマンドの成功
function SwitchBotDevicePressBool(AAuthToken,ADeviceID:string):boolean;
var
r:string;
begin
Result:=SwitchBotDevicePressString(AAuthToken,ADeviceID)=SwitchBotCommandSuccess;
end;
end.
そして,フォームのButton1をダブルクリックし,以下のコードを追加します。
implementation
{$R *.dfm}
uses uSwitchBot; // 追加したuSwitchbot.pasを利用を宣言する
const
AuthToken:string='ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ'; // 取得した認証トークンをここに記述する
procedure TForm1.Button1Click(Sender: TObject);
begin
Memo1.Lines.Clear;
Memo1.Lines.Text:=SwitchBotsFromDeviceList(SwitchBotDeviceListGet(AuthToken));
end;
前述のプログラムしButton1をクリックすると,Memo1に**デバイス名=DeviceID
**が表示されます。
取得したDeviceIDのSwitchBotのステータスを取得する
このDeviceIDをコピーしてグローバル定数SwitchBotIDを宣言し,そのステータスを取得できるようにします。
フォームのButton2をダブルクリックし,以下のコードを追加します。
implementation
{$R *.dfm}
uses uSwitchBot; // 追加したuSwitchbot.pasを利用を宣言する
const
AuthToken:string='ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ'; // 取得した認証トークンをここに記述する
SwitchBotID:string='XXXXXXXXXXXXX'; // SwitchBotのDeviceIDをここに記述する
procedure TForm1.Button2Click(Sender: TObject);
begin
Memo1.Lines.Add(SwitchBotDeviceStatusString(AuthToken,SwitchBotID)); // 戻ってきたテキストを表示する
end;
実行してButton2をクリックするとMemo1に,
{"statusCode":100,"body":{"deviceId":"XXXXXXXXXXXX","deviceType":"Bot","hubDeviceId":"XXXXXXXXXXXX","power":"on"},"message":"success"}
が戻ってくるはずです。
なお,SwitchBotの電源が入っているかどうかを調べるためだけなら
if SwitchBotDeviceStatusBool(AuthToken,SwitchBotID) then begin
Memo1.Lines.Add('ON');
end else begin
Memo1.Lines.Add('OFF or NG');
end;
と書くことができます。
SwitchBotでボタンをPressする
では,SwitchBotをPressしましょう。
フォームのButton3をダブルクリックし,以下のコードを追加します。
procedure TForm1.Button3Click(Sender: TObject);
begin
Memo1.Lines.Add(SwitchBotDevicePressString(AuthToken,SwitchBotID));
end;
実行して,Button3をクリックするとMemo1に
{"statusCode":100,"body":{},"message":"success"}
が戻ってくるはずです。
今回はVCLで書きましたが,uSwitchbot.pasではVCL固有のコードを使っていませんので,FMXでも利用できるのではないかと思います。
SwitchBot APIを使うにあたっての注意点
実際に試してみて気になることは以下の通りです。
一日の利用が1000回に制限されている
GitHubのドキュメントに書かれている通り2021/05/18現在で一日の利用回数が1000回に制限されています。
SwitchBotは電池で動作する
電池切れをチェックする方法を見つけることができませんでした。遠隔地にSwitchBotを配置する場合には注意がいると思います。バッテリーの状態はスマホのアプリからは確認できます。
ボタンを押している時間を変えることができない。
スマホのアプリでボタンを押している時間を変更することができますが,APIからは長さを自由に変えることができません。押す時間の長さはスイッチ固有の情報になるようです。
謝辞
SwitchBotのAPIの利用方法について @itouuuuuuuuu 様の記事を参考にしました。手持ちにMacかLinuxがあり,APIの動作確認をまずやりたい場合にはCURLを使うのはありだと思います。
DelphiからAPIを利用するのにTHTTPClientを利用したのですが,なかなかうまくいがず,@pik (Jun HOSOKAWA)様にTwitterでいろいろ教えていただきました。
今回は同期接続で処理を書いていますが,非同期にするともっと使いやすくなるのではないかと思います。
皆様ありがとうございます。