Overview

RFID tags provide a simple and cost effective way to trigger an action. By either using a credit card sized tag or keychain fob, the Internet of LEGO city can respond in a number of ways. For instance, a card ID can unlock a door, grant access to the train system or record an identity.


As a side bonus, my two year old loves playing with these RFID tags! So, I built a fun project that makes sounds, flashes lights and enables various functions within the IoL City. I built a LEGO box to contain the components, used an ESP8266 dev board for the electronics and send the messages over WiFi using MQTT. Node-RED then acts as the orchestrator to verify the card and trigger an action.

Components

  • Microcontroller w/ WiFi
    • WeMos D1-mini
      • The D1 mini is a mini WiFi board based on ESP-8266EX.
        • Buy it
        • 11 digital input/output pins, all pins have interrupt/pwm/I2C/one-wire supported(except D0)
        • 1 analog input(3.2V max input)
        • a Micro USB connection
        • Compatible with Arduino
        • Compatible with nodemcu
        • lots of shields
          WeMos D1-Mini
  • RFID
    • MF-RC522
      • “The MFRC522 is a highly integrated reader/writer IC for contactless communication at 13.56 MHz. The MFRC522 reader supports ISO/IEC 14443 A/MIFARE and NTAG.”
    • More Info

RFID RC522 with dongle and card

  • MQTT Client
    • Homie
      • “Homie for ESP8266 is an ESP8266 for Arduino implementation ofHomie, a thin and simple MQTT convention for the IoT. More than that, it’s also a full-featured framework to get started with your IoT project very quickly. Simply put, you don’t have to manage yourself the connection/reconnection to the Wi-Fi/MQTT. You don’t even have to hard-code credentials in your sketch: this can be done using a simple JSON API. Everything is handled internally, by Homie for ESP8266.”
  • MQTT Broker
    • Mosquitto
      • “Eclipse Mosquitto™ is an open source (EPL/EDL licensed) message broker that implements the MQTT protocol versions 3.1 and 3.1.1. MQTT provides a lightweight method of carrying out messaging using a publish/subscribe model. This makes it suitable for “Internet of Things” messaging such as with low power sensors or mobile devices such as phones, embedded computers or microcontrollers like the Arduino.”
  • Server
    • Raspberry Pi
      • “The Raspberry Pi is a tiny and affordable computer that you can use to learn programming through fun, practical projects.”

Pi2ModB1GB_-comp

  • IoT programming environment
    • Node-RED
      • “Node-RED is a tool for wiring together hardware devices, APIs and online services in new and interesting ways.”

node-red-title-flow

Construction

Circuit

This wiring diagram and sample Arduino code was the basis for the circuit. I then added a reset button, speaker and two LEDs to the ports specified in the code.

More info

MFRC522-ESP8266_wiring

LEGO Box

The LEGO box was constructed with solid base plate and long technic bricks for strength. A panel opens up to expose the WeMos D1 connections. The RFID tag was held in place with a little bit of Blu Tack.

MQTT w/ Homie

Many IoT projects use MQTT as a Publish/Subscription way of communicating. This can easily be implemented on an Arduino compatible system using a simplepubsublclient library developed by Nick o’Leary.

This project hopes to expand beyond simply using MQTT, by appreciating some sense of standard for scalability and maintenance. This is how I discovered theHomie convention, developed by Marvin Roger. What’s nice about this implementation is that it handles many of the tedious admin tasks for managing the connection, sending updates, storing state, OTA, and initializing the device with the network specific configurations.

Getting started with Homie

This project uses a WeMos D1-Mini, which will support the ESP8266 version. By including this library in the code, the device will boot up in a special configuration mode. It will then advertise its own WiFi SSID, which you must first join to configured. At that point, you can either use the API, web page or Android App to push the network and device settings. These configurations include the name of the device, MQTT broker, base topic, and WiFi settings.

I’ve used web based configuration assistant to get started.

  1. Download the web UI
  2. Turn on the Arduino/ESP device, and connect to its SSID “Homie-aabbccdd”, where the password and specific name are that of the MAC address. So, I would use “aabbccdd” as the password in this example.
  3. Once connected to the SSID, open the index.html file that is contained in the web UI download. This will run a local web application to scan for the Homie device and provide a setup guide.

 

 

Firmware

Download Code from GitHub (includes pitches.h)

This firmware implements Homie to deliver RFID scan results via MQTT. Two LEDs and a speaker are attached to the WeMos D1-mini, for user feedback.

One unique style of this code is that the setup() and loop() functions are used to begin the setupHandler() and loopHandler() functions, for Homie. The reason for this is that Homie will keep track of the connection state and manage the state of the various properties. Its been advised to avoid any sort of blocking activity (i.e.delay(1000)) within the standard loop() function to avoid disrupting the network mechanics.

  1. void setup() {
  2. Homie.setFirmware(“rfid”“1.0.0”);
  3. Homie.registerNode(rfidNode);
  4. Homie.setSetupFunction(setupHandler);
  5. Homie.setLoopFunction(loopHandler);
  6. rfidNode.subscribe(“validate”, verifyHandler);
  7. Homie.setup();
  8. }
  9. void loop() {
  10. Homie.loop();
  11. }

The actual scanning of the RFID card is handled by three functions. Within each loop iteration, the RFID scanner looks for a card then prints the UID from its buffer to a byte array.

  1. // Select one of the cards
  2. if ( ! mfrc522.PICC_ReadCardSerial()) {
  3. Serial.print(“found card…”);
  4. delay(50);
  5. return;
  6. }
  1. // Process card
  2. Serial.print(F(“Card UID:”));
  3. dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size);
  4. }
  1. // RFID: dump a byte array as hex values to Serial, then send to validation routine.
  2. void dump_byte_array(byte *buffer, byte bufferSize) {
  3. String uid;
  4. const long interval = 1000;
  5. for (byte i = 0; i < bufferSize; i++) {
  6. Serial.print(buffer[i] < 0x10 ? ” 0″ : ” “);
  7. Serial.print(buffer[i], HEX);
  8. uid = uid + String(buffer[i], HEX);
  9. }
  10. if(uid){
  11. validate(uid);
  12. }
  13. }

The Full Code will pull in the Homie library and a pitches.h library. The pitches file simply maps western musical tones (i.e. a piano range) to frequencies for easy incorporation into projects with sound.

The code is heavily commented and the functions are typically in the order of execution, where possible. Much of the code is cluttered with turning on lights and sounds (which could be endlessly tweaked and I’m guilty of wasting too much time on that).

  1. /*
  2. * RFID Scanner with audio and lights
  3. *
  4. * Communication via WiFi & MQTT using Homie.h
  5. * The ID will be sent to the MQTT topic.
  6. * When a success verification occurs, the lights and speaker will be activated
  7. * depending on the value.
  8. *
  9. *
  10. * Written by Cory Guynn
  11. * www.InternetOfLEGO.com
  12. * 2016
  13. *
  14. */
  15. // Networking – MQTT using Homie
  16. // https://github.com/marvinroger/homie/tree/master
  17. #include <Homie.h>
  18. HomieNode rfidNode(“RFID-1”“sensor”);
  19. // Audio
  20. #include “pitches.h”
  21. // RFID
  22. #include “MFRC522.h”
  23. #define RST_PIN 15 // RST-PIN for RC522 – RFID – SPI – Modul GPIO15
  24. #define SS_PIN 2 // SDA-PIN for RC522 – RFID – SPI – Modul GPIO2
  25. MFRC522 mfrc522(SS_PIN, RST_PIN)// Create MFRC522 instance
  26. // LEDs and Speaker
  27. const int PIN_RESET = 0; //D3 WeMos ~ This pin will flash WeMos when held low 5s
  28. const int PIN_RED = 16//D0 WeMos
  29. const int PIN_GREEN = 15//D8 WeMos
  30. const int PIN_SPEAKER = 5//D1 WeMos
  31. // Standard Functions
  32. void setup() {
  33. Homie.setFirmware(“rfid”“1.0.0”);
  34. Homie.registerNode(rfidNode);
  35. Homie.setSetupFunction(setupHandler);
  36. Homie.setLoopFunction(loopHandler);
  37. rfidNode.subscribe(“validate”, verifyHandler);
  38. Homie.setup();
  39. }
  40. void loop() {
  41. // all loop activity is handled by Homie, to ensure connectivity and prevent blocking activity that could disrupt communication
  42. Homie.loop();
  43. }
  44. void setupHandler() {
  45. // this replaces the traditional “setup()” to ensure connecitvity and handle OTA
  46. // RFID and Console
  47. Serial.begin(9600)// Initialize serial communications
  48. SPI.begin()// Init SPI bus
  49. mfrc522.PCD_Init()// Init MFRC522
  50. // sound beep
  51. tone(PIN_SPEAKER,NOTE_C1,250);
  52. delay(50);
  53. tone(PIN_SPEAKER,NOTE_E1,250);
  54. delay(50);
  55. tone(PIN_SPEAKER,NOTE_C1,250);
  56. delay(50);
  57. noTone(PIN_SPEAKER);
  58. // initialize LEDs
  59. pinMode(PIN_RED, OUTPUT);
  60. pinMode(PIN_GREEN, OUTPUT);
  61. digitalWrite(PIN_RED, HIGH);
  62. digitalWrite(PIN_GREEN, HIGH);
  63. delay(1000);
  64. digitalWrite(PIN_GREEN, LOW);
  65. }
  66. // Global Timer
  67. unsigned long previousMillis = 0;
  68. int interval = 2000;
  69. void loopHandler() {
  70. // Look for new RFID cards
  71. if ( ! mfrc522.PICC_IsNewCardPresent()) {
  72. //Serial.print(“scanning”);
  73. delay(50);
  74. return;
  75. }
  76. // scan the cards. Put in a non-blocking delay to avoid duplicate readings
  77. unsigned long currentMillis = millis();
  78. if (currentMillis – previousMillis >= interval) {
  79. previousMillis = currentMillis;
  80. // do non-blocking thing here
  81. // Select one of the cards
  82. if ( ! mfrc522.PICC_ReadCardSerial()) {
  83. Serial.print(“found card…”);
  84. delay(50);
  85. return;
  86. }
  87. // Process card
  88. Serial.print(F(“Card UID:”));
  89. dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size);
  90. }
  91. }
  92. // RFID: dump a byte array as hex values to Serial, then send to validation routine.
  93. void dump_byte_array(byte *buffer, byte bufferSize) {
  94. String uid;
  95. const long interval = 1000;
  96. for (byte i = 0; i < bufferSize; i++) {
  97. Serial.print(buffer[i] < 0x10 ? ” 0″ : ” “);
  98. Serial.print(buffer[i], HEX);
  99. uid = uid + String(buffer[i], HEX);
  100. }
  101. if(uid){
  102. validate(uid);
  103. }
  104. }
  105. // validate card UID by sending to server via MQTT
  106. void validate(String uid){
  107. Serial.print(“validating card: “);
  108. Serial.println(uid);
  109. // set RFID uid property to be sent via MQTT
  110. Homie.setNodeProperty(rfidNode, “uid”, uid, true);
  111. // Turn both LEDs on
  112. digitalWrite(PIN_RED, HIGH);
  113. digitalWrite(PIN_GREEN, HIGH);
  114. // play sounds
  115. tone(PIN_SPEAKER,NOTE_D1,50);
  116. delay(20);
  117. tone(PIN_SPEAKER,NOTE_D1,50);
  118. noTone(PIN_SPEAKER);
  119. digitalWrite(PIN_GREEN, LOW);
  120. }
  121. // Receive response from server via MQTT
  122. bool verifyHandler(String response) {
  123. Serial.print(“verifyHandler “);
  124. Serial.println(response);
  125. tone(PIN_SPEAKER,NOTE_C3,100);
  126. digitalWrite(PIN_RED, LOW);
  127. digitalWrite(PIN_GREEN, LOW);
  128. delay(250);
  129. if (response == “granted”) {
  130. Serial.println(“card accepted”);
  131. Homie.setNodeProperty(rfidNode, “validate”“granted”true);
  132. digitalWrite(PIN_GREEN, HIGH);
  133. tone(PIN_SPEAKER,NOTE_C3,250);
  134. delay(250);
  135. tone(PIN_SPEAKER,NOTE_C4,500);
  136. noTone(PIN_SPEAKER);
  137. delay(1000);
  138. digitalWrite(PIN_GREEN, LOW);
  139. } else if (response == “denied”) {
  140. Serial.print(“card denied”);
  141. Homie.setNodeProperty(rfidNode, “validate”“denied”true);
  142. digitalWrite(PIN_RED, HIGH);
  143. tone(PIN_SPEAKER,NOTE_C3,250);
  144. delay(250);
  145. digitalWrite(PIN_RED, LOW);
  146. tone(PIN_SPEAKER,NOTE_G2,500);
  147. delay(250);
  148. noTone(PIN_SPEAKER);
  149. digitalWrite(PIN_RED, HIGH);
  150. delay(1000);
  151. } else {
  152. digitalWrite(PIN_RED, HIGH);
  153. Serial.println(“unexpected response: “);
  154. Homie.setNodeProperty(rfidNode, “validate”“unexpected”true);
  155. Serial.print(response);
  156. tone(PIN_SPEAKER,NOTE_A2,500);
  157. delay(250);
  158. digitalWrite(PIN_RED, LOW);
  159. tone(PIN_SPEAKER,NOTE_A2,500);
  160. return false;
  161. }
  162. digitalWrite(PIN_RED, HIGH);
  163. return true;
  164. }

 

Node-RED

Flow

Download Flow

This Node-RED flow demonstrates various ways of using the RFID uid to trigger workflows and to send access messages back to the RFID scanner.

Node-RED RFID Flow with UI

Workflow

The basis for this flow starts with subscribing to the MQTT topic for the RFID tag. In my scenario, the topic happened to be “sensors/e1b47aeo/RFID-1/uid“. Themsg.payload will contain the uid for the scanned tag. A switch node will then provide several outputs based on a condition, which happens to be the uid.

Node-RED RFID switch node

 

Access

I’ve decided to send all known uid’s to a function, which sets the msg.payload to “granted”.  This in turn, will display a pop-up message on the node-red-dashboardUI, which displays the uid and whether or not the card was “granted”.

Disco & Cinema

All uid‘s that were granted will be sent to a link node, which allows me to connect it to various other flows. For example, I have sent a link to my IoL City version of a “Hello World”, which triggers disco lights in the local IoL City club and turns on a rainbow of marquee lights at the LEGO Palace Cinema.

Train Routine

A specific uid will trigger a flow to run a LEGO Horizon Express train for 5 seconds. This works because I hacked the train with a NodeMCU to control it via MQTT. See this article for all the details.

UI

The UI is provided by a handy Node-RED node, node-red-dashboard, which uses AngularJS to quickly build UI widgets. The dashboard will represent the RFID data in three ways.

  • RFID Status
    • Listen for any MQTT messages emitted by Homie. These are built-in with the Homie library and will periodically send messages relating to the state of the Homie node. This includes the device ID, IP, signal strength, defined properties, etc.
    • The MQTT messages are stored in a context object, which is then sent to the UI node when the states change.
  • RFID Event Log
    • This UI widget will listen for any MQTT message emitted from the RFID scanner and shift register it into a context array, which is then delivered to aUI template node leveraging the ng-repeat AngularJS directive to simulate a console screen.
  • RFID Notification
    • notification UI node is used to instantly create a pop-up or “toast” message on the UI dashboard with the recently scanned uid and if it was granted or denied.


RFID UI

RFID UI toast

Success!

This was a fun project with plenty of options to expand upon. The primary goal was to understand how an RFID scanner can be used with a EPS8266 and Node-RED. Using Homie was a great way to formalize a MQTT strategy. And finally, the newly embraced node-red-dashboard, demonstrates how you can quickly build a dashboard to start visualizing your data.

Final Thoughts

It’s common to use an RFID for security purposes. It would be expected to use MQTT with authentication and SSL or some secured transmission. This RFID scanner could also work really well in a more traditional REST framework. I almost wrote this project using the aREST Arduino library, but I was curious how to implement Homie… so this was a personal goal above all.

What’s also really interesting about this project and many other Internet of LEGO projects, is the reality that: Input + function = Output. I happened to use an RFID scanner for this project, but it could be any button, temperature sensor, web API or basic schedule that schedules a workflow. There are various ways to abstract this, like Zapier or IFTTT, web server/client paradigm or machine to machine communication. Once you understand the basic concept of IoT, the possibilities are endless (if you have enough LEGOs and electronics in my case).