shimodashのアイコン画像
shimodash 2024年12月15日作成 (2024年12月21日更新) © MIT
製作品 製作品 閲覧数 129
shimodash 2024年12月15日作成 (2024年12月21日更新) © MIT 製作品 製作品 閲覧数 129

NFCタグとLTEモジュールを使った外出先見守りシステム

NFCタグとLTEモジュールを使った外出先見守りシステム

はじめに

お子様や高齢者の外出を見守りたいと思った時に、真っ先に思いつくのはスマホのGPS機能
だと思います。
ただ、スマホも昔ほど安く手に入れる事ができなくなりました。そんな時に外出時にNFCタグや
カードを持ってもらい、外出先のモジュールにタッチしてもらい、居場所をなんとなく把握できる
システムをSpresenseを使って製作してみました。

全体像

お住まいの地域の公園、スーパーマーケットなどに、Spresenseを搭載したNFC読み取り機を設置します。
NFCをそこにタッチすると、LTE経由でNFCの情報がクラウドに集まります。
外出を見守る方は、クラウド情報を確認することで、お出かけの方がどこにいるかが把握できます。

システム概要

部品リスト

No 名称 入手先 備考
1 Spresense メインボード コンテスト提供品
2 LTEボード コンテスト提供品
3 NFCカードリーダー pn532 Aliexpress
4 OLED-LCD 128x32 Aliexpress ドライバICがSSD1306のもの
5 各種接続ケーブル 秋月電子など
6 soracom-Simカード SORACOM planX3を使用

なお、筐体は3Dプリンタで作成

基板接続

LTEボードのピンヘッダのI2C端子をそれぞれのモジュールとつなぎます。
LTEボードのI2CはPWM2,3と排他使用になっています。

LTEボード NFC address 0x24 OLED address 0x3c
3.3V VCC VCC
GND GND GND
PWM2 SCL SCK
PWM3 SDA SDA

キャプションを入力できます

スケッチ

/**************************************************************************/ /*! This example will wait for any ISO14443A card or tag, and depending on the size of the UID will attempt to read from it. If the card has a 4-byte UID it is probably a Mifare Classic card, and the following steps are taken: - Authenticate block 4 (the first block of Sector 1) using the default KEYA of 0XFF 0XFF 0XFF 0XFF 0XFF 0XFF - If authentication succeeds, we can then read any of the 4 blocks in that sector (though only block 4 is read here) If the card has a 7-byte UID it is probably a Mifare Ultralight card, and the 4 byte pages can be read directly. Page 4 is read by default since this is the first 'general- purpose' page on the tags. To enable debug message, define DEBUG in PN532/PN532_debug.h */ /**************************************************************************/ /*i2c scanner log I2C Scanning... -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -A -B -C -D -E -F 0- : -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 1- : -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 2- : -- -- -- -- 24 -- -- -- -- -- -- -- -- -- -- -- 3- : -- -- -- -- -- -- -- -- -- -- -- -- 3c -- -- -- 4- : -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 5- : -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 6- : -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 7- : -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- the number of found I2C devices is 2. */ #if 0 #include <SPI.h> #include <PN532_SPI.h> #include "PN532.h" PN532_SPI pn532spi(SPI, 10); PN532 nfc(pn532spi); #elif 0 #include <PN532_HSU.h> #include <PN532.h> PN532_HSU pn532hsu(Serial1); PN532 nfc(pn532hsu); #else #include <Wire.h> #include <PN532_I2C.h> #include <PN532.h> PN532_I2C pn532i2c(Wire1); PN532 nfc(pn532i2c); #endif #include <SPI.h> // #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 32 // OLED display height, in pixels // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) // The pins for I2C are defined by the Wire-library. // On an arduino UNO: A4(SDA), A5(SCL) // On an arduino MEGA 2560: 20(SDA), 21(SCL) // On an arduino LEONARDO: 2(SDA), 3(SCL), ... #define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin) #define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32 Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire1, OLED_RESET); //LTE setting #include <LTE.h> // APN name #define APP_LTE_APN "soracom.io" // replace your APN /* APN authentication settings * Ignore these parameters when setting LTE_NET_AUTHTYPE_NONE. */ #define APP_LTE_USER_NAME "sora" // replace with your username #define APP_LTE_PASSWORD "sora" // replace with your password // APN IP type #define APP_LTE_IP_TYPE (LTE_NET_IPTYPE_V4V6) // IP : IPv4v6 // #define APP_LTE_IP_TYPE (LTE_NET_IPTYPE_V4) // IP : IPv4 // #define APP_LTE_IP_TYPE (LTE_NET_IPTYPE_V6) // IP : IPv6 // APN authentication type #define APP_LTE_AUTH_TYPE (LTE_NET_AUTHTYPE_CHAP) // Authentication : CHAP // #define APP_LTE_AUTH_TYPE (LTE_NET_AUTHTYPE_PAP) // Authentication : PAP // #define APP_LTE_AUTH_TYPE (LTE_NET_AUTHTYPE_NONE) // Authentication : NONE /* RAT to use * Refer to the cellular carriers information * to find out which RAT your SIM supports. * The RAT set on the modem can be checked with LTEModemVerification::getRAT(). */ #define APP_LTE_RAT (LTE_NET_RAT_CATM) // RAT : LTE-M (LTE Cat-M1) // #define APP_LTE_RAT (LTE_NET_RAT_NBIOT) // RAT : NB-IoT // initialize the library instance LTE lteAccess; LTEScanner scannerNetworks; LTEUDP lteUdp; char host[] = "harvest.soracom.io"; int port = 8514; int ad_value = 0; String readFromSerial() { /* Read String from serial monitor */ String str; int read_byte = 0; while (true) { if (Serial.available() > 0) { read_byte = Serial.read(); if (read_byte == '\n' || read_byte == '\r') { Serial.println(""); break; } Serial.print((char)read_byte); str += (char)read_byte; } } return str; } void readApnInformation(char apn[], LTENetworkAuthType *authtype, char user_name[], char password[]) { /* Set APN parameter to arguments from readFromSerial() */ String read_buf; while (strlen(apn) == 0) { Serial.print("Enter Access Point Name:"); readFromSerial().toCharArray(apn, LTE_NET_APN_MAXLEN); } while (true) { Serial.print("Enter APN authentication type(CHAP, PAP, NONE):"); read_buf = readFromSerial(); if (read_buf.equals("NONE") == true) { *authtype = LTE_NET_AUTHTYPE_NONE; } else if (read_buf.equals("PAP") == true) { *authtype = LTE_NET_AUTHTYPE_PAP; } else if (read_buf.equals("CHAP") == true) { *authtype = LTE_NET_AUTHTYPE_CHAP; } else { /* No match authtype */ Serial.println("No match authtype. type at CHAP, PAP, NONE."); continue; } break; } if (*authtype != LTE_NET_AUTHTYPE_NONE) { while (strlen(user_name)== 0) { Serial.print("Enter username:"); readFromSerial().toCharArray(user_name, LTE_NET_USER_MAXLEN); } while (strlen(password) == 0) { Serial.print("Enter password:"); readFromSerial().toCharArray(password, LTE_NET_PASSWORD_MAXLEN); } } return; } void setup(void) { // LTE char apn[LTE_NET_APN_MAXLEN] = APP_LTE_APN; LTENetworkAuthType authtype = APP_LTE_AUTH_TYPE; char user_name[LTE_NET_USER_MAXLEN] = APP_LTE_USER_NAME; char password[LTE_NET_PASSWORD_MAXLEN] = APP_LTE_PASSWORD; Serial.begin(115200); Serial.println("Hello!"); nfc.begin(); // Show initial display buffer contents on the screen -- // the library initializes this with an Adafruit splash screen. display.display(); delay(1000); // Pause for 2 seconds uint32_t versiondata = nfc.getFirmwareVersion(); if (! versiondata) { Serial.print("Didn't find PN53x board"); display.clearDisplay(); // Draw a single pixel in white display.setTextSize(1); display.setTextColor(SSD1306_WHITE); // Draw white text display.setCursor(0,0); // Start at top-left corner // display.println(address); display.println("Didn't find PN53x board"); display.display(); while (1); // halt } // Got ok data, print it out! Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX); Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC); Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC); // configure board to read RFID tags nfc.SAMConfig(); Serial.println("Waiting for an ISO14443A Card ..."); // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) { Serial.println(F("SSD1306 allocation failed")); for(;;); // Don't proceed, loop forever } // Show initial display buffer contents on the screen -- // the library initializes this with an Adafruit splash screen. display.display(); delay(2000); // Pause for 2 seconds // Clear the buffer display.clearDisplay(); // Draw a single pixel in white display.drawPixel(10, 10, SSD1306_WHITE); display.drawPixel(20, 10, SSD1306_WHITE); display.drawPixel(30, 10, SSD1306_WHITE); display.display(); delay(2000); /* Set if Access Point Name is empty */ if (strlen(APP_LTE_APN) == 0) { Serial.println("This sketch doesn't have a APN information."); readApnInformation(apn, &authtype, user_name, password); } Serial.println("=========== APN information ==========="); Serial.print("Access Point Name : "); Serial.println(apn); Serial.print("Authentication Type: "); Serial.println(authtype == LTE_NET_AUTHTYPE_CHAP ? "CHAP" : authtype == LTE_NET_AUTHTYPE_NONE ? "NONE" : "PAP"); if (authtype != LTE_NET_AUTHTYPE_NONE) { Serial.print("User Name : "); Serial.println(user_name); Serial.print("Password : "); Serial.println(password); } while (true) { /* Power on the modem and Enable the radio function. */ if (lteAccess.begin() != LTE_SEARCHING) { Serial.println("Could not transition to LTE_SEARCHING."); Serial.println("Please check the status of the LTE board."); for (;;) { sleep(1); } } /* The connection process to the APN will start. * If the synchronous parameter is false, * the return value will be returned when the connection process is started. */ if (lteAccess.attach(APP_LTE_RAT, apn, user_name, password, authtype, APP_LTE_IP_TYPE) == LTE_READY) { Serial.println("attach succeeded."); break; } /* If the following logs occur frequently, one of the following might be a cause: * - APN settings are incorrect * - SIM is not inserted correctly * - If you have specified LTE_NET_RAT_NBIOT for APP_LTE_RAT, * your LTE board may not support it. * - Rejected from LTE network */ Serial.println("An error has occurred. Shutdown and retry the network attach process after 1 second."); lteAccess.shutdown(); sleep(1); } display.clearDisplay(); // Draw a single pixel in white display.setTextSize(2); display.setTextColor(SSD1306_WHITE); // Draw white text display.setCursor(0,0); // Start at top-left corner // display.println(address); display.println("Setup OK!!"); display.display(); delay(2000); } void loop(void) { uint8_t success; uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type) // Wait for an ISO14443A type cards (Mifare, etc.). When one is found // 'uid' will be populated with the UID, and uidLength will indicate // if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight) success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength); if (success) { // Display some basic information about the card Serial.println("Found an ISO14443A card"); Serial.print(" UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes"); Serial.print(" UID Value: "); nfc.PrintHex(uid, uidLength); drawID(uid,uidLength); udpsend(uid,uidLength); Serial.println(""); if (uidLength == 4) { // We probably have a Mifare Classic card ... Serial.println("Seems to be a Mifare Classic card (4 byte UID)"); // Now we need to try to authenticate it for read/write access // Try with the factory default KeyA: 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF Serial.println("Trying to authenticate block 4 with default KEYA value"); uint8_t keya[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; // Start with block 4 (the first block of sector 1) since sector 0 // contains the manufacturer data and it's probably better just // to leave it alone unless you know what you're doing success = nfc.mifareclassic_AuthenticateBlock(uid, uidLength, 4, 0, keya); if (success) { Serial.println("Sector 1 (Blocks 4..7) has been authenticated"); uint8_t data[16]; // If you want to write something to block 4 to test with, uncomment // the following line and this text should be read back in a minute // data = { 'a', 'd', 'a', 'f', 'r', 'u', 'i', 't', '.', 'c', 'o', 'm', 0, 0, 0, 0}; // success = nfc.mifareclassic_WriteDataBlock (4, data); // Try to read the contents of block 4 success = nfc.mifareclassic_ReadDataBlock(4, data); if (success) { // Data seems to have been read ... spit it out Serial.println("Reading Block 4:"); nfc.PrintHexChar(data, 16); Serial.println(""); // Wait a bit before reading the card again delay(1000); } else { Serial.println("Ooops ... unable to read the requested block. Try another key?"); } } else { Serial.println("Ooops ... authentication failed: Try another key?"); } } if (uidLength == 7) { // We probably have a Mifare Ultralight card ... Serial.println("Seems to be a Mifare Ultralight tag (7 byte UID)"); // Try to read the first general-purpose user page (#4) Serial.println("Reading page 4"); uint8_t data[32]; success = nfc.mifareultralight_ReadPage (4, data); if (success) { // Data seems to have been read ... spit it out nfc.PrintHexChar(data, 4); Serial.println(""); // Wait a bit before reading the card again delay(1000); } else { Serial.println("Ooops ... unable to read the requested page!?"); } } } drawLTEinfo(); } void drawLTEinfo() { // Assigned IP address IPAddress address = lteAccess.getIPAddress(); Serial.print("IP address: "); Serial.println(address); // currently connected carrier Serial.print("Current carrier: "); Serial.println(scannerNetworks.getCurrentCarrier()); // return signal strength Serial.print("Signal Strength: "); Serial.print(scannerNetworks.getSignalStrength()); Serial.println(" [dBm]"); display.clearDisplay(); display.setTextColor(SSD1306_WHITE); // Draw white text display.setCursor(0,0); // Start at top-left corner // display.println(address); display.setTextSize(2); display.print("Touch"); display.setTextSize(1); display.setCursor(64,8); display.println("Your Card"); display.println(scannerNetworks.getCurrentCarrier()); display.println(scannerNetworks.getSignalStrength()); display.display(); } void drawID(uint8_t uid[],int uidlength) { char buf[1]; display.clearDisplay(); display.setTextSize(2); // Normal 1:1 pixel scale display.setTextColor(SSD1306_WHITE); // Draw white text display.setCursor(0,0); // Start at top-left corner // display.println(F(nfc.PrintHex(uid, uidLength))); display.println(F("touch!")); String str = (const char*)uid; display.setTextSize(1); // Normal 1:1 pixel scale display.print("ID:"); for(int i=0;i<uidlength;i++){ // display.print(String(uid[i],HEX)); sprintf(buf,"%02x",uid[i]); display.print(buf); } // display.println((String)uid); display.display(); } void udpsend(uint8_t uid[],int uidlength) { Serial.println("UDP Send Start"); Serial.print("uidlength:"); Serial.println(uidlength); if (lteUdp.begin(port) == 1) { if (lteUdp.beginPacket(host, port) == 1) { Serial.println("UDP Data make Start"); // uint8ToHexString(uid, uidlength, hexString, sizeof(hexString)); char ad_str[10]; // char * ad_str = (const char *)uid; sprintf(ad_str, "%02x%02x%02x%02x", uid[0],uid[1],uid[2],uid[3]); // lteUdp.write(ad_str, uidlength); lteUdp.write(ad_str, 8); // lteUdp.write(hexString, 21); // lteUdp.write(output, 9); if (lteUdp.endPacket() == 1) { Serial.println("UDP Data Send OK"); delay(100); } else { Serial.println("UDP Data Send NG(endPacket)"); } } else { Serial.println("UDP Data make NG(beginPacket)"); } lteUdp.stop(); Serial.println("UDP Send Stop"); } }

SORACOM設定

クラウド側でデータを受信するために、SORACOM Harvestの設定を行います。
SORACOMはconsole.ioというサービスで設定がweb上で可能です。
詳細は、SORACOMのページをご確認ください。

  1. web上のメニューボタンを押すと以下の画面になり SIM管理を選びます
    キャプションを入力できます

  2. Simグループが設定されていない場合は、任意のグループ名で作成します。
    キャプションを入力できます

  3. グループができたら、メニュー画面に戻りSIMグループを選択すると
    下の方にある、SORACOM Harvest Data 設定をONにします。
    キャプションを入力できます

  4. SORACOM Harvest Dataの画面でSpresenseLTEから送信されたデータが確認できます。
    1次処理済みデータにNFCカードのIDが登録されています。
    キャプションを入力できます

参照URL

モーターの音からAIで異常検知 - IoTレシピ
https://ja.stackoverflow.com/questions/80455/lte拡張ボードの-i2c-を-arduino-で使用するには
https://docs.neqto.com/docs/ja/spresense-series/hardware/about_spresense#spresense-lte-m

最後に

動作させた動画を共有します。

ここに動画が表示されます

工夫したいところ

  • クラウドへの送信データにGPS情報を載せたい。
  • マイク機能やスピーカ機能を使い、タッチした時の音声を出したい。

LTEモジュールのご提供ありがとうございました。

shimodashのアイコン画像
会社員をしています。 Myms-techという活動名で、子供向けの電子工作ワークショップを しています。 URLは https://shimodash.github.io/Myms-tech facebookは https://www.facebook.com/mymstech twitterは https://twitter.com/shimodash_home もしよかったらSNSフォローを ※発言は個人的なものです。
ログインしてコメントを投稿する