ラズパイでスマートロック作ってみた④ – ICカードでドアを開閉する

じょるブログ

現役理系大学生による大学生に向けた情報サイト

電子工作

ラズパイでスマートロック作ってみた④ – ICカードでドアを開閉する

投稿日:

大学生の電子工作 ラズパイでスマートロック作ってみたの記事の④つ目の記事です。今回はSuicaや学生証、電子マネー(nanacoとか)等のICカードで鍵を開けられるようにしました。

近くのコンビニに買い物に行くときなどは、財布だけをもってスマホを持たずに外出してしまうことが何度かありました。(そのようなときは研究室のパソコンから自宅のラズパイにVNCで直接アクセスし鍵を開けました。)

現状私の家の玄関を開けるには、

などの方法がありますが、財布のみをもって外出してしまった場合、実用的でない方法 ( 外からアレクサに話しかけて開ける方法) を除き、鍵を開ける手段がありません。

スマホも財布も持たずに外出することは考えられないので、今回は財布に入っているICカードで開けられるようにし、スマートロック完全体を作成してスマートロックに締め出されないようにしようと思います!

また、スマホの手帳型ケースにもICカードが入っているので、スマホを操作せずともスマホをタッチするだけで鍵が開けられるようにもなります。

     

搭載した機能

  

実行環境

  • ラズベリーパイ3 B+
  • ICカードリーダー ( RC-S320 )

SONY RC-S320 非接触ICカードリーダ/ライタ PaSoRi 「パソリ」

      

手順

  1. ICカードを読み取るための基本設定
  2. ICカードで鍵を開けるプログラムの作成

  

1.  ICカードを読み取るための基本設定

まず、ICカードリーダーを使用してICカードを読み取れるようにする設定を行います。

この設定方法については以下の記事をご覧ください。

上記の記事内“実装方法” の項目のところまで行ってください。

  

2.  ICカードで鍵を開けるプログラムの作成

次に、以下のプログラムを作成し保存してください。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import paho.mqtt.client as mqtt
import subprocess
import datetime
import json
import sys
import time
import RPi.GPIO as GPIO
from time import sleep
from ctypes import *
import concurrent.futures



##### beebotteのセッティング #####
HOST = 'mqtt.beebotte.com'
PORT = 8883
CA_CERTS = 'mqtt.beebotte.com.pem'
TOKEN = 'token_xxxxxxxxxxx'
TOPIC = 'xxxxxxxx/xxxxxxxx'


# libpafe設定
FELICA_POLLING_ANY = 0xffff
allow_idm_list = ['1234567890123456', '112233445566aabbb']


##### サーボモーターのセッティング #####
# pinの指定方法をBCMに設定(GPIO.BOARDとすると基盤のピン番号となる)
GPIO.setmode(GPIO.BCM)
# pin番号の指定
pin_servo = 4
# 指定したpinを出力に設定
GPIO.setup(pin_servo, GPIO.OUT)
# PWMサイクルを50Hz(20ms)に設定 (都合により関数内で設定を行う)
# servo = GPIO.PWM(pin_servo, 50)
# 回転角を定義
left   = 2.5
center = 7.25
right  = 12.0


##### プッシュボタンのセッティング #####
pin_open     = 10 
pin_close    = 27
pin_autolock = 9

GPIO.setup(pin_open,GPIO.IN,pull_up_down=GPIO.PUD_UP)
GPIO.setup(pin_close,GPIO.IN,pull_up_down=GPIO.PUD_UP)
GPIO.setup(pin_autolock,GPIO.IN,pull_up_down=GPIO.PUD_UP)


#### グローバル変数(スプレッドシート記入用)
Terminal = 'button'



def press_open_button(pin_number):
    global Terminal
    counter = 0
    #print("GPIO[%d]のコールバックが発生しました" % pin_number)
    while True:
        status = GPIO.input(pin_open)
        if status == 0:
            counter = counter + 1
            if counter >= 10:
                Terminal = 'button'
                print("開錠します")
                open()
                break
        else:
            #print("開錠を取り消します")
            break
        time.sleep(0.001)
    #print(counter)

def press_close_button(pin_number):
    global Terminal
    counter = 0
    #print("GPIO[%d]のコールバックが発生しました" % pin_number)
    while True:
        status = GPIO.input(pin_close)
        if status == 0:
            counter = counter + 1
            if counter >= 10:
                Terminal = 'button'
                print("閉錠します")
                close()
                break
        else:
            #print("閉錠を取り消します")
            break
        time.sleep(0.001)
    #print(counter)

def press_autolock_button(pin_number):
    global Terminal
    counter = 0
    #print("GPIO[%d]のコールバックが発生しました" % pin_number)
    while True:
        status = GPIO.input(pin_autolock)
        if status == 0:
            counter = counter + 1
            if counter >= 10:
                Terminal = 'button'
                print("オートロックします")
                autolock()
                break
        else:
            #print("オートロックを取り消します")
            break
        time.sleep(0.001)
    #\print(counter)    




def open():
    global Terminal
    now = datetime.datetime.today()
    now_date = '{0:%Y-%m-%d}'.format(now)
    now_time = '{0:%H:%M:%S}'.format(now)
    lock_status ='開'
    
    servo = GPIO.PWM(pin_servo, 50)
    servo.start(center)
    time.sleep(0.3)
    servo.ChangeDutyCycle(left)
    time.sleep(0.3)
    servo.ChangeDutyCycle(center)
    time.sleep(0.3)
    servo.stop()

    cmd = ('python3 gsp-homeauto.py 0 {0} {1} {2} {3}'.format(now_date, now_time, Terminal, lock_status))
    subprocess.Popen(cmd.split())



def close():
    global Terminal
    now = datetime.datetime.today()
    now_date = '{0:%Y-%m-%d}'.format(now)
    now_time = '{0:%H:%M:%S}'.format(now)
    lock_status ='閉'
    
    servo = GPIO.PWM(pin_servo, 50)
    servo.start(center)
    time.sleep(0.3)
    servo.ChangeDutyCycle(right)
    time.sleep(0.3)
    servo.ChangeDutyCycle(center)
    time.sleep(0.3)
    servo.stop()

    cmd = ('python3 gsp-homeauto.py 0 {0} {1} {2} {3}'.format(now_date, now_time, Terminal, lock_status))
    subprocess.Popen(cmd.split())



def autolock():
    global Terminal
    now = datetime.datetime.today()
    now_date = '{0:%Y-%m-%d}'.format(now)
    now_time = '{0:%H:%M:%S}'.format(now)
    lock_status ='オートロック'
    cmd = ('python3 gsp-homeauto.py 0 {0} {1} {2} {3}'.format(now_date, now_time, Terminal, lock_status))
    subprocess.Popen(cmd.split())

    open()
    time.sleep(7)
    close()




def on_connect(client, userdata, flags, respons_code):
    print('status {0}'.format(respons_code))


def on_disconnect(client, userdata, flags, respons_code):
    if  respons_code != 0:
        print("Unexpected disconnection.")
    else:
        print('disconect')
        print(respons_code)
    client.loop_stop()
    print('11')


def on_message(client, userdata, msg):

    print(msg.topic + ' ' + str(msg.payload))
    data = json.loads(msg.payload.decode("utf-8"))["data"][0]

    global Terminal
    Terminal = data["terminal"]

    # control
    if (data["device"] == 'lock'):
        if   (data["action"] == 'open'):
            print('鍵を開けます')
            open()
            print('鍵を開けました')
        elif (data["action"] == 'close'):
            print('鍵を閉めます')
            close()
            print('鍵を閉めました')
        else:
            print('unknown message')

    else:
            print('unknown message')

def IC_read():
    global Terminal
    while True:
        felica = libpafe.felica_polling(pasori, FELICA_POLLING_ANY, 0, 0)
        idm = c_ulonglong() 
        libpafe.felica_get_idm.restype = c_void_p
        libpafe.felica_get_idm(felica, byref(idm))
        idm_No = "%016X" % idm.value
        if idm_No in allow_idm_list:
            now = datetime.datetime.today()
            now_date = '{0:%Y-%m-%d}'.format(now)
            now_time = '{0:%H:%M:%S}'.format(now)
            print('Allow: {0}'.format(idm_No))
            Terminal = 'IC_card'
            open()
            #cmd = ('python3 gsp-homeauto.py 2 {0} {1} {2} {3} {4}'.format(now_date, now_time, Terminal, idm_No, "Allow"))
            #subprocess.Popen(cmd.split())
        elif idm_No == '0000000000000000':
            #print('カードをタッチしてください')
            pass
        else:
            now = datetime.datetime.today()
            now_date = '{0:%Y-%m-%d}'.format(now)
            now_time = '{0:%H:%M:%S}'.format(now)
            print('deny: {0}'.format(idm_No))
            Terminal = 'IC_card'
            close()
            #cmd = ('python3 gsp-homeauto.py 2 {0} {1} {2} {3} {4}'.format(now_date, now_time, Terminal, idm_No, "Deny"))
            #subprocess.Popen(cmd.split())
        sleep(1)


if __name__ == '__main__':

    try:
        client = mqtt.Client()
        client.on_connect = on_connect
        client.on_disconnect = on_disconnect
        client.on_message = on_message
        client.username_pw_set('token:%s' % TOKEN)
        client.tls_set(CA_CERTS)
        client.connect(HOST, PORT)
        client.subscribe(TOPIC)

        libpafe = cdll.LoadLibrary("/usr/local/lib/libpafe.so")
        libpafe.pasori_open.restype = c_void_p
        pasori = libpafe.pasori_open()
        libpafe.pasori_init(pasori)
        libpafe.felica_polling.restype = c_void_p
        executor = concurrent.futures.ThreadPoolExecutor(max_workers=1)
        executor.submit(IC_read)

        GPIO.add_event_detect(pin_open, GPIO.FALLING, callback = press_open_button, bouncetime = 1000)
        GPIO.add_event_detect(pin_close, GPIO.FALLING, callback = press_close_button, bouncetime = 1000)
        GPIO.add_event_detect(pin_autolock, GPIO.FALLING, callback = press_autolock_button, bouncetime = 1000)
        
        client.loop_forever()
        

    except KeyboardInterrupt:
        print('finished')
        GPIO.cleanup()

このプログラムを使用するには3か所変更する必要があります。

1か所目と2か所目は “beebotteのセッティング” のところです。
プログラムの最初の方にある “beebotteのセッティング” の

TOKEN = 'token_xxxxxxxxxxx'
TOPIC = 'xxxxxxxx/xxxxxxxx'

を自分の beebotte の値に変更してください。(詳しくはこちらの記事のbeebotteの設定のところを読んでください。)

3か所目は “libpafe設定” のところです。
ここの allow_idm_list のところに使用するICカードの16桁のidm番号(16進数)を入力してください。

allow_idm_list = ['1234567890123456', '112233445566aabbb']

といってもidm番号を知ってる人はいないと思います。このプログラムを実行することでidm番号を確認することができます。

上記の1,2か所目を変更したらプログラムを実行し、ICカードリーダーにICカードをかざしてください。すると、

Deny: 13a57b9c24d68e09

と表示されると思います。この16桁の番号がidm番号なので、この値をallow_idm_listに入力してください。

  

スプレッドシートへのICカードの記載

また、上記のプログラムではコメントアウトしていますが、231,232 241,242行目に記載したようなプログラムを実行することで、

上記の画像のようにタッチされたICカード情報を自動記録することができ、部外者によりタッチされたことも分かるようになります。

スプレッドシートへの記載方法については以下の記事を参照してください。

     

最後に

登録されているICカード( allow_idm_list に記載したICカード)がタッチされると

Allow: 13a57b9c24d68e09

と表示され、鍵が開きます。

一方、登録されていないICカードがタッチされると

Deny: 13a57b9c24d68e09

と表示され、鍵が閉まります。

これにより、ICカードが複数あれば、ICカードを鍵を開ける用と閉める用に振り分けることができます。

google ads




google ads




-電子工作

執筆者:


comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

関連記事

ラズパイでスマートロック作ってみた③ – AmazonDushボタンでラズパイのスマートロックを操作する

大学生の電子工作 ラズパイでスマートロック作ってみたの記事でスマートロックを作成し、現在も使用しているのですが、一つだけ問題点があります。 それは… スマホの充電が切れたら鍵が開けられなくなってしまう …

ラズパイでスマートロック作ってみた② - 扉の開閉状況をGoogleスプレッドシートに記録

以前作成したスマートロックに、扉の開閉状況をGoogleスプレッドシートに記録する、という機能をつけたので、そのやり方について紹介します。   搭載した機能 スイッチで鍵の開閉外部サービス(Googl …

大学生の電子工作 スマートリモコン(回路)

この記事ではスマートリモコンを作ってみたで作成したスマートリモコンの回路について記載していきます。今回作成したスマートリモコンの回路は、 以下の3つからなっています。 赤外線学習回路 赤外線発信回路( …

ラズベリーパイでICカードのデータを読み取る

今回はSONYのICカードリーダー( RC-S320 )を使用して、suicaなどのICカードを読み取り、 idm(ICカードの固有番号、ICタグ)や残高、交通履歴などを取得する方法についてご紹介しま …

壊れたイヤホンを半田ごてを使って直してみた – 修理方法解説

   長年使用していたイヤホンが壊れてしまったので、半田ごてを使用して直してみました。この記事ではイヤホンの直し方について解説します。 (イヤホンの構造によって多少直し方は異なる場合があります。) 今 …