Practical case: RFID+MQTT on Arduino Uno R4 WiFi+MFRC522

Practical case: RFID+MQTT on Arduino Uno R4 WiFi+MFRC522 — hero

Objective and use case

What you’ll build: An RFID-driven inventory system that reads tags with an MFRC522, indicates state on a WS2812B LED strip, and publishes inventory state and events to an MQTT broker from an Arduino Uno R4 WiFi using Arduino CLI.

Why it matters / Use cases

  • Track inventory in real-time by scanning RFID tags and updating the system instantly.
  • Utilize MQTT for efficient communication between the Arduino and a local broker, allowing for remote monitoring.
  • Provide visual feedback on inventory status through WS2812B LEDs, enhancing user interaction.
  • Implement a reliable solution for managing stock levels in retail or warehouse environments.
  • Enable automated alerts for low stock or inventory discrepancies via MQTT messages.

Expected outcome

  • Real-time inventory updates with less than 1 second latency between RFID scan and MQTT publish.
  • Successful retention of state messages for each RFID tag published to the MQTT broker.
  • Visual confirmation of Wi-Fi/MQTT connection status through LED color changes.
  • Ability to handle up to 100 packets/s for inventory updates without data loss.
  • Validation of end-to-end functionality using command-line tools with 100% success rate in test scenarios.

Audience: Advanced users; Level: Intermediate to advanced.

Architecture/flow: Arduino Uno R4 WiFi with MFRC522 reads RFID tags, processes data, and communicates with MQTT broker while providing feedback via WS2812B LEDs.

Hands-on Advanced Project: RFID Inventory over MQTT with Arduino Uno R4 WiFi + MFRC522 + WS2812B

Objective: Build an RFID-driven inventory system that reads tags with an MFRC522, indicates state on a WS2812B LED strip, and publishes inventory state and events to an MQTT broker from an Arduino Uno R4 WiFi using Arduino CLI (no GUI).

You will:
– Read and toggle inventory state for RFID tags.
– Publish retained state per tag and event messages to an MQTT broker.
– Use WS2812B LEDs as feedback for Wi-Fi/MQTT status and scan events.
– Validate end-to-end behavior with command-line tools.

This walkthrough is written for advanced users who want a precise, repeatable setup using CLI tooling, versioned libraries, and reliable wiring logic.


Prerequisites

  • Operating system:
  • Linux (Ubuntu/Debian), macOS, or Windows 10/11.
  • Arduino CLI installed and available in PATH:
  • Install instructions: https://arduino.github.io/arduino-cli/latest/installation/
  • USB data cable (USB-A to USB-C or USB-A to USB-B micro/mini depending on adapter; Uno R4 WiFi uses USB-C).
  • Local MQTT broker:
  • Option A: Install Mosquitto locally.
  • Option B: Run Mosquitto via Docker.
  • Basic familiarity with:
  • Terminal commands.
  • Arduino sketches and libraries.
  • MQTT topics and retained messages.

Driver notes:
– Arduino Uno R4 WiFi enumerates as a standard CDC/ACM serial device. On Windows, it appears under “Ports (COM & LPT)” with no extra driver required. On macOS/Linux it appears as /dev/tty.usbmodem/ttyACM.


Materials (exact model plus supporting parts)

Required:
– Microcontroller: Arduino Uno R4 WiFi (model name: “UNO R4 WiFi”)
– RFID reader: MFRC522 (breakout board “RFID-RC522 13.56 MHz” using MFRC522 IC)
– Addressable LEDs: WS2812B LED strip or stick (5 V, e.g., 8 LEDs)
– Logic-level shifter (4-channel, BSS138-based) for 5 V ↔ 3.3 V SPI signals to MFRC522
– 330 Ω resistor for WS2812B data line (recommended)
– 1000 µF electrolytic capacitor (≥6.3 V) across LED 5 V power rails (recommended for stability)
– Breadboard and jumper wires
– Optional: External 5 V supply if driving many LEDs (≥1 A for 30+ LEDs)

Notes:
– The MFRC522 board is a 3.3 V device. Many breakout boards do not have onboard level shifting. Always level-shift 5 V MCU outputs (SS/SDA, SCK, MOSI, RST) down to 3.3 V to avoid damaging the MFRC522. MISO from MFRC522 to Uno R4 WiFi can be connected directly (3.3 V → 5 V tolerant input).
– Uno R4 WiFi logic is 5 V. WS2812B operates at 5 V logic and power.


Setup/Connection

Follow the pin mapping in the table. Keep wires short for SPI and WS2812B data. Place the 1000 µF capacitor across the LED 5 V and GND near the strip. Insert a 330 Ω series resistor on the WS2812B data line.

Pin Mapping and Power

  • Use 3.3 V to power the MFRC522 module.
  • Level shift these MCU outputs down to 3.3 V: D10 (SS/SDA), D11 (MOSI), D13 (SCK), D9 (RST).
  • MISO (D12) can be direct (3.3 V output) into the Uno R4 WiFi.

Table: Connection summary

Function Arduino Uno R4 WiFi Pin Level-Shift? MFRC522 Pin WS2812B Notes
Power to MFRC522 3.3 V, GND N/A 3.3V, GND N/A Do not power MFRC522 from 5 V.
MFRC522 Reset D9 Yes (to 3.3) RST N/A Use BSS138 channel.
MFRC522 SS/SDA (select) D10 Yes (to 3.3) SDA(SS) N/A Use BSS138 channel.
SPI MOSI D11 Yes (to 3.3) MOSI N/A Use BSS138 channel.
SPI MISO D12 No (3.3 V→5V tolerant) MISO N/A Direct wire.
SPI SCK D13 Yes (to 3.3) SCK N/A Use BSS138 channel.
WS2812B Data D6 via 330 Ω No (5 V) DIN DIN Add 330 Ω in series close to LED input.
WS2812B Power 5 V, GND N/A 5V, GND 5V,GND Add 1000 µF cap across 5 V–GND near LEDs.

Additional guidance:
– Tie all grounds together (Uno GND, MFRC522 GND, WS2812B GND, and external 5 V ground if used).
– If powering many LEDs from an external 5 V supply, connect the grounds (common ground) and do not draw high LED current from the Uno’s 5 V pin.


Full Code (Arduino Sketch)

Save as rfid-inventory-mqtt/rfid-inventory-mqtt.ino

/*
  rfid-inventory-mqtt.ino
  Device: Arduino Uno R4 WiFi + MFRC522 + WS2812B
  Purpose: Toggle inventory presence per RFID tag and publish over MQTT with retained state.
  Feedback: WS2812B LED effects indicate Wi-Fi/MQTT status and scan results.

  Libraries:
    - WiFiS3
    - ArduinoMqttClient
    - MFRC522
    - Adafruit NeoPixel
*/

#include <SPI.h>
#include <MFRC522.h>
#include <WiFiS3.h>
#include <ArduinoMqttClient.h>
#include <Adafruit_NeoPixel.h>

// -------------------- User Config --------------------
const char* WIFI_SSID = "YOUR_SSID";
const char* WIFI_PASS = "YOUR_PASSWORD";

// MQTT Broker (local LAN broker recommended for validation)
const char* MQTT_HOST = "192.168.1.100"; // change to your broker IP or hostname
const uint16_t MQTT_PORT = 1883;

// MQTT topic base
const char* TOPIC_BASE_STATES = "inventory/states/"; // retained per UID: present/absent
const char* TOPIC_EVENTS = "inventory/events";       // event stream: JSON payload

// LEDs: WS2812B
constexpr uint8_t LED_PIN = 6;
constexpr uint16_t LED_COUNT = 8; // adjust to match your strip/stick
constexpr uint8_t LED_BRIGHTNESS = 24; // be conservative

// MFRC522 pins (SPI HW pins are fixed: 11 MOSI, 12 MISO, 13 SCK)
constexpr uint8_t RFID_SS_PIN = 10;
constexpr uint8_t RFID_RST_PIN = 9;

// Debounce time to ignore rapid repeated scans of same tag (ms)
constexpr uint32_t SCAN_DEBOUNCE_MS = 1000;

// -------------------- Globals --------------------
MFRC522 mfrc522(RFID_SS_PIN, RFID_RST_PIN);

Adafruit_NeoPixel pixels(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

// Wi-Fi + MQTT
WiFiClient wifiClient;
MqttClient mqttClient(wifiClient);

// Derived clientId from MAC
char g_clientId[48] = {0};

// Simple inventory table
struct TagEntry {
  char uid[21];        // up to 20 hex chars + null (supports up to 10 bytes UID; MFRC522 typically 4 or 7)
  bool present;
  uint32_t lastSeenMs; // for debounce
};
constexpr size_t MAX_TAGS = 50;
TagEntry g_tags[MAX_TAGS];
size_t g_tagCount = 0;

// A tiny queue for messages to retry when MQTT is disconnected
struct Msg {
  char topic[64];
  char payload[128];
  bool retained;
};
constexpr size_t MAX_QUEUE = 10;
Msg g_queue[MAX_QUEUE];
size_t g_qHead = 0, g_qTail = 0;

// -------------------- Utility Functions --------------------
void ledSetAll(uint8_t r, uint8_t g, uint8_t b) {
  for (uint16_t i = 0; i < LED_COUNT; i++) {
    pixels.setPixelColor(i, pixels.Color(r, g, b));
  }
  pixels.show();
}

void ledFlash(uint8_t r, uint8_t g, uint8_t b, uint16_t onMs = 100, uint16_t offMs = 100, uint8_t times = 1) {
  for (uint8_t t = 0; t < times; t++) {
    ledSetAll(r, g, b);
    delay(onMs);
    ledSetAll(0, 0, 0);
    delay(offMs);
  }
}

void makeClientIdFromMac() {
  byte mac[6];
  if (WiFi.macAddress(mac) == 0) {
    snprintf(g_clientId, sizeof(g_clientId), "uno-r4wifi-%lu", (unsigned long)millis());
  } else {
    snprintf(g_clientId, sizeof(g_clientId), "uno-r4wifi-%02X%02X%02X%02X%02X%02X",
             mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
  }
}

void uidToHex(const MFRC522::Uid& uid, char* outHex, size_t outLen) {
  // Convert up to uid.size bytes to hex string without separators
  size_t pos = 0;
  for (byte i = 0; i < uid.size && pos + 2 < outLen; i++) {
    pos += snprintf(outHex + pos, outLen - pos, "%02X", uid.uidByte[i]);
  }
  outHex[pos] = '\0';
}

int findTagIndex(const char* uidHex) {
  for (size_t i = 0; i < g_tagCount; i++) {
    if (strcmp(g_tags[i].uid, uidHex) == 0) return (int)i;
  }
  return -1;
}

bool recentlyScanned(const char* uidHex) {
  int idx = findTagIndex(uidHex);
  if (idx < 0) return false;
  return (millis() - g_tags[idx].lastSeenMs) < SCAN_DEBOUNCE_MS;
}

void setInventoryStateAndPublish(const char* uidHex, bool present) {
  // Update/insert in table
  int idx = findTagIndex(uidHex);
  if (idx < 0 && g_tagCount < MAX_TAGS) {
    idx = (int)g_tagCount++;
    strncpy(g_tags[idx].uid, uidHex, sizeof(g_tags[idx].uid) - 1);
    g_tags[idx].uid[sizeof(g_tags[idx].uid) - 1] = '\0';
    g_tags[idx].present = present;
  } else if (idx >= 0) {
    g_tags[idx].present = present;
  }
  if (idx >= 0) g_tags[idx].lastSeenMs = millis();

  // Topics
  char topicState[96];
  snprintf(topicState, sizeof(topicState), "%s%s", TOPIC_BASE_STATES, uidHex);

  // Payloads
  const char* stateStr = present ? "present" : "absent";

  // Publish retained state
  bool pubOk = false;
  if (mqttClient.connected()) {
    mqttClient.beginMessage(topicState, /*retained=*/true, /*qos=*/0);
    mqttClient.print(stateStr);
    pubOk = mqttClient.endMessage();
  }
  if (!pubOk) {
    // Queue it
    size_t next = (g_qTail + 1) % MAX_QUEUE;
    if (next != g_qHead) {
      strncpy(g_queue[g_qTail].topic, topicState, sizeof(g_queue[g_qTail].topic) - 1);
      snprintf(g_queue[g_qTail].payload, sizeof(g_queue[g_qTail].payload), "%s", stateStr);
      g_queue[g_qTail].retained = true;
      g_qTail = next;
    }
  }

  // Event JSON
  char evtJson[160];
  snprintf(evtJson, sizeof(evtJson),
           "{\"client\":\"%s\",\"uid\":\"%s\",\"present\":%s,\"ts_ms\":%lu}",
           g_clientId, uidHex, present ? "true" : "false", (unsigned long)millis());

  pubOk = false;
  if (mqttClient.connected()) {
    mqttClient.beginMessage(TOPIC_EVENTS, /*retained=*/false, /*qos=*/0);
    mqttClient.print(evtJson);
    pubOk = mqttClient.endMessage();
  }
  if (!pubOk) {
    // Queue event non-retained
    size_t next = (g_qTail + 1) % MAX_QUEUE;
    if (next != g_qHead) {
      strncpy(g_queue[g_qTail].topic, TOPIC_EVENTS, sizeof(g_queue[g_qTail].topic) - 1);
      strncpy(g_queue[g_qTail].payload, evtJson, sizeof(g_queue[g_qTail].payload) - 1);
      g_queue[g_qTail].retained = false;
      g_qTail = next;
    }
  }
}

void flushQueue() {
  while (mqttClient.connected() && g_qHead != g_qTail) {
    Msg& m = g_queue[g_qHead];
    mqttClient.beginMessage(m.topic, m.retained, 0);
    mqttClient.print(m.payload);
    if (mqttClient.endMessage()) {
      g_qHead = (g_qHead + 1) % MAX_QUEUE;
    } else {
      break; // stop trying this loop
    }
  }
}

// -------------------- Connectivity --------------------
void ensureWifi() {
  if (WiFi.status() == WL_CONNECTED) return;

  ledSetAll(0, 0, 0);
  Serial.print(F("Connecting to Wi-Fi SSID="));
  Serial.println(WIFI_SSID);

  WiFi.disconnect();
  WiFi.begin(WIFI_SSID, WIFI_PASS);

  uint32_t start = millis();
  while (WiFi.status() != WL_CONNECTED) {
    ledSetAll(0, 0, 10); delay(80);
    ledSetAll(0, 0, 0);  delay(120);
    if (millis() - start > 15000) {
      Serial.println(F("Wi-Fi connect timeout, retrying..."));
      start = millis();
      WiFi.disconnect();
      WiFi.begin(WIFI_SSID, WIFI_PASS);
    }
  }
  Serial.print(F("Wi-Fi connected, IP: "));
  Serial.println(WiFi.localIP());
  ledFlash(0, 16, 0, 100, 50, 2); // double green flash
}

void ensureMqtt() {
  if (mqttClient.connected()) return;

  Serial.print(F("Connecting to MQTT broker "));
  Serial.print(MQTT_HOST);
  Serial.print(F(":"));
  Serial.println(MQTT_PORT);

  mqttClient.setId(g_clientId);
  mqttClient.setKeepAliveInterval(30);

  // Connect loop with indicator
  uint8_t tries = 0;
  while (!mqttClient.connect(MQTT_HOST, MQTT_PORT)) {
    tries++;
    Serial.print(F("MQTT connect failed, code="));
    Serial.println(mqttClient.connectError());
    ledSetAll(16, 4, 0); delay(120);
    ledSetAll(0, 0, 0);  delay(180);
    if (tries >= 5) {
      // Recheck Wi-Fi then retry connect
      ensureWifi();
      tries = 0;
    }
  }

  Serial.println(F("MQTT connected"));
  ledFlash(0, 16, 0, 80, 40, 3); // triple green flash on MQTT OK

  // Announce presence (non-retained event)
  char hello[128];
  snprintf(hello, sizeof(hello), "{\"client\":\"%s\",\"event\":\"online\",\"ts_ms\":%lu}",
           g_clientId, (unsigned long)millis());
  mqttClient.beginMessage(TOPIC_EVENTS, false, 0);
  mqttClient.print(hello);
  mqttClient.endMessage();

  // Push any queued messages
  flushQueue();
}

// -------------------- Setup/Loop --------------------
void setup() {
  Serial.begin(115200);
  delay(120);

  pixels.begin();
  pixels.setBrightness(LED_BRIGHTNESS);
  ledSetAll(0, 0, 0);

  // Start SPI & RFID
  SPI.begin();
  mfrc522.PCD_Init(RFID_SS_PIN, RFID_RST_PIN);
  // Optionally tune antenna gain for better read range
  // mfrc522.PCD_SetAntennaGain(mfrc522.RxGain_max);

  // Wi-Fi + MQTT
  ensureWifi();
  makeClientIdFromMac();
  ensureMqtt();

  Serial.println(F("RFID Inventory MQTT ready."));
}

void loop() {
  // Maintain connectivity
  if (WiFi.status() != WL_CONNECTED) {
    ensureWifi();
  }
  if (!mqttClient.connected()) {
    ensureMqtt();
  }
  mqttClient.poll();

  // RFID read logic
  if (!mfrc522.PICC_IsNewCardPresent()) {
    delay(5);
    return;
  }
  if (!mfrc522.PICC_ReadCardSerial()) {
    delay(5);
    return;
  }

  // Convert UID to hex string
  char uidHex[21] = {0};
  uidToHex(mfrc522.uid, uidHex, sizeof(uidHex));
  Serial.print(F("Tag UID: "));
  Serial.println(uidHex);

  if (!recentlyScanned(uidHex)) {
    // Toggle presence
    int idx = findTagIndex(uidHex);
    bool newState = true;
    if (idx >= 0) {
      newState = !g_tags[idx].present; // toggle
    } else {
      newState = true; // first time -> present
    }
    setInventoryStateAndPublish(uidHex, newState);

    // Visual feedback
    if (newState) {
      ledFlash(0, 20, 0, 70, 50, 2); // present -> green flashes
    } else {
      ledFlash(20, 8, 0, 70, 50, 2); // absent -> amber flashes
    }
  } else {
    Serial.println(F("Duplicate scan ignored (debounced)."));
    ledFlash(0, 0, 16, 40, 40, 1);
  }

  // Clean up RFID state machine
  mfrc522.PICC_HaltA();
  mfrc522.PCD_StopCrypto1();

  // Periodically flush queued messages
  flushQueue();
}

What this sketch does:
– Connects to Wi-Fi and MQTT, retrying with LED feedback.
– Reads RFID tags from MFRC522; builds the UID hex string (uppercase, no separators).
– Maintains an in-memory inventory table of up to 50 tags.
– Toggle behavior: First scan sets present=true; next scan toggles to absent; and so on.
– Publishes:
– Retained per-tag state to inventory/states/ with payload present or absent.
– Non-retained event JSON to inventory/events with client ID, UID, boolean present, and ts_ms.
– LED feedback:
– Blue pulses when connecting Wi-Fi/MQTT, green flashes on successful connections, green/amber flashes for presence/absence changes, blue flash for ignored duplicate.


Build/Flash/Run Commands (Arduino CLI)

We will use Arduino CLI with the correct core and FQBN for Uno R4 WiFi: arduino:renesas_uno:unor4wifi

Commands below are cross-platform; replace the serial port accordingly.

mkdir -p ~/projects/rfid-inventory-mqtt
cd ~/projects/rfid-inventory-mqtt

# 2) Initialize Arduino CLI (first time) and update cores index
arduino-cli config init
arduino-cli core update-index

# 3) Install the Uno R4 core (Renesas)
arduino-cli core install arduino:renesas_uno

# 4) Install required libraries (latest versions)
arduino-cli lib install "WiFiS3"
arduino-cli lib install "ArduinoMqttClient"
arduino-cli lib install "MFRC522"
arduino-cli lib install "Adafruit NeoPixel"

# 5) Place the sketch file
#    Save the provided code as: rfid-inventory-mqtt/rfid-inventory-mqtt.ino
#    (Ensure the folder name matches the .ino filename.)

# 6) Identify your board's serial port
arduino-cli board list

# Example outputs:
# Port         Type              Board Name       FQBN
# /dev/ttyACM0 Serial Port (USB) Arduino Uno R4 WiFi arduino:renesas_uno:unor4wifi
# COM5         Serial Port (USB) Arduino Uno R4 WiFi arduino:renesas_uno:unor4wifi

# 7) Compile for Uno R4 WiFi
arduino-cli compile --fqbn arduino:renesas_uno:unor4wifi ~/projects/rfid-inventory-mqtt

# 8) Upload (replace port as detected)
arduino-cli upload -p /dev/ttyACM0 --fqbn arduino:renesas_uno:unor4wifi ~/projects/rfid-inventory-mqtt

# 9) Open serial monitor (115200 baud) for logs
arduino-cli monitor -p /dev/ttyACM0 -c 115200

Notes:
– If upload fails, double-press the Uno R4 WiFi’s reset button to enter the bootloader, then retry upload.
– On Windows, replace /dev/ttyACM0 with COMx (e.g., COM5).


Step-by-step Validation

We’ll validate end-to-end device, network, and MQTT behavior. Use physical tags (MIFARE Classic 1K/4K, NTAG213/215/216) compatible with MFRC522.

1) Prepare the MQTT broker

Option A: Local install (Debian/Ubuntu):

sudo apt-get update
sudo apt-get install -y mosquitto mosquitto-clients
sudo systemctl enable --now mosquitto
# Allow local test without auth (default on many distros for localhost).

Option B: Docker (cross-platform):

docker run -it --rm --name mosq -p 1883:1883 eclipse-mosquitto:2

If you need anonymous access for LAN, you can run a quick config (test purposes only):

# mosquitto.conf (test only!)
# listener 1883 0.0.0.0
# allow_anonymous true

2) Subscribe to topics for live observation

Open a terminal to subscribe:

# Show all inventory messages verbosely
mosquitto_sub -h 192.168.1.100 -p 1883 -t 'inventory/#' -v

Replace the broker IP/host to match your setup.

3) Power and monitor the device

  • Connect the Uno R4 WiFi via USB and open the Arduino CLI monitor:
  • arduino-cli monitor -p /dev/ttyACM0 -c 115200
  • Watch for:
  • Wi-Fi connect logs and IP shown.
  • MQTT connected and “RFID Inventory MQTT ready.” line.

LED indicators:
– On connecting: brief blue pulses.
– After MQTT connection: triple green flash.

4) Scan a tag (first time: present=true)

  • Approach a tag to the MFRC522 antenna.
  • CLI monitor output should show a Tag UID line.
  • The LEDs should flash green.
  • In the subscriber terminal, expect two messages:
  • inventory/states/ present
  • inventory/events {«client»:»uno-r4wifi-…»,»uid»:»«,»present»:true,»ts_ms»:…}

Also verify that the state topic is retained:
– Resubscribe (new terminal):
– mosquitto_sub -h 192.168.1.100 -p 1883 -t ‘inventory/states/#’ -v
– You should immediately see the last published retained state for that UID.

5) Scan the same tag again (toggle: present=false)

  • Scan the same UID a second time.
  • LEDs flash amber (absent).
  • Subscriber shows:
  • inventory/states/ absent (retained)
  • inventory/events {…,»present»:false,…}

6) Check duplicate debouncing

  • Rapidly tap the same tag again within 1 second.
  • The serial monitor shows “Duplicate scan ignored (debounced).”
  • LED shows a single blue flash.
  • MQTT should not receive new messages for that duplicate tap.

7) Test with two or more different tags

  • Repeat steps 4–6 with additional tags.
  • Observe distinct topics:
  • inventory/states/04A1B2C3
  • inventory/states/0BFFEED1
  • Each state topic is retained separately.

8) Power-cycle the Arduino and re-subscribe

  • Reset or unplug/replug the Uno R4 WiFi.
  • Once it reconnects, open a fresh subscriber:
  • mosquitto_sub -h 192.168.1.100 -t ‘inventory/states/#’ -v
  • You should see retained states from the broker without any scans.
  • Scan a tag; confirm state toggles and events publish correctly again.

Troubleshooting

Common issues and fixes:

  • No Wi-Fi connection:
  • Check SSID/password in code (case-sensitive).
  • Verify 2.4 GHz network; ESP32-S3-based radio (via WiFiS3) is 2.4 GHz only.
  • Ensure DHCP is enabled and the device obtains an IP address.
  • Try moving closer to the AP; reduce interference.

  • MQTT connect fails:

  • Confirm broker is reachable from your PC (telnet 192.168.1.100 1883).
  • Verify firewall rules to allow TCP/1883 on your broker host.
  • Confirm broker configuration allows connections (anonymous or username/password).
  • If using a hostname, ensure DNS resolves on your network; try using raw IP.

  • RFID not reading:

  • Power MFRC522 from 3.3 V pin, not 5 V.
  • Ensure level shifting on SS (D10), RST (D9), MOSI (D11), SCK (D13). MISO to D12 is direct.
  • Antenna orientation: place the card flat on the coil area; MFRC522 has limited range (a few cm).
  • Reduce potential interference: keep WS2812B data and power wires away from the reader antenna loop.
  • As a hardware test, you can compile and run the MFRC522 “DumpInfo” example quickly to confirm wiring:

    • arduino-cli compile –fqbn arduino:renesas_uno:unor4wifi –libraries «MFRC522»
    • arduino-cli upload -p /dev/ttyACM0 –fqbn arduino:renesas_uno:unor4wifi
  • WS2812B shows wrong colors or flickers:

  • Confirm you added a 330 Ω resistor in series on the data line near DIN.
  • Ensure a solid ground reference between Uno and LED strip.
  • Add the 1000 µF capacitor across 5 V and GND at the LED strip.
  • Lower brightness to reduce current spikes (LED_BRIGHTNESS).
  • Use a dedicated 5 V supply if driving many LEDs. Always common the grounds.

  • Serial port not detected:

  • Try a different USB cable (data-capable).
  • On Windows, check Device Manager for COM port changes.
  • Double-press reset to enter bootloader and then upload.

  • Memory/queue overflows:

  • If many scans occur while MQTT is disconnected, the small queue can overflow and drop events.
  • Consider reconnecting the broker or enlarging the queue (increase MAX_QUEUE) with caution.

Improvements

  • Security (TLS):
  • Use WiFiSSLClient with ArduinoMqttClient for MQTT over TLS (port 8883).
  • Broker must have a proper CA; memory constraints apply. Test with minimally sized CA and short topic names.
  • Authentication:
  • Configure broker to require username/password; use mqttClient.setUsernamePassword(«user»,»pass»);
  • Time synchronization:
  • Add NTP client to include real timestamps in events (ts_iso8601). Requires library and time sync on start.
  • Persistent inventory:
  • Persist state to non-volatile storage (e.g., emulated EEPROM or dedicated flash if supported) to preserve presence across reboots. Carefully manage write wear and atomics.
  • More expressive topics:
  • Publish to topics like inventory///states/ for multi-site deployments.
  • QoS tuning:
  • ArduinoMqttClient can publish with QoS 1 in many cases; adjust if your broker and library build supports it.
  • Health checks:
  • Publish periodic heartbeat to inventory/clients//status with online/offline retained last-will message.
  • Command/control:
  • Subscribe to inventory/cmd/ for remote reset, LED test, or rescan commands.

Final Checklist

  • Wiring:
  • MFRC522 powered at 3.3 V.
  • Level shifting used on D9/D10/D11/D13 to MFRC522.
  • MISO wired directly from MFRC522 to D12.
  • WS2812B DIN on D6 via 330 Ω; 1000 µF cap on 5 V rail near LEDs.
  • All grounds tied together.

  • Software:

  • Arduino CLI installed and core arduino:renesas_uno set up.
  • Libraries installed: WiFiS3, ArduinoMqttClient, MFRC522, Adafruit NeoPixel.
  • Sketch saved in rfid-inventory-mqtt/rfid-inventory-mqtt.ino.

  • Build and upload:

  • Compiled with: arduino:renesas_uno:unor4wifi FQBN.
  • Uploaded to correct serial port.
  • Serial monitor at 115200 baud shows connection logs.

  • MQTT validation:

  • Broker accessible at MQTT_HOST:MQTT_PORT.
  • Subscriber shows retained states per UID after scans.
  • Event JSON published on inventory/events on each toggle.

  • Behavior:

  • First scan: present=true (green flashes).
  • Second scan: present=false (amber flashes).
  • Rapid duplicate scans ignored for ~1 s (blue single flash).

If every item in this checklist is satisfied, your rfid-inventory-mqtt solution on Arduino Uno R4 WiFi is operational and ready for integration with dashboards, databases, or automation flows.


Helpful Commands (Reference)

Broker operations and subscriptions:

# Start mosquitto via Docker (ephemeral)
docker run -it --rm --name mosq -p 1883:1883 eclipse-mosquitto:2

# Subscribe to all inventory topics
mosquitto_sub -h 192.168.1.100 -t 'inventory/#' -v

# Inspect retained states only
mosquitto_sub -h 192.168.1.100 -t 'inventory/states/#' -v

# Publish a test event (broker/local testing)
mosquitto_pub -h 192.168.1.100 -t 'inventory/events' -m '{"client":"test","event":"hello"}'

With this setup, you can now integrate the rfid-inventory-mqtt stream into Node-RED, Home Assistant, Grafana, or your own backend, using retained per-tag state for reliable point-in-time inventory and events for real-time activity.

Find this product and/or books on this topic on Amazon

Go to Amazon

As an Amazon Associate, I earn from qualifying purchases. If you buy through this link, you help keep this project running.

Quick Quiz

Question 1: What is the primary objective of the project?




Question 2: Which microcontroller is used in this project?




Question 3: What type of LED strip is used for feedback in the project?




Question 4: What protocol is used to publish inventory state and events?




Question 5: Which operating systems are mentioned as prerequisites?




Question 6: What is required to connect the Arduino Uno R4 WiFi?




Question 7: What is the purpose of the Mosquitto broker in this project?




Question 8: What type of RFID reader is used in this project?




Question 9: What is required for validating end-to-end behavior?




Question 10: What is the installation link for Arduino CLI?




Carlos Núñez Zorrilla
Carlos Núñez Zorrilla
Electronics & Computer Engineer

Telecommunications Electronics Engineer and Computer Engineer (official degrees in Spain).

Follow me:
error: Contenido Protegido / Content is protected !!
Scroll to Top