Simulating a cellular modem and MQTT without a full network
Category: Engineering
Telematics firmware does not need a tower, a SIM, or a public broker to prove the interesting part: the MCU talks AT, gets a GNSS fix, publishes JSON, and someone can collect that payload. We built that surface in LabWired — deliberately not a full cellular network.
A CLM-style device looks simple on a slide: modem, GPS, cloud. On the bench it is SIMs, antennas, broker accounts, and “works once” demos. The firmware path that matters for bring-up is narrower:
- Drive the modem with Quectel-style AT (
AT+QGPS*,AT+QMT*). - Parse a GNSS fix.
- Publish a small JSON payload (lat/lon, source).
- Collect that message for a human, a test, or an agent.
That is the product surface. Not EPC, not TLS termination, not a real MQTT 3.1.1 wire broker.
What we simulate (and what we don’t) {#what-we-simulate}
| In scope | Out of scope |
|---|---|
| BG770A AT surface over UART (QGPS, QMT open/conn/pub/sub) | Full LTE-M/NB-IoT air interface / RAN / EPC |
GNSS reply shapes (+QGPSLOC) with lab coordinates | Real constellation dynamics |
| SimMqttFabric — land publishes, inspect/collect | Real MQTT broker, auth, retained sessions |
| Path-loss CSQ from a shared RF medium | Accurate link-budget engineering |
| Headless io-smoke in CI (UART + fabric payload) | Carrier certification |
Honesty is the feature: demos stay honest about stand-ins, and CI still gates the firmware path that will run on silicon.
The stack: MCU, modem AT, AirBus {#the-stack}
The demo board is an STM32H735 virtual MCU:
- USART1 → Quectel BG770A model (modem AT)
- USART3 → console (full AT transcript)
- SPI1 + PA4 → compact ILI9341 strip (lat/lon, status)
The network peer is not “the internet.” It is SimMqttFabric, on the lab AirBus next to nRF/BLE virtual air and the shared path-loss RfMedium:
MCU ──USART──► BG770A AT model
│
├── RfMedium (range → CSQ)
└── SimMqttFabric (QMTPUB → collect)
One bind path: attach_lab_air. CLI mints a private lab air when a modem is present; the playground rebinds the same API to a shared AirBus. Multi-node World can put every UE on one fabric so publishes share a collection surface — publisher on one node, subscriber on another.
Send and collect {#send-and-collect}
Firmware does what production firmware does:
AT+QGPS=1
AT+QGPSLOC=0 → parse lat/lon
AT+QMTOPEN=0,"broker…",1883
AT+QMTCONN=0,"client"
AT+QMTPUB=0,0,0,0,"telematics/location",N
> {"lat":…,"lon":…,"src":"qgpsloc"}
Ctrl-Z
→ +QMTPUB: 0,0,0
On submit, the payload is retained on the fabric. That is collect:
- Headless smoke: UART (
GPS fix,location published,+QMTPUB:) andmqtt_fabricassertion that topictelematics/locationholds the JSON. - Playground: fabric strip shows topic + payload.
- Wasm/API:
mqtt_fabric_has_publish,mqtt_fabric_last_payload,mqtt_fabric_inspect(legacycellular_*aliases still work).
Optional: QMTSUB on the same fabric gets +QMTRECV (loopback or a second UE). Still not a carrier — enough for multi-node “message arrived” stories.
Radio quality without a radio {#radio-quality}
When an RfMedium is attached, UE↔cell distance (SimInput Range) drives path loss → dBm → CSQ. Drag range far enough and you get no-service.
MQTT respects that: with RF below the floor, open fails (+QMTOPEN: id,1) and publish does not pretend success. Healthy CSQ: open, connect, and publish follow the AT happy path. Weak radio → no cloud messages.
Try it {#try-it}
Playground board id h735-telematics-lab — Run, open Serial for the AT log, watch the fabric strip collect the MQTT payload.
CLI (from labwired-core):
cargo build -p h735-telematics-lab --release --target thumbv7em-none-eabi
cargo run -q -p labwired-cli -- test \
--script examples/h735-telematics-lab/io-smoke.yaml \
--output-dir /tmp/h735-out --no-uart-stdout
Two UEs (publisher + subscriber) on one fabric: examples/h735-telematics-lab/env-two-ue-smoke.yaml.
Receipts {#receipts}
The same model powers unit tests for fabric publish, loopback +QMTRECV, and RF-gated open; example io-smoke asserting GPS + publish and fabric payload; dual-UE fan-out; and source under examples/h735-telematics-lab/ plus SimMqttFabric in core.
Send messages. Collect data. Don’t fake a network you don’t have. That is the bar for modem + MQTT in LabWired — enough to develop and CI telematics firmware before anyone finds a SIM tray.