🔑

玄関のハイテク指紋認証システムを卒業してSlack認証に移行する話

2020/12/21に公開

この記事は高知工科大学 Advent Calendar 2020 21日目の記事です。

どうも、ロボ部OBの \ヒッカリーン/ です。
突然ですがみなさん、自宅の玄関の鍵の管理はどうしてますか?
財布に入れるなりなんなりして外出時はちゃんと毎回鍵を閉めていますか?
ほんとに? スーパー行くときは? コンビニ行くときは? 自販機行くときは?

そう、実は鍵を掛け持ち歩くというのは非常にめんどうです。
財布に入れるにしても邪魔だし、かといって鍵ポーチとかすると無くすし忘れるし、そもそも鞄から探し出して鍵穴にさして回すという動作自体がめんどくささの塊です。

そして、朝急いでる時に「今日はいっか」となり、一度あることは百度あり、だんだんそれに慣れ、しまいめには「うちはハイテク指紋認証システムやからドアノブ触った瞬間に認証してるし大丈夫」とか言い出すようになってしまいます。

ロボ部員はとても技術力が高く優秀なのでそんなハイテクなシステムを構築し運用してる人を何人も見てきました。
が、残念なことに私にはそんなハイテクシステムを維持管理出来るほど技術力が足りてなかったのでもっと簡単なものにダウングレードすることにしました。

鍵からの解放

そもそも論として鍵とかいう金属の塊の存在が邪魔です。
いや形状がカードとかだとしても玄関を開けることしか能のない専用の物体を持ち歩いてるという事自体がもう先の時代の敗北者であることを物語っています。

今は"令和"です。スマホさえあれば何でもできる時代です。
モバイルSuica、QUICPay, iD, QRコード決済, etc... でスーパーとかコンビニとか行く程度なら財布すら持ち歩く必要はありません。
なのになぜ鍵とかいう訳の分からん物を持ち歩かねばならんのでしょう?
もはや意味が分かりません。

そこでスマートロックです。スマートロックであれば Bluetooth, Wi-Fi, FeliCa 等なんかしらの方法でスマホで鍵を開けれます。

スマートロック

しかし以下をご覧ください。

https://www.google.co.jp/search?q=スマートロック+比較

たけぇ。
だいたいどれも1万超えてるというか数万するやつもあるしそのくせ機能的にも微妙なのばっかりです。
そしてAPIとかも公開されてないから使いやすいように自分でいい感じにすることも出来ない。
これではもはやスマートとは言えません。

ならば作るしかない。パンがなければお菓子を作ればいいじゃない。

そこで登場するのはこいつです。
https://www.sparkfun.com/products/retired/13648

これにはサムターンを回すためのモーターと電池入れが付いてます。
そして安い。(当時4個セットで$119.8)
完璧です。あとはこれにラズパイかなんかを取り付けてちょっとプログラム書くだけです。
もはや既に完成しているといっても過言ではないでしょう。

しかしこれには大きな罠がありました。
価格がドルであることから察せられる通りこれは日本向けの製品ではなく海外の製品です。
そう、つまりでかすぎたのです。

でかい。でかすぎる。
ドアノブには干渉するし、そもそもドアの枠にすら収まっていません。
何という事でしょう。これではただのガラクタです。

これが2016年に起きた悲劇です。
しかしこれは敗北ではありません。時代の最先端を行くために必要な投資であり、尊い犠牲なのです。

(欲しい人はあげるので言ってください)

セサミ mini

気を取り直してスマートロックに最低限必要な機能を定義しましょう。
いい感じにヨロとか適当なことやってるからあんなことになるのです。要件定義は大事です!!!

  • 設置できる <- 非常に重要
  • スマホで開けれる
  • WebAPI とか Bluetooth の API とか何かがあって自分でカスタマイズできる

これらを満たしてるのを去年発見しました。セサミ mini です。

https://jp.candyhouse.co

これはスマホに専用アプリを入れて Bluetooth で接続して操作するタイプのやつで、WiFiモジュールもセットで買うことでなんとWebAPIでも操作が可能になるという素晴らしいやつです。
そして何よりちっちゃいので設置可能です。

WebAPIがあるという事は向こうにそういうサーバーがあるという事なのですが、それを使うのがいやであればラズパイかなんかを直接 Bluetooth で接続させて自宅でサーバー立てるという事も頑張れば可能そうです。
https://qiita.com/odetarou/items/9628d66d4d94290b5f2d

完璧です。使ってみて専用アプリがクソだったとしてもこれなら自分でなんとかできそうです。

そして数日使ってみてクソな点をいくつか発見しました。

  1. スマホと Bluetooth で繋ぐ時の時間が非常に長いため鍵が開くまで玄関先で待たされる
  2. 鍵を2台目のスマホとか友達とかにシェアするのにも専用アプリとアカウント登録が必要

1番は人によるかもしれませんが、こちとら超ハイテクシステムを使っていた身です。待ち時間が真の0秒から数十秒になるのは苦痛です。
2番もめんどくさい。アプリ入れるだけならまだしもアカウント登録とかもうええわって感じです。

1番の原因はスマホと Bluetooth で接続するのが遅い事です。ならばスマホより前に接続済みであろうWiFiモジュールつまりWebAPIで鍵を開ければ解決しそうです。
2番も簡単。WebAPIがあるのでそういう何かを作ればいいのです。

そこで登場するのが Slack の Slash Commands。
私の家に来るような奴はどうせSlackに居るし、鍵開ける用プライベートチャンネルを作りそこでしか呼び出せないようなコマンド作って使わせればいいのではないでしょうか。
Slack に任せてしまえば認証とかめんどくさいこと考えなくて済みますし。

Slack 認証システム

Slack通知

では早速鍵を開けるコマンドを作っていきたいですがその前にまずは通知機能が必要でしょう。
Sesame Webhook という機能がありこれを使えば鍵の開閉時に登録したURLに通知を飛ばすことが出来ます。
https://docs.candyhouse.co/#sesame-webhook

今回は Sesame Webhook で Google Apps Script に HTTP POST 投げて、GAS から Slack の Incoming WebHooks で自分に dm で通知するようにします。

1. Slack の Incoming WebHooks の設定をする

設定の仕方はググってください。
自分のdmに通知が行くようにし、あと Webhook URL を取得しメモっておきます。

2. Sesame のダッシュボードで Device ID を取得する

https://my.candyhouse.co/#/sesameList
↑ダッシュボードのセサミリストで使用する Sesame を選ぶとブラウザのURLでデバイスIDが取得できるのでそれを取得する。(デバイスIDはシリアル番号の事ではありません)

以下参考
https://docs.candyhouse.co/#obtain-your-api-key-and-device-id

3. GAS を作成する

GASを作り、以下の様にスクリプトとスクリプトプロパティを入力します。

※ 最近GASのスクリプトエディタが更新されましたがそっちだと "スクリプトのプロパティ" が編集出来ないみたいなので旧バージョンを使うように

メニューバーの "ファイル" -> "プロジェクトのプロパティ" -> "スクリプトのプロパティ"

プロパティ
SLACK_WEBHOOK_URL Slack の Webhook URL
SESAME_DEVICE_ID Sesame の Device ID
const props = PropertiesService.getScriptProperties();

function doPost(e) {
  const param = e.parameter;

  if (param.is_sesame == 1) {
    const data = JSON.parse(e.postData.getDataAsString());
    if (data.device_id == props.getProperty('SESAME_DEVICE_ID')) {
      UrlFetchApp.fetch(props.getProperty('SLACK_WEBHOOK_URL'), {
        method: 'post',
        contentType: 'application/json',
        payload: JSON.stringify({
          text: `玄関の鍵が${data.locked ? '閉まりました' : '開きました'}`
        })
      });
      return ContentService.createTextOutput('OK');
    }
    return;
  }
}

4. GAS のデプロイ

メニューバーの "公開" -> "Webアプリケーションとして導入"
でアクセス権を "Anyone, even anonymous" としてデプロイします。
そして URL を取得します。

5. Sesame Webhook を設定する

https://my.candyhouse.co/#/credentials
↑ダッシュボードのAPI設定の Services -> Webhook で POST を選択し、URL にさっき取得した GAS の URL を入力します。
そして URL にクエリパラメータとして ?is_sesame=1 を追加します。


これで鍵が開閉されるたびに Slack に通知が来るようになりました。

鍵開けるコマンド

さて本命鍵開けるコマンドです。
鍵を開けるには以下の Control Sesame の API を使えばよさそうです。
https://docs.candyhouse.co/#control-sesame

今回は Slack の Slash Commands で先ほどの GAS に HTTP POST 投げて、GAS から Sesame の Control Sesame の API 叩くようにします。

1. Slack の Slash Commands を設定する

設定の仕方はググってください。
URL に GAS の URL を入力し、Method は POST にします。
コマンドは /hikari unlock とかにしましょうか。
そして Token の値をメモっておきます。

※ 開閉通知時に is_sesame=1 とか付けたのはこの Slash Commands からのリクエストなのかどうかを区別するためです。

2. Sesame のダッシュボードで API Key を取得する

https://my.candyhouse.co/#/credentials
↑ダッシュボードのAPI設定の API Keys で API Key を取得します。

3. Slack で鍵開ける用プライベートチャンネル作成し、チャンネルIDとか取得する

プライベートチャンネルを作成した後ブラウザで Slack を開くと URL でチャンネルのIDとかが取得できるのでメモっておく。
https://app.slack.com/client/{チームID}/{チャンネルID}
のような URL になってます。

4. GAS を以下のように変更する

プロパティ
SLACK_WEBHOOK_URL Slack の Webhook URL
SESAME_DEVICE_ID Sesame の Device ID
SESAME_ENDPOINT https://api.candyhouse.co/public
SESAME_API_KEY Sesame の API Key
SLACK_TOKEN Slash Command の Token
SLACK_TEAM_ID Slack のチームID
SLACK_CHANNEL_ID Slack のチャンネルID

const props = PropertiesService.getScriptProperties();

function doPost(e) {
  const param = e.parameter;

  if (param.is_sesame == 1) {
    const data = JSON.parse(e.postData.getDataAsString());
    if (data.device_id == props.getProperty('SESAME_DEVICE_ID')) {
      UrlFetchApp.fetch(props.getProperty('SLACK_WEBHOOK_URL'), {
        method: 'post',
        contentType: 'application/json',
        payload: JSON.stringify({
          text: `玄関の鍵が${data.locked ? '閉まりました' : '開きました'}`
        })
      });
      return ContentService.createTextOutput('OK');
    }
    return;
  }

  if (param.token != props.getProperty('SLACK_TOKEN')
    || param.team_id != props.getProperty('SLACK_TEAM_ID')
  ) {
    return;
  }

  if (param.channel_id != props.getProperty('SLACK_CHANNEL_ID')) {
    return ContentService.createTextOutput(`このコマンドは <#${props.getProperty('SLACK_CHANNEL_ID')}> で実行してください`);
  }

  const args = param.text.split(' ');
  switch (args[0]) {
    case 'unlock': {
      const res = post_command(props.getProperty('SESAME_DEVICE_ID'), 'unlock');
      return ContentService.createTextOutput(JSON.stringify({
        response_type: 'in_channel',
        text: `<@${param.user_id}> が鍵を開けました`
      })).setMimeType(ContentService.MimeType.JSON);
    }
  }

  return ContentService.createTextOutput('Invalid argument');
}

// command: 'lock' or 'unlock' or 'sync'
function post_command(device_id, command) {
  return UrlFetchApp.fetch(`${props.getProperty('SESAME_ENDPOINT')}/sesame/${device_id}`, {
    method: 'post',
    headers: {
      Authorization: props.getProperty('SESAME_API_KEY'),
    },
    contentType: 'application/json',
    payload: JSON.stringify({
      command: command
    })
  });
}

5. GAS のデプロイ

再度 "Webアプリケーションとして導入" でデプロイします。Project version を New にすること。


これでプライベートチャンネルで /hikari unlock コマンドが使えるようになりました。
このコマンドで鍵を開けれます。

さいごに

いかがでしたか?
非常に簡単に Slack 連携が出来たのではないでしょうか?

セサミWiFiセットを買って↑のスクリプトコピペするだけ

じゃあ今すぐポチろう
https://jp.candyhouse.co/collections/frontpage

と思ったらちょっとまて

先週ぐらいに SESAME3 とかいう新バージョン発表されてるやん
なんか接続時間とか改善されてて性能あがってるし
しかも WiFiセットで8千円しないし

miniのセットを2万で買った私はいったい...

あとマンションのエントランスのせいで結局鍵要るのなんとかしたい 😇


追記

SESAME3だとエントランス問題も解決するらしい 😇

Discussion