Ons project

Wij hebben besloten om een project te maken in verband met NFC tags en scanners. Ons project bestaat uit 4 NFC tags met een bepaalde kleur.

De NFC tags zullen in de juiste volgorde gescanned moeten worden aan de hand van een kleurcode. De kleurcode kan gevonden worden door gebruik te maken van de gekleurde knoppen.

Foto's

Een overzicht van onze componenten en opbouw.

Blokschema's

De blokschema's van elk onderdeel van ons project.

Componenten

Een overzicht van de onderdelen die we hebben gemaakt.

Schema van de RFID scanner

RFID / NFC Reader

De NFC reader is gemaakt met een ESP32 feather, een 7-segment display, een buzzer en een RFID reader. De NFC tags hebben elk een verschillende kleur geprogrammeerd vanbinnen. Als de RFID reader een tag leest, stuurt het die kleur door via MQTT naar de MQTT broker, die op de Raspberry Pi draait. Dit gebeurt allemaal via WiFi, want de Raspberry Pi fungeert als een WiFi access point.

Het bericht wordt dan opgevangen in Node-RED, die ook draait op de Pi. Daar wordt gecontroleerd welk nummer er overeen komt met de kleur. Dat nummer wordt dan teruggestuurd naar de ESP, die vervolgens het nummer op de 7-segment display toont. Ook zal er dan een buzzer te horen zijn.

Bekijk flowchart →
Schema van de arcade knoppen

Knoppen

De knoppen hebben elk een verschillende kleur en hebben elk een LED ingebouwd. Deze opstelling is gemaakt met een ESP32 van Joy-IT en de 4 arcade buttons. De ESP controleert continu of er een knop is ingedrukt.

Als er 4 verschillende knoppen zijn ingedrukt, wordt er een MQTT bericht doorgestuurd naar de Pi met de volgorde van de ingedrukte knoppen. In Node-RED wordt dan de volgorde gecontroleerd en als dit de juiste volgorde is komt er op het scherm van de Pi een code tevoorschijn.

Bekijk flowchart →
Schema van de Wifi Kit 8

Afstandsbediening

Dit onderdeel is gemaakt met een Wifi Kit 8, een IR receiver, een afstandsbediening en een buzzer. Als je de code op het scherm hebt gekregen, kan je met de afstandsbediening die code hier ingeven. Die zal ook als je deze ingeeft op het scherm verschijnen.

Als er 4 cijfers zijn ingegeven wordt die verzonden naar de Raspberry Pi, die controleert dan of deze correct is. Als dat zo is wordt er een bericht teruggestuurd (juist/fout), en hoor je een gepaste toon uit de buzzer komen. En nu is het spel gedaan.

Bekijk flowchart →

Raspberry Pi

Dit is gemaakt met een Raspberry Pi 4 en een 7 inch IPS scherm. De Raspberry Pi werkt als een access point voor alle andere onderdelen — alle andere zijn er mee verbonden.

Op de Pi draait Mosquitto, een programma waarmee je MQTT berichten kan verzenden en ontvangen. De Pi is ingesteld als de broker. Op de Pi draait ook Node-RED: een programma waarmee je makkelijk een dashboard kan maken en dat eenvoudig te koppelen is met MQTT. Je kan er in JavaScript programmeren in blokken, en zo inkomende berichten controleren en verwerken.

Code

De broncode van elk onderdeel van ons project, met ruimte voor commentaar.

RFID / NFC Reader Arduino / C++
#include <SPI.h>
#include <MFRC522.h>
#include "WiFi.h"
#include <PubSubClient.h>

#define RST_PIN 21
#define SS_PIN 23

int pinsVanSegmenten[7] = {32, 14, 13, 12, 27, 15, 33};

// Methoden
void mqttConnect();
void callback(char* topic, byte* message, unsigned int length);
void initWiFi();
void initMQTTbroker();
void segments(int A, int B, int C, int D, int E, int F, int G);

const char* ssid = "EscapeGame_Groep16";
const char* paswoord = "EscapeGame_PASS";

WiFiClient WiFiClient1;
MFRC522 mfrc522(SS_PIN, RST_PIN);

// MQTT instellingen
const char* mqttBroker = "10.42.0.1";
const char* mqttClientName = "RFID_SCANNER";
const char* subNumber = "EscapeGame/Number";
const char* pubScannedCode = "EscapeGame/ScannedCode";
const char* mqttPwd = "EscapeGame";
const char* clientID = "EscapeGame_Scanner";

PubSubClient mqttClient1(WiFiClient1);

// 7-segment display
void segments(int A, int B, int C, int D, int E, int F, int G) {
  digitalWrite(pinsVanSegmenten[0], A);
  digitalWrite(pinsVanSegmenten[1], B);
  digitalWrite(pinsVanSegmenten[2], C);
  digitalWrite(pinsVanSegmenten[3], D);
  digitalWrite(pinsVanSegmenten[4], E);
  digitalWrite(pinsVanSegmenten[5], F);
  digitalWrite(pinsVanSegmenten[6], G);
}

// MQTT connectie
void mqttConnect() {
  while (!mqttClient1.connected()) {
    if (mqttClient1.connect(mqttClientName)) {
      mqttClient1.subscribe(subNumber);
    } else {
      delay(5000);
    }
  }
}

// Callback
void callback(char* topic, byte* message, unsigned int length) {
  String ontvangenMsg;
  for (int i = 0; i < length; i++) {
    ontvangenMsg += (char)message[i];
  }

  if (String(topic) == subNumber) {
    if (ontvangenMsg == "1") segments(0,1,1,0,0,0,0);
    else if (ontvangenMsg == "2") segments(1,1,0,1,1,0,1);
    else if (ontvangenMsg == "3") segments(1,1,1,1,0,0,1);
    else if (ontvangenMsg == "4") segments(0,1,1,0,0,1,1);
    else if (ontvangenMsg == "0") segments(0,0,0,0,0,0,0);
  }
}

// WiFi
void initWiFi() {
  WiFi.begin(ssid, paswoord);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }
}

// MQTT init
void initMQTTbroker() {
  mqttClient1.setServer(mqttBroker, 1883);
  mqttClient1.setCallback(callback);
}

void setup() {
  Serial.begin(115200);
  initWiFi();
  initMQTTbroker();

  SPI.begin();
  mfrc522.PCD_Init();

  for (int i = 0; i < 7; i++) {
    pinMode(pinsVanSegmenten[i], OUTPUT);
  }
}

void loop() {
  if (!mqttClient1.connected()) {
    mqttConnect();
  }
  mqttClient1.loop();

  MFRC522::MIFARE_Key key;
  for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF;

  if (!mfrc522.PICC_IsNewCardPresent()) return;
  if (!mfrc522.PICC_ReadCardSerial()) return;

  byte buffer2[18];
  byte len = 18;

  MFRC522::StatusCode status;

  status = mfrc522.PCD_Authenticate(
    MFRC522::PICC_CMD_MF_AUTH_KEY_A, 
    1, 
    &key, 
    &(mfrc522.uid)
  );

  if (status != MFRC522::STATUS_OK) return;

  status = mfrc522.MIFARE_Read(1, buffer2, &len);
  if (status != MFRC522::STATUS_OK) return;

  mqttClient1.publish(pubScannedCode, (char*)buffer2);

  delay(1000);

  mfrc522.PICC_HaltA();
  mfrc522.PCD_StopCrypto1();
}
Knoppen Arduino / C++
#include "WiFi.h"
#include <PubSubClient.h>

#define knopROOD 23
#define knopBLAUW 22
#define knopGROEN 15
#define knopGEEL 4

#define ledROOD 21
#define ledBLAUW 19
#define ledGROEN 18
#define ledGEEL 5

int knopArr[4] = {knopROOD, knopBLAUW, knopGROEN, knopGEEL};
int ledArr[4] = {ledROOD, ledBLAUW, ledGROEN, ledGEEL};
String kleurArr[4] = {"ROOD", "BLAUW", "GROEN", "GEEL"};

String strVolgorde = "";
int teller = 0;

// Declaratie methoden
void mqttConnect();
void initWiFi();
void initMQTTbroker();

const char* ssid = "EscapeGame_Groep16";
const char* paswoord = "EscapeGame_PASS";

WiFiClient WiFiClient1;

// MQTT instellingen
const char* mqttBroker = "10.42.0.1";
const char* mqttClientName = "Knoppen";
const char* pubVolgorde = "EscapeGame/Volgorde";
const char* mqttPwd = "EscapeGame";
const char* clientID = "EscapeGame_Knoppen";

PubSubClient mqttClient1(WiFiClient1);

// MQTT connectie
void mqttConnect() {
  while (!mqttClient1.connected()) {
    if (mqttClient1.connect(mqttClientName)) {
      digitalWrite(ledGROEN, HIGH);
      delay(1000);
      digitalWrite(ledGROEN, LOW);
      mqttClient1.publish("Hallo", mqttClientName);
    } else {
      delay(5000);
    }
  }
}

// WiFi init
void initWiFi() {
  WiFi.begin(ssid, paswoord);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }
}

// MQTT init
void initMQTTbroker() {
  mqttClient1.setServer(mqttBroker, 1883);
}

void setup() {
  Serial.begin(115200);
  initWiFi();
  initMQTTbroker();

  pinMode(knopBLAUW, INPUT_PULLUP);
  pinMode(knopROOD, INPUT_PULLUP);
  pinMode(knopGROEN, INPUT_PULLUP);
  pinMode(knopGEEL, INPUT_PULLUP);

  pinMode(ledROOD, OUTPUT);
  pinMode(ledBLAUW, OUTPUT);
  pinMode(ledGROEN, OUTPUT);
  pinMode(ledGEEL, OUTPUT);
}

void loop() {
  if (!mqttClient1.connected()) {
    mqttConnect();
  }
  mqttClient1.loop();

  for (int i = 0; i < 4; i++) {
    if (digitalRead(knopArr[i]) == LOW) {
      if (digitalRead(ledArr[i]) == LOW) {
        digitalWrite(ledArr[i], HIGH);
        strVolgorde += kleurArr[i] + " ";
        teller++;
        Serial.println(strVolgorde);
      }
      delay(50);
    }
  }

  if (teller == 4) {
    mqttClient1.publish(pubVolgorde, strVolgorde.c_str());
    teller = 0;
    strVolgorde = "";

    digitalWrite(ledROOD, LOW);
    digitalWrite(ledBLAUW, LOW);
    digitalWrite(ledGROEN, LOW);
    digitalWrite(ledGEEL, LOW);
  }
  else if (teller > 4) {
    for (int i = 0; i < 4; i++) {
      digitalWrite(ledArr[i], LOW);
    }
  }

  delay(200);
}
Afstandsbediening Arduino / C++
#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <IRremoteESP8266.h>
#include <IRrecv.h>
#include <IRutils.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>

// Declaratie van de methoden
void mqttConnect();
void callback(char* topic, byte* message, unsigned int length);
void initWiFi();
void initMQTTbroker();

const char* ssid = "EscapeGame_Groep16";
const char* paswoord = "EscapeGame_PASS";
WiFiClient WiFiClient1;

// MQTT instellingen
const char* mqttBroker = "10.42.0.1"; 
const char* mqttClientName = "Afstandsbediening";
const char* SubCorrect = "EscapeGame/Correct";
const char* PubCode = "EscapeGame/Code";
const char* mqttPwd = "EscapeGame";
const char* clientID = "EscapeGame_Afstandsbediening";
PubSubClient mqttClient1(WiFiClient1);

// OLED setup
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define OLED_RESET    16
#define OLED_SDA       4
#define OLED_SCL       5
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// Pins
const int IR_RECEIVE_PIN = 14;
const int BUZZER_PIN     = 12;

// IR codes
const unsigned long IR_CODES[] = {
  0xAD52FF00, 0xFF6897, 0xFF9867, 0xFFB04F,
  0xFF30CF, 0xFF18E7, 0xFF7A85, 0xFF10EF,
  0xFF38C7, 0xFF5AA5
};

IRrecv irrecv(IR_RECEIVE_PIN);
decode_results results;

// Puzzle
int enteredDigits[4];
int enteredCount = 0;
bool waitingForServer = false;

// Buzzer
struct BuzzerNote {
  int freq;
  int duration;
};

BuzzerNote correctNotes[] = {{1047,150},{1319,150},{1568,150},{2093,300}};
BuzzerNote wrongNotes[]   = {{300,200},{200,400}};

BuzzerNote* currentMelody = nullptr;
int melodyLength = 0;
int melodyIndex = 0;
unsigned long noteStartTime = 0;

// MQTT connectie
void mqttConnect() {
  while (!mqttClient1.connected()) {
    if (mqttClient1.connect(mqttClientName)) {
      mqttClient1.subscribe(SubCorrect);
    } else {
      delay(5000);
    }
  }
}

// Callback
void callback(char* topic, byte* message, unsigned int length) {
  String ontvangenMsg;
  for (int i = 0; i < length; i++) {
    ontvangenMsg += (char)message[i];
  }

  if (String(topic) == SubCorrect) {
    waitingForServer = false;

    if (ontvangenMsg == "1") {
      startMelody(correctNotes, 4);
      delay(3000);
      enteredCount = 0;
    } else {
      startMelody(wrongNotes, 2);
      enteredCount = 0;
    }
  }
}

// WiFi
void initWiFi() {
  WiFi.begin(ssid, paswoord);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }
}

// MQTT init
void initMQTTbroker() {
  mqttClient1.setServer(mqttBroker, 1883);
  mqttClient1.setCallback(callback);
}

// Buzzer functies
void playTone(int freq) {
  if (freq == 0) analogWrite(BUZZER_PIN, 0);
  else {
    analogWriteFreq(freq);
    analogWrite(BUZZER_PIN, 128);
  }
}

void stopTone() {
  analogWrite(BUZZER_PIN, 0);
}

void startMelody(BuzzerNote* melody, int length) {
  currentMelody = melody;
  melodyLength = length;
  melodyIndex = 0;
  noteStartTime = millis();
  playTone(melody[0].freq);
}

void updateBuzzer() {
  if (!currentMelody) return;

  if (millis() - noteStartTime >= currentMelody[melodyIndex].duration) {
    melodyIndex++;
    if (melodyIndex >= melodyLength) {
      stopTone();
      currentMelody = nullptr;
      return;
    }
    noteStartTime = millis();
    playTone(currentMelody[melodyIndex].freq);
  }
}

// IR naar cijfer
int irCodeToDigit(unsigned long code) {
  for (int i = 0; i < 10; i++) {
    if (IR_CODES[i] == code) return i;
  }
  return -1;
}

// Display
void updateDisplay() {
  display.clearDisplay();
  display.setTextSize(3);
  display.setCursor(28, 4);

  for (int i = 0; i < 4; i++) {
    if (i < enteredCount) display.print(enteredDigits[i]);
    else display.print('_');
  }

  display.display();
}

void setup() {
  Serial.begin(115200);
  initWiFi();
  initMQTTbroker();

  Wire.begin(OLED_SDA, OLED_SCL);

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();

  irrecv.enableIRIn();

  pinMode(BUZZER_PIN, OUTPUT);
  analogWriteRange(255);
}

void loop() {
  if (!mqttClient1.connected()) mqttConnect();
  mqttClient1.loop();

  updateBuzzer();

  if (!waitingForServer && irrecv.decode(&results)) {
    int digit = irCodeToDigit(results.value);

    if (digit != -1 && enteredCount < 4) {
      enteredDigits[enteredCount++] = digit;
      updateDisplay();

      if (enteredCount == 4) {
        waitingForServer = true;

        String payload = String(enteredDigits[0]) + " " +
                         String(enteredDigits[1]) + " " +
                         String(enteredDigits[2]) + " " +
                         String(enteredDigits[3]);

        mqttClient1.publish(PubCode, payload.c_str());
      }
    }
    irrecv.resume();
  }
}