[PYTHON] Use your Raspberry Pi to read your student ID number from your student ID card

Introduction

In the laboratory of the university I belong to, the system was built by throwing the fact that the door of the room was unlocked and closed by the ancestor to Slack by pressing the Amazon Dash button. However, the notification did not fly as soon as the internal button reached the end of its life this year. I had an idea to change the button or change the battery, but anyway, if I can check the occupancy status using not only the room door but also the student ID as a development of these in my graduation research, the battery is dead etc. The system will not stop working, and I think that checking the occupancy status will make it easier to manage the keys, so I will collaborate with my friends to check the occupancy status in the laboratory as part of my graduation research. Of the systems, I will be in charge of the system for "reading the student ID number from the student ID card". I will leave it in the article as a memorandum. Even so, the precedents (Shizuoka University and Aizu University 02 / nfcpy% E3% 82% 92% E4% BD% BF% E3% 81% A3% E3% 81% A6% E5% AD% A6% E7% 94% 9F% E8% A8% BC% E3% 81% 8B% E3% 82% 89% E5% AD% A6% E7% B1% 8D% E7% 95% AA% E5% 8F% B7% E3% 82% 92% E8% AA% AD% E3% 81% BF% Since there is an example of E5% 8F% 96% E3% 82% 8B), we built it based on that.)

I'm a complete amateur when it comes to Python. As part of the seminar, I moved it from GPIO to LED or tact switch.

environment

--Server (Raspberry Pi this time)

Build

Since I was provided with Raspberry Pi 4 as a server from the laboratory side this time, I searched for a library for various NFC card readers with Python, and since all articles use nfcpy (there is no other choice) nfcpy I decided to move it in various ways using. Also, most of the card readers used Sony's PaSoRi, so I bought it on my own for research.

Official nfcpy documentation

Construction started in July because the start time was significantly different due to a new virus. At that stage, there was no example of using Raspberry Pi 4, but the result was successful.

Driver related

  1. Insert nfcpy

First, insert nfcpy. It won't start without this.

  1. Recognize PaSoRi

This article has been changed to Reference. You should get an error when you type python -m nfc. Type the following command (long) sudo sh -c 'echo SUBSYSTEM==\"usb\", ACTION==\"add\", ATTRS{idVendor}==\"054c\", ATTRS{idProduct}==\"06c3\", GROUP=\"plugdev\" >> /etc/udev/rules.d/nfcdev.rules' According to the article, port100 is doing something wrong. sudo udevadm control -R sudo modprobe -r port100 sudo sh -c 'echo blacklist port100 >> /etc/modprobe.d/blacklist-nfc.conf' This will prevent port100 from booting. You can recognize PaSoRi by typing python -m nfc.

Now you are ready to read the NFC card reader.

Student ID data reading

After completing the above preparations, I will write a program to read my student ID card.

Dump the data stored on your student ID

NFC cards such as student ID cards do not store data as they are (naturally), so it is necessary to find out in which area the target data is located. Although the target is different, there was a pioneer who wrote a program that dumps in the same way, so here is the code I used it to dump my student ID. The extracted data is as follows, but since it may lead to my personal information as the author, I will omit the part other than the student ID number part which is the core of this time.


Type3Tag 'FeliCa Standard (RC-SA00/1)' ID=0116040086180701 PMM=033242828247AAFF SYS=809E
  System 809E (unknown)
  Area 0000--FFFE
    Area 1000--10FF
      Random Service 64: write with key & read w/o key (0x1008 0x100B)
      Area 2000--20FF
      Random Service 128: write with key & read w/o key (0x2008 0x200B)
       0000: XX XX XX XX 32 31 31 35 00 00 00 00 00 00 00 00 |*XXX2115........|
      Area 3000--30FF
      Random Service 192: write with key & read w/o key (0x3008 0x300B)
      Area 4000--40FF
      Random Service 256: write with key & read w/o key (0x4008 0x400B)
  System FE00 (Common Area)
  Area 0000--FFFE
    Area 1A80--1AFF
      Area 1A81--1AFF
        Random Service 106: write with key & read w/o key (0x1A88 0x1A8B)

Looking at the above results, it was found that our university stores it as an ASCII code in the service code 0x200B of the system code: 0x809E (If you give out the student ID number as it is, it will lead to personal injury, so the first 4 characters are hidden. Therefore, when you read the NFC card, you can get the student ID number by reading out those block codes and extracting them.

Read NFC

Below is a program that reads the student ID number using nfcpy.

read_nfc.py


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

import sys
import binascii
import nfc

#Service code that stores the student ID number of our student ID card
service_code = 0x200B

def connected(tag):

    if isinstance(tag, nfc.tag.tt3.Type3Tag):
        try:
            #16-bit service_code to service>>Extract the upper 10 bits with 6 and service_code &&Extract the lower 6 bits with 0x3f
            svcd = nfc.tag.tt3.ServiceCode(service_code >> 6, service_code & 0x3f)
            #service is read_without_encryption argument service_Index in list
            blcd = nfc.tag.tt3.BlockCode(0,service=0)
            #read_without_Read the block data in the information of the specified part of the tag by encryption
            block_data = tag.read_without_encryption([svcd], [blcd])
            #This time, it is stored in the 1st to 8th characters of the block data, it is converted to a character string and utf-Decode at 8
            student_id = str(block_data[0:8].decode("utf-8"))
            print(student_id)
        except Exception as e:
            print("Error:%s" % e)
    else:
        print("Error:tag isn't Type3Tag")
    
    #If the value is returned as True, it will be processed only once until it is touched and released.
    return True

clf = nfc.ContactlessFrontend('usb')

def main():
    while True:
        #Wait until you read your student ID
        clf.connect(rdwr={'on-connect': connected,})

try:
    main()
except KeyboardInterrupt:
    print("Forced termination")
    clf.close()
    sys.exit(0)

To be honest, I can't do much commentary because of lack of skills, but it's a memorandum, so it's a personal memo. Reference

First of all, clf = nfc.ContactlessFrontend ('usb') means to open an NFC reader with a USB connection, which is just a declaration to use PaSoRi. Start the NFC card reader with clf.connect and wait until the NFC touch is done. Among the arguments of connect, there are callbacks such as on-startup at startup, on-connect when touched, and on-release when the card is released. By specifying a callback function for each, the behavior can be changed by the action. This time, specify the function connected (tag) for on-connect. In the connected that is called when the card is touched to the reader, a tag that represents the object of that tag is passed. After that, the tag is used to communicate with the NFC tag.

The NFC service code itself is a 16-bit value, with the upper 10 bits being the service number and the lower 6 bits being the attribute value. In this case, since the service code to be examined has already been obtained (0x200B), there is a high possibility that it will work even if you do not put it in the honest variable, and it seems that you do not need to take extra memory, but when using multiple service codes I think it will be more efficient to look up using an array. nfc.tag.tt3.ServiceCode (service_code >> 6, service_code & 0x3f) is a way to create a ServiceCode object from a 16-bit integer service. Extract the upper 10 bits with service_code >> 6. Extract the lower 6 bits with service_code & 0x3f.

Next, I will read the data block, but the document of read_without_encryption According to this, service = 0 passed when generating the Blockcode is not the service code itself, but the index in the argument service_list of the argument of read_without_encryption. Each service has a block with a size of 16 bytes, and serial numbers are assigned from 0 in the service. In this case, it is in the 0th to 7th, but if you set student_id = str (block_data [0: 8] .decode ("utf-8 ")) here, the last data will be Be careful as it will be cut off. Regarding the character code, I think it depends on the OS used in the system, but our student ID card is Shift_JIS (~~ I want you to perish ~~), and there are too many inconveniences for Linux systems such as Raspberry OS. , Basically, it is safe to decode to utf-8.

Finally, if the return value of connected is set to True, processing will be performed only once until the card is touched and released. On the contrary, if it is False, the process of reading it will occur many times, so it will be inconvenient for this system, so let's set it to True properly.

Finally

This time I started from a state where I didn't know much about Python, so I wrote the program with great reference to the source article, but it works unexpectedly. Since it is still in the prototype stage, we will make various improvements so that it can be announced as a graduation research.

Postscript

(2020/10/16 19:36) I received a report that there was a part where I forgot to hide the block data, so I reflected it.

Recommended Posts

Use your Raspberry Pi to read your student ID number from your student ID card
Output from Raspberry Pi to Line
How to use Raspberry Pi pie camera Python
Connect your Raspberry Pi to your smartphone using Blynk
From setting up Raspberry Pi to installing Python environment
How to use the Raspberry Pi relay module Python
[Go language] Use OpenWeatherMap and Twitter API to regularly tweet weather information from Raspberry Pi
How to get temperature from switchBot thermo-hygrometer using raspberry Pi
Introduced python3-OpenCV3 to Raspberry Pi
I talked to Raspberry Pi
Introducing PyMySQL to raspberry pi3
Use NeoPixel on Raspberry Pi
About the error I encountered when trying to use Adafruit_DHT from Python on a Raspberry Pi
Let's access your Raspberry Pi from outside your home with VPN (WireGuard)
How to use Visual Recognition to get LINE ID from a girl
Use python on Raspberry Pi 3 to illuminate the LED (Hello World)
A memo when connecting bluetooth from a smartphone / PC to Raspberry Pi 4
I made an npm package to get the ID of the IC card with Raspberry Pi and PaSoRi
Port FreeRTOS to Raspberry Pi 4B
Use vl53l0x with Raspberry Pi (python)
How to use SWIG from waf
Read and use Python files from Python
[Raspberry Pi] Changed Python default to Python3
Use BME280 temperature / humidity / barometric pressure sensor from Python on Raspberry Pi 2
A memo to simply use the illuminance sensor TSL2561 with Raspberry Pi 2
Use Raspberry Pi to solve the problem of insufficient mobile Wi-Fi connection
Use python on Raspberry Pi 3 to light the LED with switch control!
Make it possible to read .eml from your smartphone using discord bot