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/
– 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
- arduino-cli compile –fqbn arduino:renesas_uno:unor4wifi –libraries «MFRC522»
-
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
As an Amazon Associate, I earn from qualifying purchases. If you buy through this link, you help keep this project running.



