You can build a fully mock RF Controls data-feed system using a Python FastAPI backend that simulates both REST endpoints and STOMP-over-WebSocket streams, and a React frontend that subscribes to live tag events and renders them on a map and in a table. The mock backend will generate tag reads for two antennas across five zones—including a “Point of Sale” zone—and enrich each read with product metadata (EPC → SKU/category). On the frontend, @stomp/stompjs (or rx-stomp via stomp-js) will handle the real-time feed, React Leaflet will draw zones and plot item positions as interactive dots, and TanStack Table (formerly React Table) will display a live-updating table of tag IDs, categories, and SKUs. This proof-of-concept requires no Java/Angular or Next.js—plain React + FastAPI suffices.
- Antennas:
ant1,ant2 - Zones (e.g.,
zone1…zone5), withzone5marked as the “Point of Sale” target - Products: Mapping of tag EPCs to
{ sku, category }, e.g.{"EPC0001":{"sku":"SKU123","category":"electronics"}}
-
Tag Reads: JSON objects
{ epc, antennaId, zoneId, timestamp }emitted via STOMP frames. -
REST Endpoints:
GET /api/zones→[{"id":"zone1","name":"Electronics Aisle",…}, …]GET /api/products→[{ epc, sku, category }]
Use FastAPI’s built-in WebSocket support to accept STOMP frames (fastapi.tiangolo.com). Install dependencies:
pip install fastapi uvicorn websocketsfrom fastapi import FastAPI
app = FastAPI()
# Zones metadata
@app.get("/api/zones")
def get_zones():
return [
{"id":"zone1","name":"Electronics Aisle"},
...,
{"id":"zone5","name":"Point of Sale"}
]
# Products metadata
@app.get("/api/products")
def get_products():
return [
{"epc":"EPC0001","sku":"SKU123","category":"electronics"},
{"epc":"EPC0023","sku":"SKU999","category":"clothes"},
...
]Use asyncio to emit a STOMP MESSAGE frame every second per antenna, randomizing zone and EPC (stackoverflow.com):
import asyncio, json, random, time
from fastapi import WebSocket
@app.websocket("/ws/tags")
async def tag_stream(ws: WebSocket):
await ws.accept()
while True:
epc = random.choice(["EPC0001","EPC0023"])
zone = random.choice(["zone1","zone2","zone3","zone4","zone5"])
antenna = random.choice(["ant1","ant2"])
body = json.dumps({
"epc": epc,
"antennaId": antenna,
"zoneId": zone,
"timestamp": int(time.time()*1000)
})
frame = (
"MESSAGE\n"
"destination:/topic/tagBlinkLite.*\n\n"
f"{body}\x00"
)
await ws.send_text(frame)
await asyncio.sleep(1)STOMP is a simple text-based, frame-oriented protocol. Each frame has a command (MESSAGE), headers (destination), and a body terminated by a NULL byte (0x00) (stomp.github.io).
The above code manually constructs MESSAGE frames. For more fidelity, you could use a STOMP library like stomp.py to build frames programmatically, but raw construction suffices for a mock (websockets.readthedocs.io).
Install:
npm install @stomp/stompjs axiosInitialize STOMP client:
import { Client } from '@stomp/stompjs';
const client = new Client({
brokerURL: 'ws://localhost:8000/ws/tags',
debug: (msg) => console.log(msg),
});
client.onConnect = () => {
client.subscribe('/topic/tagBlinkLite.*', message => {
const data = JSON.parse(message.body);
// update React state with data
});
};
client.activate();This follows patterns from community samples (medium.com).
Install:
npm install react-leaflet leafletRender a map and zone overlays, then plot live tag positions:
import { MapContainer, TileLayer, CircleMarker, Polygon } from 'react-leaflet';
function MapView({ zones, tags }) {
return (
<MapContainer center={[0,0]} zoom={18} style={{ height: '400px' }}>
<TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
{zones.map(z => (
<Polygon key={z.id} positions={z.boundary} />
))}
{tags.map(tag => (
<CircleMarker
key={tag.epc}
center={tag.position}
radius={8}
eventHandlers={{
mouseover: () => {/* show popup with SKU */},
}}
/>
))}
</MapContainer>
);
}Usage mirrors official docs (react-leaflet.js.org).
Install:
npm install @tanstack/react-tableDefine columns for EPC, SKU, category, zone, timestamp, and feed live data into the table component. This approach is similar to community guides (blog.logrocket.com).
- Mock Backend emits STOMP frames (
/ws/tags) and serves metadata (/api/zones,/api/products). - React front end uses @stomp/stompjs to consume live reads, axios to fetch metadata, and merges them in state.
- MapView plots items by converting
zoneIdto spatial boundaries, and TableView lists all reads with associated SKU/category and zone.
This decoupled design lets you later swap mocks with real RFC-OS endpoints without changing the frontend.
- Schema Completeness: Public examples lack some proprietary fields (e.g., RSSI, antenna beam info). For 100% fidelity, request RF Controls’ Programmer’s Reference Guide or OpenAPI spec.
- Auth & Security: Introduce Basic Auth or tokens on
/ws/tagsand/api/*, and migrate to WSS/HTTPS for production. - Advanced Processing: Add zone-clustering/buffering logic (as in
wms-demo-app) to smooth noisy reads before display.
With this blueprint, you can simulate a realistic RF Controls data feed for development, demo, or customer prototyping—then simply replace the mocks with true RF Controls API calls once credentials and specs are available.