A Zebra FX9600 is a solid industrial reader: four antenna ports, an IP-rated housing, and a documented LLRP interface. None of that makes it easy to connect to Odoo. The integration work is not in reading tags; it is in configuration discipline, time, and the boundary between what the reader decides and what the ERP is told.
The pattern that survives is unglamorous: standardise on LLRP, use the vendor SDK only where it earns its place, and keep all business logic outside the reader.
Why LLRP is the right layer to standardise on
LLRP is verbose, and that is precisely why it is worth using for the parts that must not change.
- LLRP is an open standard, so the configuration and reporting model survives a change of reader vendor.
- It exposes the concepts that matter operationally: radio profile, antenna configuration, inventory rounds and access operations.
- A ROSpec describes what to read and where to send it; an AccessSpec describes a write or a lock on a specific tag.
- Reports arrive as structured messages, which means the gateway parses fields instead of vendor-specific events.
- The cost is verbosity and a steep learning curve, paid once rather than at every firmware change.
Reader configuration: set once, version it, stop touching it
Most field incidents are configuration drift, not hardware failure.
- Fix the regulatory region and the transmit power explicitly; never rely on the default, which may be illegal locally.
- Choose the RF mode deliberately: dense-reader mode for many tags in a small space, a higher-throughput mode for a conveyor.
- Select the session strategy by traffic pattern; session two is the usual choice where tags move and must be re-read quickly.
- Set a report interval that matches the business cadence; a report every two hundred milliseconds is a firehose for an inventory system.
- Store the full configuration in the repository and apply it from a script, so a replaced reader comes up identical.
The SDK in Python: what it earns and what it does not
The vendor SDK is genuinely useful for a small set of tasks, and a liability for everything else.
- Useful: discovery, firmware queries, health metrics and the occasional low-level diagnostic read.
- Useful: applying an LLRP configuration file to a device without hand-writing XML.
- Not useful: business logic, deduplication or any decision that must be auditable — those belong in your gateway.
- Not useful as the primary event path if you want vendor independence, because the SDK's event model is proprietary.
- Pin the SDK version in the same way as any dependency; an upgrade can silently change default behaviour.
Event filtering before Odoo sees anything
The reader is a good place to discard data, and the ERP is the worst place to discover you did not.
- Apply an RSSI threshold at the reader to remove marginal reads, and record the threshold in the configuration history.
- Filter by EPC prefix when only one client's stock crosses a portal, which removes most of the noise for free.
- Mask unused antenna ports explicitly; an open port with no antenna produces nothing but confusing diagnostics.
- Deduplicate by EPC within a time window at the gateway, not at the reader, so the window is visible and tunable.
- Report the rejected count per antenna, because a sudden rise is the earliest signal of a detuned installation.
Antenna and read-cycle design
Read-cycle settings decide whether the portal sees a fast pallet or only a stationary one.
- One antenna per face of the portal is the reliable pattern; two antennas on the same face need careful phase and timing separation.
- Inventory rounds per report should match the transit time; a pallet crossing in three seconds needs enough rounds inside three seconds.
- Antenna dwell time trades sensitivity against speed; more dwell is better for a slow conveyor and worse for a fast one.
- Test with the pallet loaded the way operations actually loads it, not with a clean demo pallet.
- Record the final power, mode and dwell per portal on a drawing that the next technician can read.
Failure handling: sessions, reconnects and duplicated reads
A dropped TCP session is normal operation, and the design has to treat it that way.
- Expect LLRP sessions to drop on network events; implement reconnect with backoff and a bounded retry count.
- On reconnect, do not replay old reads as new events; use the reader's event time to discard anything stale.
- Keep a local spool so an outage delays data rather than losing it, and let the gateway drain the spool after recovery.
- Watch for duplicated reads across two readers covering the same zone; the gateway's deduplication must be global, not per reader.
- Alert on repeated reconnects as a network problem, because a flapping link is usually cabling or PoE, not firmware.
Deployment: network, firmware and time
Three infrastructure decisions cause more incidents than the RFID design itself.
- Put readers on a dedicated VLAN with predictable addressing, and document the PoE budget per switch port.
- Pin firmware per site and test upgrades in a lab portal first, because RF behaviour can shift between releases.
- Synchronise reader clocks with NTP; an unsynchronised reader produces events that look out of order during reconciliation.
- Reserve fixed addresses or DHCP reservations, so a replaced unit does not acquire a new identity in the gateway.
- Keep a spare reader pre-configured, because the failure mode that hurts is the one at the busiest dock.
A working integration sequence
The sequence is deliberately slow at the start, because the alternative is slow at the end.
- Step one: a single reader on a bench, LLRP configured, one tag read and logged by the gateway, no Odoo write.
- Step two: the same reader at one portal in shadow mode for a week, comparing its reads against the manual process.
- Step three: enable writes for that portal only, with the old process still available as a fallback.
- Step four: expand portal by portal, watching rejected reads and reconciliation gaps rather than tag counts.
- Step five: hand over with a configuration repository, a runbook for replacing a reader, and a reconciliation report.






