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

じょるブログ

電子工作やプログラミング関連の情報を発信している技術系ブログ

電子工作 ラズベリーパイ

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

投稿日:2019年8月5日 更新日:

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

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

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

などの方法がありますが、財布のみをもって外出してしまった場合、鍵を開ける手段がありません。

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

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

     

搭載した機能

  

実行環境

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

Raspberry Pi4 ModelB 4GB ラズベリーパイ4 技適対応品

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

      

手順

  1. ICカードを読み取るための基本設定
  2. ICカードで鍵を開けるプログラムの作成
  3. スプレッドシートへのICカードの記載

  

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

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

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

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

  

②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




-電子工作, ラズベリーパイ

執筆者:


  1. abiko より:

    スマートロックをラズベリーパイ4で作っています。ICカードでドアを開閉するプログラムを実行するとこのような(以下)エラーが出て解決策を探しています。教えてもらえるとありがたいです。

    >>> %Run pasori_idm2.py
    pasori_idm2.py:36: RuntimeWarning: This channel is already in use, continuing anyway. Use GPIO.setwarnings(False) to disable warnings.
    GPIO.setup(pin_servo, GPIO.OUT)
    Traceback (most recent call last):
    File “/home/pi/pasori/libpafe/tests/pasori_idm2.py”, line 256, in
    client.tls_set(CA_CERTS)
    File “/usr/local/lib/python3.7/dist-packages/paho/mqtt/client.py”, line 831, in tls_set
    context.load_verify_locations(ca_certs)
    FileNotFoundError: [Errno 2] No such file or directory

    *プログラムの方は変えるところ以外は何も変更してはいません*
    よろしくおねがいします。

    • joruji より:

      コメントありがとうございます。
      一番目のGPIOに関するエラーは、二番目のエラーのせいで
      GPIO.cleanup()
      が実行されずにプログラムが終了してしまったために表示されていると思われるので、
      このエラーは無視しても大丈夫です。

      二番目のエラーについてですが、beebotteの証明書である、
      mqtt.beebotte.com.pem
      というファイルがこのプログラムファイル(pasori_idm2.py)と同じフォルダーにないため発生していると思います。
      こちら(https://jorublog.site/electronic-work-smart-lock/)を参考にして、
      プログラムファイルと同じフォルダーに証明書を置いてからプログラムを実行してみてください!

comment

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

CAPTCHA


関連記事

電子工作 ラズパイで玄関モニター(兼防犯カメラ)作ってみた

今回は前回のスマートリモコンに続き、2回目のIoTデバイス制作です。玄関モニター兼防犯カメラを作ってみました。作成難易度はスマートリモコンよりも簡単ですので皆さんも是非作ってみてください! 玄関モニタ …

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

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

ラズパイでスマートロック作ってみた⑤- スプレッドシートをICカードのデータベースとして使用する

    大学生の電子工作 ラズパイでスマートロック作ってみたの記事の⑤つ目の記事です。今回は、前回追加したICカードで鍵を開ける機能のアップデートを行いました。 具体的には、今までラズパイのプログラム …

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

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

簡単にRasberryPi Zero WH へ node.js, npmを入れる方法

  はじめに  スマートリモコンでPS4を操作するためにはps4-wakerというパッケージが必要であり、これをインストールするにはnode.jsのパッケージ管理ツールであるnpmをインストールする必 …




関連記事