Photo by David Clode on Unsplash. The Gopher character is based on the Go mascot designed by Renee French.
※本記事で紹介している認証方法はFelicaのIDmのみを使用しております。IDm単体での認証はセキュリティ上望ましくないため、本記事を参考にされる方はご注意ください。
0. はじめに
はじめまして、2021年4月入社TIG/DXユニット所属の宮永です。
夏の自由研究ブログ連載2021の第2本目の投稿として、Sesame3にFelicaによる施錠解錠を実装しました。
作成したプログラムは orangekame3/gopy-sesame3: Sesame3のAPIをたたくクライアントアプリにて公開しています。
1. 動機
私が所属しているプロジェクトではGoをメイン言語としています。Go未経験者である私は身の回りで楽しみながら言語を学べるブツはないかと探しました。
するとそこにはSesame3がありました。
2. Sesame3とは
Sesame3はCANDY HOUSE JAPANが開発、販売しているスマートロックです。Sesame3本体に加えてwifiモジュールを購入すると、外出先から鍵の施錠/解錠を行うことができます。
また、6月にCANDY HOUSE公式でWeb APIが公開されており、鍵の状態確認、施錠/解錠などを行うことができます。
今回はこのデバイスを使ってFelicaによる施錠と解錠の機能を実装したいと思います。
3. 必要なもの
実装に使用したものを列挙します
3.1. ハード
- SESAME3 – CANDY HOUSE JAPAN
- 非接触ICカードリーダー | NFCポート パソリ | ソニー
- Raspberry Pi 3 Model B+ – Raspberry Pi
- スピーカー 8Ω8W: パーツ一般 秋月電子通商-電子部品・ネット通販
- 3.5mmステレオミニプラグ⇔スクリュー端子台: パーツ一般 秋月電子通商-電子部品・ネット通販
- PAM8012使用2ワットD級アンプモジュール: 組立キット(モジュール) 秋月電子通商-電子部品・ネット通販
3.2. ソフト
開発はWindows10環境、WSL2上で行いました。
- Go1.16.6 linux/amd64
- Python 3.8.10
Sesame3を動かすWeb APIはこちらからAPI_TOKENを発行してください。
API_TOKENの発行の方法はこちらのブログが参考になりました。
施錠/解錠に必要な情報は
- API_TOKEN
- UUID
- SECRET_KEY
の3つです。
4. 構成
PythonでカードリーダーによるIDmの読み取りとSECRET_KEY
の暗号化を行い、GoでHTTPリクエストを行うという構成にしました。
この構成にした理由は以下の3点です。
- Pythonに便利なモジュールがあった
- Goに少しでも慣れたかった
- cgoというものを見つけてしまった
本来であれば素直にPython1本、Go1本に絞ったほうが良いと思います…。
4.1 システム概要図
以下システムの概要図です。
Raspberry Piにカードリーダー、スピーカーを接続しています。PythonでカードーリーダーからFelicaのIDmを取得し、暗号化したSECRET_KEYとAPI_TOKENをGo側に渡します。また、IDmの検知をユーザーに通知音で知らせています。GOではCANDY HOUSEが公開しているWeb APIに向けてHTTPリクエストを行います。リクエストに応じて、SESAME3を開閉できるという構成になっています。
4.2. ディレクトリの構成
ビルド前のディレクトリの構成です。
. |
5. 実装
APIの使用方法は公式にて、PythonおよびJavaScriptで公開されています。
今回は公式に記載された方法を手掛かりにコーディングしました。
5.1. HTTPリクエスト
GoでHTTPリクエストを実装します。今回はcgo
を使用するため、構造体はなるべく使わずメソッドのみで完結させます。
まずは変数定義です。rootUrl
は公式に記載されたendpointです。コマンドに応じてrootUrl
に追記していきます。cmd_unlock
、cmd_lock
は公式ページに指定された解錠コマンドおよび施錠コマンドです。src
にはアプリに登録する履歴名を指定しています。今回はby Felica
という名前で登録しています。
package main |
続いて、HTTPリクエストに使用するJSONを格納するための構造体を定義します。こちらも
公式に記載されているJSONの定義を参考にしました。
type RequestBody struct { |
それでは、鍵の開閉を行う関数executeSesame3
を実装します。関数内で指定された引数signPtr
、apiPtr
、uuidPtr
はPythonから渡されることを想定しています。C.
を指定することでcgo
内の関数を使用できます。
ここで1つ注意が必要です。cgo
を利用する際はメソッドの上のコメントを関数名にそろえる必要があります。
開閉の流れとしては「施錠中/解錠中の確認fetchStatus
」→「解錠中isUnlocked
であればexecuteLock
を実行」「施錠中であればexecuteUnlock
を実行する」という構成です。
//export executeSesame3 |
次に、fetchStatus
をコーディングします。fetchStatus
は鍵の状態を取得する関数です。鍵の状態取得のHTTPリクエストに必要な情報はUUID
とAPI_TOKEN
です。rootUrl
に自分のデバイスのUUID
を追加したものがendpointです。
//export fetchStatus |
最後に施錠と解錠の関数executeLock
、executeUnlock
をコーディングします。こちらの2つはほぼ同じ内容です。
//export executeUnlock |
以上でGo側のコーディングは完成です。
Pythonのコーディングを始める前にexport.go
をビルドします。/exoprt
にて以下コマンドを実行します。
go build -buildmode=c-shared -o export.so |
ビルド後、export配下に新たにexport.so
、export.h
が出力されていることが確認できます。
. |
次にPython側をコーディングしていきます。
5.2 NFCの読み込み
Python側ではカードリーダーの制御、環境変数の引き渡し、SECRET_KEY
の暗号化を行います。また、ICカード検知の通知音を出すために、スピーカーの制御も行っています。
以下必要となるモジュールを読み込みます。自作したモジュールはnfcreader.py
のみです。
from ctypes import * |
まずは環境変数の読み込みです。
ここで環境変数とはSECRET_KEY
、API_TOKEN
、UUID
、ICカードのIDm
を指しています。環境変数は誤ってGitHubなどに公開しないようにまとめて管理します。
環境変数の管理にはpython-dotenv
を使用しました。ソースコードでは相対ディレクトリでプロジェクトディレクトリの直上に配置しています。
load_dotenv('../.env') |
まずはMySesame3
クラスを定義します。
MySesame3
はコンストラクタにて冒頭で読み込んだ環境変数を格納しています。暗号化する際にtimestamp
が必要となるため、sign
(署名)のみ空にしています。また、先ほどビルドすることによって生成されたexport.so
ファイルを読み込んでいます。メソッドとしてSECRET_KEY
の暗号化encryptmyKey
、および施錠と解錠lockOrunlock
を持っています。
class MySesame3: |
次に一度main.py
からは離れて、カードリーダーのクラスを定義します。こちらは別ファイルnfcreader.py
にコーディングします。nfcreader.py
をコーディングするにあたってこちらの方の記事を参考にしました。
import nfc |
main.py
の本体を記述します。
先ほど定義したクラス、およびカードリーダーのクラスを使用します。
構成としては「Mysesame3
およびCardReader
インスタンス生成」→「CardReader
インスタンスに格納されたIDmを取得」→「受信を検知したらスピーカーから音で通知」→「環境変数に登録したIDmを参照」→「一致したら施錠/解錠リクエストを送信」といった流れになっています。スピーカーの音源はnotify.wav
という名前で同main.py
と同階層に配置しています。
def ismyID(id): |
6. スピーカーから音を出す
最後にラズパイから音を出すためにスピーカーを取り付けます。高価なスピーカーはもったいないのでこちらはアンプを取り付けて自作します。スピーカーの取り付けはこちらの記事を参考にしました。
7. 取り付け
スピーカーを取り付けたらとりあえず、新聞受けに投げ入れます。玄関まで電源コードを延長するのが大変でしたが、こちらの延長コードでどうにか電源供給できました。
カードリーダーはコクヨのマグネットプレートを使って取り付けました。
8. 動作確認
動作確認の結果です。待機Waiting Felica...
から検知Detected!!
→Lock command was executed.
と正しく動作していることがわかります。
こちらは施錠時のスマホの通知画面です。export.go
に定義した文字列by Felica
が正しく表示されています。
9. まとめ
Sesame3のWeb APIを利用して、Felicaによる施錠解錠の機能を実装しました。
今回認証に使用したIDmはスマホアプリでも簡単に取得できます。そのため、IDm単体に認証を任せてしまうのはセキュリティの観点から適切ではありません。実用に耐えうるにはさらなる工夫が求められます。とはいえ、GoとPythonを使って楽しみながらコーディングできたため、夏休みの自由研究の目的は達成できたと思います。
次は大野さんによる最高の持ち歩きキーボード考です。