|
| ||||||||
|
巻き戻し中。
|
|
2020-02-12(水) IoT [長年日記]
_ 家の鍵
sesameでIoT化してみた。
もちろん、スマホから操作可能。
WiFiアダプタもセットしたのでBluetoothでの近場の操作だけじゃなくてネット経由で操作可能。
開閉よりも、実は外部から鍵の状態が分かる方がありがたい。
「アレ?鍵ちゃんと閉めたっけ?」と言うときにすぐ確認できる。
それだけじゃ面白くないので、せっかくネットに繋がってるしAWSのIoTエンタープライズボタンでコントロールできるようにしてみた。
クリック一発動作だけならメーカーの解説にあるサンプルコードで十分。
で、ウチの場合は
・玄関は鍵が2つ
・クリックで開くだけだと不便、ポケット内で押しちゃう誤動作も気になる
と言うことで、一発で2個のsesamiにコマンド投げるのと「クリック/ダブルクリック/長押し」を使い分けることにした。
誤動作防止と利便性を考えて
-シングルクリック:施錠
-ダブルクリック:解錠
-長押し:トグル
にしてみた。
これなら、間違って押したぐらいなら鍵が閉まるだけ。
もちろん、AWSIoTボタンのネットワークは自宅の無線LANにしか繋がらないようにしてあるのでとんでもないところからうっかり施錠や解錠することはない。
あと、print文を何カ所かに入れてあるので、AWSのログに変数/コマンドの履歴が残って確認が楽&開閉記録になるはず。
AWS IoTエンタープライズボタンはこちら
_ Lambdaのコードはこんな感じ
切り貼りだったり、実験で使ったのも含んでるので余計なimportとかスマソ。from http.client import HTTPSConnection import json import os import boto3 import logging def get_command(conn, url, headers): conn.request('GET', url, headers=headers) ret = conn.getresponse() if ret.getcode() == 200: sesame_status = json.loads(ret.read().decode('ascii', 'ignore')) return 'unlock' if sesame_status['locked'] else 'lock' else: raise RuntimeError('Server return error: %s' % ret.read()) def get_clicktype(event): try: clicktype = event['deviceEvent']['buttonClicked']['clickType'] except KeyError as err: clicktype = 'other' print(clicktype) return clicktype def lambda_handler(event, context): if 'DEVICE_ID1' not in os.environ: raise RuntimeError('DEVICE_ID1 not given') if 'DEVICE_ID2' not in os.environ: raise RuntimeError('DEVICE_ID2 not given') if 'APIKEY' not in os.environ: raise RuntimeError('APIKEY not given') if os.environ.get('COMMAND_L') not in ('lock', 'unlock', 'toggle'): raise RuntimeError('COMMAND_L must be "lock", "unlock" or "toggle"') if os.environ.get('COMMAND_S') not in ('lock', 'unlock', 'toggle'): raise RuntimeError('COMMAND_S must be "lock", "unlock" or "toggle"') if os.environ.get('COMMAND_D') not in ('lock', 'unlock', 'toggle'): raise RuntimeError('COMMAND_D must be "lock", "unlock" or "toggle"') click_type = get_clicktype(event) print(click_type) if click_type == "SINGLE": COMMAND = os.environ['COMMAND_S'] elif click_type == "DOUBLE": COMMAND = os.environ['COMMAND_D'] elif click_type == "LONG": COMMAND = os.environ['COMMAND_L'] else: COMMAND = "" #pass print(COMMAND) url_1 = '/public/sesame/%s' % os.environ['DEVICE_ID1'] url_2 = '/public/sesame/%s' % os.environ['DEVICE_ID2'] headers = { 'Authorization': os.environ['APIKEY'], 'Content-Type': 'application/json' } conn = HTTPSConnection('api.candyhouse.co') if COMMAND == "toggle": body1 = json.dumps({'command': get_command(conn, url_1, headers)}) else: body1 = json.dumps({'command': COMMAND}) conn.request('POST', url_1, headers=headers, body=body1) ret1 = conn.getresponse() conn = HTTPSConnection('api.candyhouse.co') if COMMAND == "toggle": body2 = json.dumps({'command': get_command(conn, url_2, headers)}) else: body2 = json.dumps({'command': COMMAND}) conn.request('POST', url_2, headers=headers, body=body2) print(body2) ret2 = conn.getresponse() try: response_body1 = json.loads(ret1.read().decode('ascii', 'ignore')) response_body2 = json.loads(ret2.read().decode('ascii', 'ignore')) if ret1.getcode() == 200: print('[SESAME1] Request successed with task_id=%(task_id)s' % response_body1) return response_body1 elif ret2.getcode() == 200: print('[SESAME2] Request successed with task_id=%(task_id)s' % response_body2) return response_body2 else: raise RuntimeError('Server return error for ID_1: %(error)s' % response_body1) raise RuntimeError('Server return error for ID_2: %(error)s' % response_body2) except json.decoder.JSONDecodeError: raise RuntimeError('Can not parse response for ID_1: %s' % response_body1) raise RuntimeError('Can not parse response for ID_2: %s' % response_body2)
_ 変数
Lambdaの環境変数は以下を指定
-----------------------------------------
APIKEY
:sesamiのサイトで取得
DEVICE_ID1
:1個目の鍵のID
DEVICE_ID2
:2個目の鍵のID
COMMAND_L
:toggle:長押し時のコマンド
COMMAND_S
:lock:シングルクリック時のコマンド
COMMAND_D
:unlock:ダブルクリック時のコマンド
-----------------------------------------
Tweets by RC31E | |||||||||
| |||||||||
| |||||||||
|