// PROJECT 008

RFID Inventory Platform

End-to-end RFID inventory automation for a warehouse and manufacturing environment. Zebra FX9600 fixed readers, custom middleware integrating with ERP via MQTT, and a real-time web dashboard reduced manual stock-count operations by 85% and achieved 99.8% inventory accuracy.

Zebra FX9600UHF RFIDMQTT Python MiddlewareERP IntegrationAWS IoT LLRP ProtocolEPC GS1
// RFID TAGS EPC GS1 UHF Pallets / Cases Individual Items Bins / Shelves RTI Assets 860–960 MHz // ZEBRA FX9600 READERS 4 Antenna Ports each LLRP v1.1 Protocol 10 dBm – 30 dBm TX ROSpec: Continuous TRIGGER ZONES Dock Door ×4 Conveyor ×2 Staging Area ×3 Ethernet → Middleware // PYTHON MIDDLEWARE LLRP Client EPC Decoder Tag Deduplication Zone Mapping Event Filtering MQTT Publisher rfid/read/events rfid/zone/change rfid/inventory/delta // CLOUD + ERP AWS IoT Core Lambda Processor DynamoDB (Events) ERP INTEGRATION SAP S/4HANA REST API Sync Inventory Updates PO Matching React Dashboard
Problem
Inventory Blind Spots
Manual barcode scanning created inventory inaccuracies up to 12%, required 3 full-time staff for daily cycle counts, and caused production delays from missing parts.
Solution
RFID Automation
Zebra FX9600 fixed readers at dock doors, conveyors, and staging areas. Python LLRP middleware published read events via MQTT to AWS IoT for ERP integration.
Result
Reduced Manual Operations
85% reduction in manual cycle counts, inventory accuracy improved from 88% to 99.8%, dock door processing time cut from 12 minutes to under 90 seconds.
99.8%Inventory Accuracy
85%Manual Count Reduction
<90sDock Processing Time
10k+Tags / Day

LLRP Reader Integration

The Zebra FX9600 readers are controlled via LLRP (Low Level Reader Protocol) v1.1. A Python LLRP client connects over TCP, configures ROSpec (Reader Operation Spec) for continuous inventory mode, and streams TagReportData events to the deduplication engine.

class ZebraReader:
    def __init__(self, host, port=5084):
        self.client = LLRPClient(host, port)
        self.seen_tags = TTLCache(maxsize=10000, ttl=5.0)  # 5s dedup window

    async def start_inventory(self):
        rospec = ROSpec(
            id=1,
            priority=0,
            current_state=ROSpecState.DISABLED,
            roi_spec=ROISpec(
                antenna_ids=[1, 2, 3, 4],
                air_protocols=[AirProtocol.EPCGlobalClass1Gen2]
            ),
            ro_report_spec=ROReportSpec(
                report_trigger=N_TAG_OBSERVATION,
                n=1,  # Report every tag immediately
                tag_report_content_selector=TagReportContentSelector(
                    epc=True, antenna_id=True, rssi=True, timestamp=True
                )
            )
        )
        await self.client.add_rospec(rospec)
        await self.client.enable_rospec(rospec_id=1)

    def on_tag_read(self, tag: TagReport):
        epc = tag.epc.hex().upper()
        if epc not in self.seen_tags:      # Deduplicate within 5s window
            self.seen_tags[epc] = True
            self._publish_mqtt(epc, tag.antenna_id, tag.rssi)

MQTT Event Schema

rfid/read/eventsepc, reader_id, antenna, rssi, timestamp — raw reads, QoS 0
rfid/zone/entryepc, zone_id, item_type, quantity — on zone entry, QoS 1
rfid/zone/exitepc, zone_id, dwell_seconds — on zone departure, QoS 1
rfid/inventory/deltaadded[], removed[], zone_id — per cycle, QoS 1
rfid/alerts/missingepc, expected_zone, last_seen — retained, QoS 2
reader/{id}/statusuptime, read_rate_per_min, antenna_health — 60s heartbeat

Technology Stack

RFID HardwareZebra FX9600 (4-port), Zebra AN620 circularly polarised antennas
RFID TagsImpinj Monza R6-P UHF Gen2, EPC GS1 96-bit encoding
MiddlewarePython 3.11, sllurp LLRP library, asyncio, TTLCache dedup
MessagingMQTT 3.1.1, Eclipse Mosquitto broker, AWS IoT Core (cloud)
ERPSAP S/4HANA REST API, inventory delta sync via Lambda
DashboardReact, WebSocket, live floor-plan SVG, Grafana metrics
← All Projects