スマートロック SESAME の WEB API が便利だった！

#<b>■はじめに</b>
昨年末の Google Home / Amazon Echo リリースから、私の回りでもおうちハックが盛んで自分も色々遊んでいます。その中でも特に気になっていたのがスマートロック。玄関のカギをスマートにコントロールするアイテムです。

数年前から BLE の普及に合わせて盛り上がってるのは知ってはいましたが、ちょうど良い機会なので、そしてスマートスピーカーを使って音声で玄関を開錠したくて（ひらけゴマで（笑））遅ればせながら導入してみました。

こーゆー製品は知識では知ってはいても実際に日常生活で使ってみないと本当の価値は分かりませんね。
今回実感しました。

ということで・・・・今回は実際に自宅に導入したスマートロック製品 SESAME の簡単なご紹介と、複数の方からご要望を頂きましたので、SESAME の特徴である WEB API による制御についてご紹介してみようと思います。
![SESAME.png](https://qiita-image-store.s3.amazonaws.com/0/241735/46923d38-668d-0957-25e0-a5704e6bf0cc.png)
https://ameblo.jp/candyhouse-inc/
http://yocchko.blogspot.jp/2017/12/sesame_16.html

※こちらの投稿は 2018年4月時点での、初代SESAMEを使用した内容です。現在 SESAME3 を検討中ですのでそちらの内容はまた後日追記しようと思っています。SESAME3 は性能もかなり向上しているようですし値段も安いのでかなり期待です！

##<b>■何が出来るの？</b>

#####<b>●スマホで外から鍵の状態確認＆開閉</b>
あれ？鍵閉めたっけ？とか外出中に家族がカギを忘れて締め出され電話がかかってくるとか。良くある話だと思いますが、そんな時にスマートロックがあればどこからでも鍵を開けられるのはものすごい安心感です ：D
以下に挙げている、その他の機能は機種によっても色々でそちらも便利なのですが、まずはこのもっとも基本の機能が当たり前ですが一番嬉しいですね☆

#####<b>●GoogleHome/AmazonEcho で音声で開錠 (API利用)</b>
玄関前で「ひらけゴマ」と言うと鍵が開きます。面白いですが危ないので日頃は無効にしていますが（笑）

#####<b>●オートロック</b>
ホテルなどで良くある、しばらくすると勝手に鍵がしまるあれです。

#####<b>●手ぶらで開錠</b>
自宅近くに帰ってくると自動で鍵を開けたりできます。

#####<b>●IoTボタンで開錠 (API利用)</b>
IoTボタンで鍵空ける（子供用）

#####<b>●おサイフケータイ・NFCタグで開錠 (API利用)</b>
玄関内側ガラス越しにカードリーダー設置して特定のスマホやNFCタグシールをかざして開錠。
NFCタグは安価で沢山カギを量産でき無くしても困らず、カジュアル・コピーも比較的防げるので、通常のカギよりは安心です。（うちのカギはディンプルシリンダーなのでカギ複製が1本5千円もするので無くすと痛いです・・・＞＜）

#####<b>●ノックで開錠</b>
こちらは SESAME だと iOS のみの機能みたいですが玄関近くでスマホをノックすると開錠出来る機能です。Android でも Tasker などのツールを併用すると似たことが可能です。

#####<b>●鍵のシェア</b>
これも良くある機能みたいですが、一時的に友達に自宅の鍵をシェアしたりできます。
例えば家で親戚が集まるよ！となったら親戚一同にメールで鍵を送れば、来客時に中から鍵を開けなくても鍵を持っている親戚は自由に鍵を開けることが出来ます。シェアした鍵は用事が済んだら無効にできます。
他にも色々活用方法が考えられるスマートロックらしい機能です。

#####<b>●ガラケー対応 (IFTTT利用)</b>
家族のガラケーから特定のSMS受け取るとIFTTT経由で開錠（公式アプリがスマホのみなので）

#####<b>●開閉の履歴</b>
いつ鍵が開いていつ閉まったか？の履歴がいつでもスマホで確認できます。

#####<b>●バッテリ残量を LINE とメールでお知らせ (API利用)</b>
この手の製品は基本省電力で電池駆動なので1年くらい持つらしいのですが、バッテリが切れる手前くらいで LINE やメールに通知が飛ぶようにしています。APIからバッテリ残量を確認できます。

#####<b>●IFTTT / WEB API によるコントロール</b>
今回こちらの投稿記事でご紹介しているメインの部分です。公式アプリ以外からも色々便利に使えますよという内容です。
調べてみたところ IFTTT や WEB API などをサポートしているスマートロック機種は意外に少なく、SESAME は比較的安価でこれらの機能が使える貴重な製品です。

##<b>■どんな商品があるの？</b>
あえてリンク等貼りませんがスマートロックで調べると色んなタイプの物が見つかると思います。

勝手にカテゴライズしてみると・・・

#####<b>⬜自作タイプ</b>
小回りの利く(ハッカブルな)商品が日本には少ないこともあって自作の方も結構おられます。
私も最初は自作を考えたのですが玄関なので見栄えが第一と考え今回はやめました。工作としてはそれなりに難易度も高く面白そうなのですが。

#####<b>⬜貼るタイプ</b>
今回ご紹介する SESAME もこちらですが、既存のドア鍵のサムターンを覆う形で被せることで自動でコントロールできるようにした商品で、他のタイプに比べると比較的安価で設置の手間も最小限ですが、サイズが大きかったり見栄えがイマイチな場合があるというタイプです。

#####<b>⬜ビルトインタイプ</b>
最初からスマートホーム化されてる おうち向け。
ドアの中に埋め込んでしまうタイプですね。賃貸だったりすると基本このタイプの選択は無理ですが、こちらは見栄えの面では一番すっきりしています。
早く全てのおうちに最初からスマートロックがビルトインされる時代が来ると良いですね～ ：D

※いずれのタイプも電池で駆動するものが中心ですが、基本1年くらいは電池交換なしで大丈夫です。

##<b>■IFTTT からコントロール</b>

今回 WEB API のご紹介なので省略しますが知りたい方は SESAME の公式サイトからどうぞ。
https://ameblo.jp/candyhouse-inc/entry-12353322034.html

鍵の開閉と、開閉時の通知を受け取れます。

以下でご紹介している WEB API がちょっと難しいな？と思われる場合には、IFTTT でも多少遅延はありますが、似たようなことが可能ですのでまずはこちらから試すのもありです。

その他おすすめとしては sesame の公式アプリがガラケーに対応していないので、IFTTT でガラケーから特定の題名のSMSを受け取るとそれをトリガーにして sesame で解錠というのが地味に便利です♪（この方法を使うとガラケーの人とも仮想鍵のシェアができるようになります）

※IFTTT や以下の WEB API の利用には SESAME 用の Wifi アダプタ？とか言うのが必要です。

##<b>■WEB API を使ってみよう</b>

SESAME では WEB API をサポートしていて、公式アプリではなく PC や Raspberry Pi など好みの機器から遠隔で鍵のコントロールが可能です。
https://docs.candyhouse.co/#sesame-api
https://ameblo.jp/candyhouse-inc/entry-12352517694.html

これが使いたくて SESAME を選択したようなものですが、実際に導入してみると、WEB API が最も使い勝手が良く私は公式アプリよりもこちらからの利用がメインです。

WEB API なら鍵の状態や SESAME のバッテリ残量は瞬時に確認可能で、鍵の開閉もおおむね2～5秒程度で完了しますので、IFTTT はもちろん下手をすると公式アプリよりも快適だったりします。

今回はご参考に nodejs のサンプルコードを用意しました。以下のコードを node がインストールされた端末で実行すると鍵の状態確認、開閉が可能です。

※ご使用時は node で HTTP 通信をするための request もインストールしてください。
　IDやパスは書き換え、デバイスIDもご使用の機器の物にステータス確認してかえてください。
　また WEB API はサーバーへ負荷をかけますのであまり頻繁にアクセスするのは控えましょう。

```sesame-door-ctl.js
var request = require('request');

// 引数チェック
var argExe = process.argv[0];
var argScr = process.argv[1];
if (process.argv.length < 3) {
    console.log('use: ' + argExe + ' ' + argScr + ' lock/unlock/status [force]');
    return;
}

var cmd = process.argv[2];  // コマンド引数取得
// コントロールコマンド強制フラグ
// 鍵の状態に関わらず必ず一回はコントロールコマンド送信
var cmdForce = false;
if( process.argv[3] == 'force' ) cmdForce = true;
var start = new Date();  // コマンド開始時間の記録
var authCode = 0;
var controlPostData = {"type": cmd };
var loginPostData = {
   email : "loginID", // ご自身のID/PASSへ！ 
   password : "pass"
};

var urlAry = [
{
  url: 'https://api.candyhouse.co/v1/accounts/login',
  method: 'POST',
  headers: { 'Content-Type' : 'application/json' },
  json: loginPostData
},
{
  url: 'https://api.candyhouse.co/v1/sesames',
  headers: { 'X-Authorization' :  authCode },
  method: 'GET',
},
{ // こちらのデバイスIDをお使いのものに書き換えてください 
  url:'https://api.candyhouse.co/v1/sesames/[deviceID]/control',
  method: 'POST',
  headers: { 'Content-Type' : 'application/json' },
  json: controlPostData
},
{url: 'end',method: 'GET',}]

// URL 配列から該当レコードを取り出してHTTPアクセス
function execRequests(urls, callback) {
  var url;
  var loopCounter = 0;

  function execRequest(mode) {
    // 現在時間の取得
    var end = new Date();
    // 経過時間
    var executionTime = end.getTime() - start.getTime();
    // 2分間リトライしてもだめなときは終了
    if( executionTime >= 1000 * 60 * 2 ) return callback();

    // 通信失敗の場合はログインからやり直す
    var nextMode = "login";
    var nextTimer = 1000;

    if( mode == "login" ) url = urls[0];
    else if( mode == "status" ) url = urls[1];
    else if( mode == "control" ) url = urls[2];
    else return callback();

    console.log("call url:", url.url);

    // ログインモード以外なら認証コード設定
    if( mode != "login" ) url.headers['X-Authorization'] = authCode;

    // HTTP リクエストの発行
    request(url, function(error, response, body) {
      console.log( "statusCode:", response.statusCode);
      if (!error && response.statusCode >= 200 && response.statusCode <= 210 ) {
         // ログイン・モードの場合
         if( mode == "login" ){
             // 認証キーを保存してステータス確認へ推移
             authCode = body.authorization;
             nextMode = "status";
             if( cmdForce ) nextMode = "control";
         // ステータス確認モードの場合
         } if( mode == "status" ){
             // 各種ステータスを取得
             var data = JSON.parse(body);
             var unlockedStat = true;
             var batteryStat = 100;
             if( data.sesames[0] ){
                 console.log('device_id: ' + data.sesames[0].device_id);
                 console.log('nickname: ' + data.sesames[0].nickname);
                 batteryStat = data.sesames[0].battery;
                 console.log('batteryStat: ' + batteryStat);
                 unlockedStat = data.sesames[0].is_unlocked;
                 console.log('is_unlocked: ' + unlockedStat);
             }
             if( unlockedStat ) console.log('鍵は開いています');
             else  console.log('鍵はしまっています');
             // ステータス確認のみなら即終了
             if( cmd == 'status') return callback();
             // ロック処理＆既にロック済みなので終了
             if( cmd == 'lock' && unlockedStat == false && !cmdForce ) return callback();
             // アンロック処理＆既にアンロック済みなので終了
             if( cmd == 'unlock' && unlockedStat == true && !cmdForce ) return callback();
             // コントロールAPI発行後 5回ステータス確認を繰り返す
             if( loopCounter >= 1 && loopCounter <= 5 ){
                 nextMode = "status";
                 nextTimer = 10000; // 10秒間隔
                 loopCounter++;
             } else {
                 // 初回もしくは5回ステータス確認後はコントロールAPI発行
                 nextMode = "control";
                 loopCounter = 1;
             }
         // コントロール・モードの場合
         } if( mode == "control" ){
             // コマンド発信後はステータス確認（ループカウンタも初期化）
             nextMode = "status";
             loopCounter = 1;
             // 一度コントロールコマンドを送ったら強制フラグを無効化
             cmdForce = false;
         }
      }

      // 指定モードに推移
      console.log("execute next mode after 10 sec...");
      setTimeout(function() {
         execRequest(nextMode)
      }, nextTimer );
    });
  }

  // login から処理を開始
  execRequest("login");
}

execRequests(urlAry, function() {
    console.log("---------End--------");
});
```
##<b>■WEBHOOK サーバの構築</b>

上記のサンプルだけだと、どうやって外からコントロールするのか分からない方もおられると思いますので参考情報も載せました。

以下は WEBHOOK サーバーを自宅に構築するために使っている node を使った HTTP サーバーのサンプルです。（HTTPサーバーをこんなシンプルなコードで書けるなんて良い時代ですね～しみじみ(笑)）
ルーターの設定で、この HTTP サーバーを実行する端末に向けてポートを空け、あとは IFTTT などから WEBHOOK を送れば、自宅の SESAME を外部からコントロールできます。

例えば IFTTT の位置情報をトリガーにして自宅近くに戻ったら、鍵を開ける WEBHOOK コマンドを自宅に送ると、玄関前に着いた頃にはちょうど鍵が空いているなんてことが出来たり、深夜に自動で鍵を閉めたり、など公式アプリでは出来ない色々なことが可能です。

※自宅の IP アドレスは変わると思いますので no-ip などのサービスと合わせてどうぞ☆
※掲載コード簡略化のためセキュリティー対策部分など省略していますので自己責任でどうぞ。

```webhook-server.js
// 使い方
// WEBHOOK URL: http://[URL]:1234 (ポートはお好きなものに変えてください)
// Method : POST
// Content type : application/json
// Body : { "command": "lock/unlock" }

// サーバーモジュール
var http = require('http');
// SHELL コマンド実行（同期呼び出し）
const execSync = require('child_process').execSync;

// WEBHOOK サーバー処理
var server = http.createServer(function (req, res) {
    // POST 処理
    if(req.method=='POST') {
         var body='';
         req.on('data', function (data) {
             body +=data;
         });
         req.on('end',function(){
            var POST = JSON.parse(body);
            res.writeHead(200, {'Content-Type': 'text/plain'});
            res.write('Hello World\n');
            if( POST.command ){ // 任意のコマンド呼び出し
                var cmdLine = 'node sesame-door-ctl.js \"' + POST.command  + '\" &';
                var result = execSync( cmdLine ).toString()
                console.log(result);
            }
            res.end();
         });
    }
});

console.log('start webhook server');

// サーバー起動
server.listen(1234);
```

※ルーターのポートを空けたくない場合には、ひと手間かかりますが Slack 経由とか Firebase 経由などのほか色々な方法があるのでお好みで☆
 サーバーを実行する機器はPCやラズパイ等の他FireTVStick等も利用可能です。

※Firebase [[Link]](https://qiita.com/kt-sz/items/c008084300a978516153)
※Slack [[Link1]](https://scrapbox.io/smart-home/TOP) [[Link2]](https://scrapbox.io/smart-home/Amazon_Echo%E3%81%A7RM_Mini3%E3%82%92%E6%93%8D%E4%BD%9C%E3%81%99%E3%82%8B)
※FireTVStickをlinuxサーバー化 [[Link]](https://scrapbox.io/smart-home/Fire_TV_Stickをhubotサーバ化してRM_Mini3を操作する)

##<b>■最後に</b>

上にも書きましたが WEB API の発行はあまり短時間に乱発しない様に、控えめな使い方を是非お願いします♪
サーバーに負荷がかかるとその分運用コストに跳ね返るので、最悪サービス停止なんてこともあり得ますから・・汗

##<b>■更新履歴</b>

・sesame-door-ctl.js に強制コマンド送信フラグ force を追加 (2018/04/16)

##<b>※投稿記事一覧</b>
他にも 自分で「おうちハック」した内容を以下に投稿しているので、よろしければ合わせてご覧ください☆

・GoogleHome/AmazonEcho とラズパイでやった事・やりたい事一覧[[LINK]](https://qiita.com/kt-sz/items/86536aff99d80c1cd464)
・Google Home でちょっと未来風のスマート TV を作ってみたよ☆[[LINK]](https://qiita.com/kt-sz/items/0362d5fe3e9a3e478245)
・黒豆 (Broadlink RM Mini 3) の IR 信号解析してみたよ♪ [[LINK]](https://qiita.com/kt-sz/items/1c36a7b22a58359a8e6f)
・スマートロック SESAME の WEB API が便利だった！[[LINK]](https://qiita.com/kt-sz/items/e8ccec02605584e62b53)
・Amazon Echo の沢山ある面白スキルを気軽に遊ぶ方法[[LINK]](https://qiita.com/kt-sz/items/0d01e763d540ddea5816)
・LINEを「ラズパイのターミナル化＆スマートホームのフロントエンド化(ChatOps風)」してみた♪[[LINK]](https://qiita.com/kt-sz/items/9adcb02a3b3a6cf3dd7b)
・LINE と Firebase とラズパイを繋いでみたよ☆[[LINK]](https://qiita.com/kt-sz/items/c008084300a978516153)
・GoogleHome と Chromecast でキーワード＆画像＆Wikipedia検索～TV表示[[LINK]](https://qiita.com/kt-sz/items/9edea18c4f0f5e8cf631)
・スマホ ハック＆スマートホーム連携 [[LINK]](https://qiita.com/kt-sz/items/9e23bd5969f0024b17f8)
・ラズパイとサーモセンサーで自宅のガスコンロ監視（火の用心） [[LINK]](https://qiita.com/kt-sz/items/471f469cc89d2bac0c76)
・トニー・スタークの家にありそうなスマート・テーブル（笑） [[LINK]](https://qiita.com/kt-sz/items/13cb71214604081dbf7c)