【2019/05/18 追記】
- DBをSQLiteから、MariaDBに変更しました。
- 旧ソースコードでは、複数カード登録した際にタイムラグが発生する現象が起きていたので、修正しました。
はじめに
ひょんなことから、スマートロックのプロトタイプ開発をすることになり、色々ネットで記事を漁りつつ、開発をしてみました。
参考になった記事を、敬意を評しつつ、ここに載せておきます。
基本的な事はこちらに書いてますので、見てください。
Raspberry Piでサーボモーターを回す
Raspberry PiにNFCリーダを接続してSuicaを読み取る
Raspberry Piとサーボモータで踊るはにわ制作
Raspberry PiでPythonからMySQLデータベースを扱う
必要なもの
物理的なもの
Raspberry Pi 3 B+(今回はスターターキットを購入)
サーボモータ
ジャンパーピン(オス/メス)
USBキーボード
USBマウス
ディスプレイ
NFCカードリーダ(PaSoRi RC-S380)
開発環境
OS: Raspbian
言語: Python2
DB: MariaDB(MySQL)
やりたいこと
- 事前に、DB登録プログラムを動かして、DBにカードのIDmを登録。
- スマートロックもどきプログラムを動かして、カードを認証
- 認証されたカードが、DBにあるIDmと一致した場合、サーボモータが回転する。
- 今回は、Suicaと白無地のFelicaカードを認証するプログラムを書く。
DB登録追加プログラムを作成
まず、以下のコマンドを実行して、nfcpyをインストールする。
pip install nfcpy
そして、MariaDBにデータベースを作成して、テーブルを作成する。
create database suica;
use suica;
create table usercard(id int(11) primary key, auto_increment, card varchar(100));
そして、DB登録プログラムを作成する。
以下を記述。
import binascii
import nfc
import time
import pymysql.cursors
import hashlib
from threading import Thread, Timer
from contextlib import closing
from mysql.connector import errorcode
TIME_cycle = 1.0
TIME_interval = 0.1
TIME_wait = 3
count = 0
#suica
target_req_suica = nfc.clf.RemoteTarget("212F")
#それ以外のカード
target_req_blank = nfc.clf.RemoteTarget("212F")
target_req_suica.sensf_req = bytearray.fromhex("0000030000")
connection = pymysql.connect(host="localhost", user="root", password="********", db="suica", charset="utf8")
print 'Suica waiting...'
while True:
clf = nfc.ContactlessFrontend('usb')
# suica
target_res = clf.sense(target_req_suica, iterations=int(TIME_cycle//TIME_interval)+1, interval=TIME_interval)
#それ以外のカード
target_res2 = clf.sense(target_req_blank, iterations=int(TIME_cycle//TIME_interval)+1, interval=TIME_interval)
#suicaかそれ以外のカードか分別する
target = None
if target_res != None:
target = target_res
elif target_res2 != None:
target = target_res2
if target != None:
tag = nfc.tag.activate(clf, target)
tag.sys = 3
idm = binascii.hexlify(tag.idm)
with connection.cursor() as conn:
hash_idm = hashlib.md5(str(idm)).hexdigest()
insert = 'insert into usercard (card) values (%r);' % hash_idm
print insert
conn.execute(insert)
connection.commit()
time.sleep(10)
clf.close()
物理的な設定(サーボモータ)
オス/メスのジャンパーピンも併用して、サーボモータに接続する。
サーボモータのケーブルと同色のジャンパーピンを接続し、
ジャンパーピンを以下に記載しているラズパイのピンに接続する。
赤: 5V
茶: GND
オレンジ: GPIO系で任意のもの(今回はGPIO4(端子番号7番)に接続)
スマートロックもどきプログラムを作成する。
いよいよ、スマートロックもどきライブラリを作成する。
import binascii
import nfc
import RPi.GPIO as GPIO
import time
import pymysql.cursors
import hashlib
from threading import Thread, Timer
from contextlib import closing
TIME_cycle = 1.0
TIME_interval = 0.1
TIME_wait = 1
status = 0
count = 0
target = ''
def open():
GPIO.setmode(GPIO.BCM)
gp_out = 4
GPIO.setup(gp_out, GPIO.OUT)
servo = GPIO.PWM(gp_out, 50)
servo.start(0)
servo.ChangeDutyCycle(12)
time.sleep(0.1)
servo.stop()
def close():
GPIO.setmode(GPIO.BCM)
gp_out = 4
GPIO.setup(gp_out, GPIO.OUT)
servo = GPIO.PWM(gp_out, 50)
servo.start(0)
servo.ChangeDutyCycle(7.25)
time.sleep(0.1)
servo.stop()
target_req_suica = nfc.clf.RemoteTarget("212F")
target_req_blank = nfc.clf.RemoteTarget("212F")
target_req_suica.sensf_req = bytearray.fromhex("0000030000")
connection = pymysql.connect(host="localhost", user="root", password="mnmr0043", db="suica", charset="utf8")
print 'Suica servo waiting...'
while True:
clf = nfc.ContactlessFrontend('usb')
target_res = clf.sense(target_req_suica, iterations=int(TIME_cycle//TIME_interval)+1, interval=TIME_interval)
target_res2 = clf.sense(target_req_blank, iterations=int(TIME_cycle//TIME_interval)+1, interval=TIME_interval)
#print target_res
target = None
if target_res != None:
target = target_res
elif target_res2 != None:
target = target_res2
if target != None:
tag = nfc.tag.activate(clf, target)
tag.sys = 3
idm = binascii.hexlify(tag.idm)
#print idm
print 'sleep' + str(TIME_wait) + 'seconds'
with connection.cursor() as conn:
c = conn
db_idm = hashlib.md5(str(idm)).hexdigest()
select = 'select card from usercard where card=%r;' % db_idm
c.execute(select)
result = c.fetchall()
for row in result:
if db_idm == str(row[0]):
if status == 0:
open()
print 'servo turn'
print status
status = 1
count+=1
else:
close()
print 'servo reverse turn'
print status
status = 0
time.sleep(TIME_wait)
print 'sleep' + str(TIME_wait) + 'seconds'
else:
print 'Not users Auth.'
GPIO.cleanup()
clf.close()
完成
最初に、以下のコマンドでDB登録ライブラリを動かして、カードを読み込む。
sudo python2 add_suica.py
次に、以下コマンドでスマートロックもどきライブラリを動かして、カードを読み込むと、サーボモータが動く。
sudo python2 suica.py
Raspberry Piでスマートロックもどき作った。
— やっぴー@20卒 (@yanashi_masa) 2019年5月15日
・DBにカードのIDmを登録するライブラリを動かして、カードを認識させて登録。
・認証したカードのIDmが、DBにあるIDmと一致した場合、サーボモーターが回る。(ない場合は回らない。) pic.twitter.com/Aa8MHCZjSD
感想
・意外と簡単だった。
・ここから、電子工作で拡張していくので、結構大変になるかも。。。