LoginSignup
6
11

More than 3 years have passed since last update.

【改訂版】Suicaをカードリーダで認識させて、サーボモータを回すスマートロックもどきを作った。

Last updated at Posted at 2019-05-15

【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カードを認証するプログラムを書く。

スクリーンショット 2019-05-15 19.15.04.png

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登録プログラムを作成する。
以下を記述。

add_suica.py
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番)に接続)

スマートロックもどきプログラムを作成する。

いよいよ、スマートロックもどきライブラリを作成する。

suica.py
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

感想

・意外と簡単だった。
・ここから、電子工作で拡張していくので、結構大変になるかも。。。

6
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
11