ASQUARETE

Case study

Inventory counts from 4 hours to 11 minutes — Chainway C72 + Odoo, 8,000-SKU warehouse

A distribution warehouse ran cycle counts by hand against 8,000 SKUs. A Chainway C72 bulk-read pipeline with server-side dedup cut a 4-hour count to 11 minutes and posted adjustments straight into Odoo.

Device · Chainway C72Role · Android integration + Odoo backendStack · Android, Kotlin, Chainway UHF SDK, Odoo, JSON-RPC

A mid-sized distribution warehouse — roughly 8,000 active SKUs across pallet racking and a bin-shelf overflow area — ran cycle counts the way most warehouses do: a two-person team with clipboards, walking rows, reconciling against an Odoo inventory export at the end of the day. A full count took the better part of a shift. Nobody trusted the numbers by the time they were typed in, because the count and the entry were separated by hours and a stack of paper.

The ask was narrow: get a UHF handheld into the warehouse, have it read tagged pallets and bins in bulk, and land the counts in Odoo as inventory adjustments without a human retyping anything.

The problem

Every SKU already had an RFID tag from an earlier labeling pass, but nothing read them in bulk. The existing process was a barcode scanner used one item at a time, which doesn't change the fundamental math — you're still walking to every location. The warehouse needed a device that could stand at the end of an aisle, trigger a read, and pick up every tag in range in one pass, then needed that raw tag data turned into something Odoo's inventory model would accept without a human reconciling a spreadsheet.

The other half of the problem was noise. A bulk UHF read in a dense pallet stack returns duplicate reads of the same tag, phantom reads from adjacent aisles bleeding through, and the odd tag that didn't answer at all because of orientation. Raw scan data is not count data; it has to be cleaned before it means anything.

Hardware used

ItemRole
Chainway C72Handheld UHF RFID reader, Android 11, integrated pistol-grip antenna
Chainway UHF SDKTag inventory API — continuous read, RSSI + antenna metadata per tag
Odoo 17 (Inventory app)System of record — stock quants, inventory adjustments
On-prem Linux hostJSON-RPC bridge between the Android app and Odoo's external API

Architecture

The C72 runs a Kotlin app built against Chainway's inventory SDK. The operator selects a zone (a set of bin locations), holds the trigger, and walks the aisle once. The SDK streams raw EPC reads with RSSI and read-count as they come in; the app buffers them locally rather than pushing per-tag network calls, since a single pass can return several thousand raw reads for a few hundred distinct tags.

[C72 trigger hold]
      |
      v
[SDK: continuous inventory stream]
      |  raw reads: EPC, RSSI, antenna, timestamp
      v
[On-device dedup + RSSI floor filter]
      |  distinct EPCs, read-count, avg RSSI
      v
[Batch POST -> on-prem bridge service]
      |  JSON-RPC: stock.quant + Odoo inventory adjustment
      v
[Odoo Inventory: draft adjustment for review]

Deduplication happens on-device: EPCs are grouped, read-count and average RSSI are attached, and anything below a tuned RSSI floor is dropped as a probable cross-aisle bleed-through rather than a real read at that location. The cleaned distinct-EPC list is batched and POSTed to a small on-prem bridge service, which maps EPC to SKU (via a lookup table populated at labeling time) and writes an Odoo inventory adjustment through JSON-RPC — landing as a draft adjustment, not an auto-applied one, so a supervisor still confirms before stock levels change.

What was tricky

The RSSI floor was the whole project, honestly. Set it too low and the app counted tags from the next aisle over as being in the current zone, inflating counts. Set it too high and it dropped legitimate reads from tags on the far side of a dense pallet, undercounting. There's no single correct threshold — it changes with aisle width, pallet density, and even how full a rack is that week. What ended up working was zone-relative calibration: a short "walk the zone empty-handed" baseline read at setup time per aisle, rather than one global constant baked into the app. That added a setup step nobody asked for, but a fixed threshold produced counts the warehouse manager didn't trust on the first week of testing, and trust was the actual deliverable here, not just a number.

The second snag was EPC-to-SKU mapping drift — tags applied during an earlier labeling pass didn't perfectly match the lookup table after a mid-year SKU renumbering. Reads that didn't resolve to a known SKU were flagged in a review queue rather than silently dropped, which surfaced the mismatch in week one instead of it quietly corrupting counts for months.

Result

A full-warehouse cycle count that took roughly 4 hours with two people now runs in about 11 minutes of active scanning time by one person, followed by a supervisor review-and-post step in Odoo that takes another few minutes. Draft adjustments are reviewed rather than auto-applied, so the system caught and corrected about a dozen mapping mismatches in the first two weeks without any stock data being wrongly overwritten. The warehouse now runs cycle counts weekly instead of monthly, since the labor cost of a count dropped by roughly 90%.


Role · Android integration + Odoo backend

Stack · Android, Kotlin, Chainway UHF SDK, Odoo, JSON-RPC

Updated Feb 3, 2026

Similar hardware on your desk?

Send the device model, the SDK, and what's failing. You get a written feasibility read within 24 hours.

Get a feasibility read

Another case study