Code readingHow-to

Barcode scan results in a session property: read the last value

Where a mobile HMI puts each barcode scan result, how to bind a display to the session property's last element, guard the empty state, and avoid stale reads.

LumaSpec Vision8 min read Share on LinkedIn

On this page 10 sections
  1. 01Where the scan result actually lands
  2. 02What you need
  3. 03Read the last scan: the steps
  4. 04Fire the trigger where the client can run it
  5. 05Guard the empty array and the repeat scan
  6. 06Trim the array: a worked size example
  7. 07When the value must reach the machine, not the screen
  8. 08When the device camera is the wrong reader
  9. 09Ship checklist
  10. 10Questions

You wired the scan action to a button, the phone opens its camera, the code reads green — and your script still has no string to work with. That is how web and mobile HMI clients behave: a scan never returns a value to the component that triggered it. The decoded result is appended to a session-level property, an array that collects every scan the client session makes, and reading that array's last element is the whole trick. This guide gives you the binding, the empty-state guard, the trigger rules, and the two failure modes that catch most projects: repeat scans that look like no scan at all, and arrays that grow for weeks.

Where the scan result actually lands

A client-side scan action runs on the device: it opens the camera, decodes the code, and hands over nothing to the button. The result is appended to a session property instead. In the platform family this recipe targets, the array lives at session.props.device.barcodes, one element per scan, newest last, and each element is an object whose decoded text sits in data.text. Later releases add a scan-input component that loads the same string, prefix and suffix stripped, into its own data property. Read whichever one your view uses; the last-element pattern is identical.

Getting the scan to happen in a browser at all is its own task: see scanning barcodes in a web HMI with camera access and the choice between the native app route and browser camera access.

What you need

  • A view with a button whose click event runs the platform's Scan Barcode action
  • A display component; a label is enough
  • Read access to the session results array (session.props.device.barcodes in the layout above)
  • The operator's actual phone or tablet, with the HMI's mobile client installed

Read the last scan: the steps

  1. Trigger from a component event. Add a button to the view and set its click event to run the Scan Barcode action. It is a client-side action, so it must start from something the client renders.
  2. Bind the label to the array. Set the label's text binding to the session results property, session.props.device.barcodes.
  3. Guard the empty state. Add a script transform to that binding. It receives the whole array and returns what the label should show.
  4. Test on the device. Scan a known code and compare the label to the printed string, character for character.
  5. Fan the value out if you must. When something other than the label needs the scan, write it to a tag from the session event (the Barcode Scanned type) rather than reading the array later.
if len(value) == 0:
    return "No scan yet"
return value[-1].data.text

From session start until the first scan, len(value) == 0 is true and the label shows the placeholder. After the first scan, value[-1].data.text is always the most recent decode, because every scan appends one element to the end of the array.

Fire the trigger where the client can run it

A view lifecycle event such as onStartup runs server-side. The Scan Barcode action runs on the client device, and a server-side script cannot drive it: the script context there is not the component wrapper, so a call written as self.view... ends in an attribute error. This is a placement problem, not a syntax problem. Start the scan from a component event on the view; if the workflow needs a scan without a keypress, put an obvious Scan button on the screen rather than trying to open the phone's camera from the server.

Guard the empty array and the repeat scan

The placeholder covers the fresh session. The nastier case is the repeat scan: scanning the same label twice appends a second, identical element, so the array length goes from 1 to 2 while the text stays the same, character for character. A label bound to value[-1].data.text redraws the same string, and any logic keyed on the displayed text changing misses the second scan entirely. Key that logic on the array length, or run it from the scan event itself.

This is the same class of bug as a property read returning a stale value on repeated reads: an identical value reads as no change. If the screen should show nothing until the first scan, return an empty string in the transform and hide the label — the pattern in guarding a barcode display against empty values.

Trim the array: a worked size example

The array is append-only for the life of the session, and shop tablets stay logged in for weeks. The memory itself is small; the rendering is what bites. Assume 200 bytes per entry — decoded text plus object overhead — and 500 scans a day on a shared terminal. Over a 30-day session that is 500 × 30 = 15,000 entries, and 15,000 × 200 B = 3,000,000 B ≈ 3 MB of session data. Three megabytes will not hurt the client. A table bound to all 15,000 rows, re-evaluated on every scan, will.

Cap what the screen sees: copy the last N entries into a view-scoped property and bind history to that. It is the classic PLC pattern — a circular buffer holding the last 20 test results for an HMI — applied to a session property. Twenty to fifty entries covers every history an operator acts on. At the 200-byte estimate, a 20-entry cap holds 20 × 200 B = 4,000 B ≈ 4 KB, so every redraw moves a couple of dozen rows instead of 15,000.

When the value must reach the machine, not the screen

A session property is UI state: no delivery guarantee, no acknowledgment, and it disappears with the session. Display from it; do not control from it. The moment the scan must release a gate, log a lot, or select a program, move the value over a real path — a handler on the Barcode Scanned session event writes to a tag, and the PLC handshakes on that tag. The queue-every-scan wiring is in the PLC-to-HMI barcode handshake, and per-view routing is in routing scan data to tags by view with a session property.

Remember too that each client session keeps its own array: one tablet never sees another's scans, which is the argument behind session properties per user rather than a shared tag.

When the device camera is the wrong reader

A phone camera reads printed labels at hand range and gives up on direct-part-mark codes, small modules, and anything past arm's length. When the station is fixed, a fixed code reader mounted at a specified distance reads the same code every cycle. When the operator walks to the part, a handheld code reader is the tool. If the station also inspects, smart cameras fold the read and the check into one device. A wired reader reaches the HMI by its own route — keyboard wedge or serial — not through the session array; the USB reader as a keyboard wedge covers the common case.

For a close-range presentation mount, pick a reader whose specified distance covers it. The LS-CRD-0047 is a compact fixed reader rated for a 60-120 mm reading distance, built on a 1.2 MP sensor over USB 2.0.

Fixed code readersCompact fixed industrial barcode reader, 1.2 MP, USB 2.0, 60-120 mm reading distance (LS-CRD-0047)LS-CRD-0047
Resolution
Up to 3 MP
Shutter
Global
Interface
USB
$559.00View part

Manual stations want the same discipline in the hand. The LS-HCR-0001 is a 1.0 MP handheld reader on USB 2.0 with a global shutter.

Handheld code readersHandheld industrial barcode reader, 1.0 MP, USB 2.0 (LS-HCR-0001)LS-HCR-0001
Resolution
Up to 3 MP
Shutter
Global
Interface
USB
Connection
Wired
$539.00View part

Use the code-reader and camera finder to compare the rest of the range, and match the specified reading distance to your mount before you order.

Ship checklist

  • Trigger the scan from a component event; lifecycle scripts run server-side and cannot open the device camera.
  • The label binding reads the array; the transform guards len(value) == 0 and returns value[-1].data.text.
  • Prove it on the operator's actual device — desktop previews do not prove phone camera behavior.
  • Key repeat-scan logic on the array length or the scan event, not on the displayed text changing.
  • Render history from a capped property, 20-50 entries, never the raw array.
  • Handshake machine-facing scans through a tag; treat the session property as display-only.

If the codes on your parts defeat the device camera, send a photo of the code, its size, and the mounting distance through the contact page, and we will help you match a reader. The code-reading topic page gathers the scan-integration guides, from serial framing to PLC handshakes.

Questions

Do session barcode results survive a page refresh?

No. The array belongs to the client session, so a refresh, a reconnect, or a closed app starts a clean array and the label falls back to the empty-state placeholder. Treat the session property as a screen scratchpad. If the record matters — lot traceability, scan counts, audit trails — write each scan to a tag or database from the scan event handler at the moment it fires, not later from the array.

Is the barcode results array shared between two tablets?

No. Session properties are scoped to one client session, so each tablet accumulates its own array and its own last value; an operator on device A never sees device B's scan. That isolation is usually what you want for per-station screens. When several devices must act on the same scan, publish it to a shared tag from the scan event and let every client read the tag instead of their local array.

How do I show the last ten scans instead of only the newest?

Bind a table to the array and reverse the order in a transform so the newest row sits on top. A slice that keeps value[-10:] limits what the table renders; the array itself still holds the whole session. Give the table its own empty state for the zero-scan case. On screens that scan hundreds of codes an hour, cap the render — the table re-sorts on every scan, and a thousand-row redraw on each beep is real latency.

What reader handles direct-part-mark codes the phone camera keeps missing?

DPM codes need controlled light and real optics, so move to an industrial reader: a fixed code reader mounted at a repeatable distance for station scanning, or a handheld industrial reader where an operator presents the tool. Note the symbology, module size, surface finish, and the mounting distance you can hold, then match a reader whose specified reading distance covers it. Send code samples through the quote route and we will help you narrow the list.