Three views in one HMI project, each with its own scan button, and every decoded string lands in the same tag. When the barcodes are near-identical, no amount of post-processing can tell you which view produced which string. Stop trying to separate the scans by content and carry the view's identity alongside the payload instead. Set a custom session property to the view's key just before each scan — or attach the key as context on the Scan Barcode action — then read it in the Barcode Scanned session event and write the string into the tag that key selects. This guide walks through the property, the event script, the action-context alternative, a three-view test, and the ordering mistakes that quietly send a scan to the wrong station.
What you need
- An HMI project where scanning is session-level: each view carries a Scan Barcode action, and the project exposes a session-level Barcode Scanned event in its Session Events configuration.
- One custom session property:
activeScanView, type string, initial value"". Empty means no view has armed a scan. - Three destination tags, one per view — internal tags or controller paths. The routing table in step 3 only holds paths, so either kind works.
- Script write access from the session event to those tags.
Session properties are scoped per client, not global: every open client carries its own copy, the same rule that keeps a scanner session property per user instead of shared. Two tablets scanning in parallel therefore never overwrite each other's view key.
Why content cannot tell the views apart
The built-in scan-to-tag binding writes whatever the scanner returns into one fixed tag. It never knows which view fired the scan, and three near-identical strings in one tag are indistinguishable afterwards. So route by origin, not content. The view already knows which station it belongs to before the camera starts looking, and that fact is free. The decoded string is never modified — only its destination changes — which keeps the payload exactly what the scanner returned.
Step 1: add the custom session property
- Open the project's session properties and add a custom property named
activeScanView, type string, default"". - Keep the default empty: an empty key is the unarmed state, and the event script treats it as nothing to route.
- Choose short, stable keys —
viewA,viewB,viewC— because the same strings must appear in the routing table and in every scan button's write.
The name is yours to pick; the platform's manual demonstrates the same pattern with a session property called scannerInput that a session event updates. What matters is that one session-scoped string holds the armed view.
Step 2: write the view name before each scan
- On each view, open the event chain that triggers the scan — normally the scan button's press event.
- Add a step that writes
activeScanViewwith that view's key:viewAon view A,viewBon view B, and so on. - Keep the property write and the Scan Barcode action in the same chain, write first: the key must be in place before the scan starts.
- If one shared view template serves several pages, read the page's URL parameter for the key instead of hardcoding it.
Order is the whole trick. A property write that lands after the scan action leaves the previous view's key armed, and the string goes to the wrong tag with no error anywhere.
Step 3: route the string in the Barcode Scanned event
- Open the project's Session Events and add a script to the Barcode Scanned event.
- Check the platform's scripting documentation for your release: it shows the exact names the Barcode Scanned event passes to the script and how to read them. Confirm those names before you paste the body below.
- Use the script below as the routing body:
barcodeandcontextare the payload names,activeScanViewthe property from step 2, andtagWritestands in for your platform's tag-write call.
# Barcode Scanned session event
# barcode : str, decoded string, '' when nothing decoded
# context : dict, key/value pairs attached to the Scan Barcode action
# activeScanView : str, session property from step 2, '' when unarmed
TAG_PATHS = { # dict: view key -> destination tag path (str)
'viewA': '[default]Line1/StationA/lastScan',
'viewB': '[default]Line1/StationB/lastScan',
'viewC': '[default]Line1/StationC/lastScan',
}
viewKey = context.get('view', '') # str: action context wins
if viewKey == '':
viewKey = activeScanView # str: session property is the fallback
if viewKey in TAG_PATHS and barcode != '':
tagWrite(TAG_PATHS[viewKey], barcode) # tag write; 1000 ms timeout is ample
Keep both guards: an unknown key or an empty string writes nothing, and no update beats a wrong update. Two related patterns drop straight into this event. Keep any write-back non-recursive, as in scan event handling without recursive updates. And if the destination PLC clears the string one scan cycle later, latch it on the pulse, as in scan string disappears after one PLC scan.
Alternative: context on the Scan Barcode action
The session event can also read static key/value pairs attached to the Scan Barcode action itself. On each view, open the action's configuration and add one pair — key view, value viewA — then repeat per view. The event reads the context first and needs no session property at all.
| Situation | Use |
|---|---|
| Every view owns its scan action | Action context: one key/value pair per action, no ordering constraint |
| One shared trigger starts scans, or other scripts need the current view | Session property, written before the scan |
| One view template duplicated across pages | Session property, key read from the page URL parameter |
Keep the property read as the fallback even when every action carries context, so a view that loses its key/value pair still routes instead of dropping the scan.
Test the routing
- Arm view A and scan a test code, for example
LOT-4501-A. - Check that
Line1/StationA/lastScanholdsLOT-4501-A, whileStationB/lastScanandStationC/lastScankeep their previous values — empty on a fresh project. - Repeat on views B and C with
LOT-4502-BandLOT-4503-C. - Scan a second code from view A and confirm only
StationA/lastScanchanges. - Write
""intoactiveScanViewfrom a test button, scan again, and confirm nothing is written anywhere.
| Scan fired from | Armed key | Tag that changes | Value after |
|---|---|---|---|
| View A | viewA |
Line1/StationA/lastScan |
LOT-4501-A |
| View B | viewB |
Line1/StationB/lastScan |
LOT-4502-B |
| View C | viewC |
Line1/StationC/lastScan |
LOT-4503-C |
| Unarmed session | "" |
none | unchanged |
Write a scan timestamp next to each routed string. A fresh timestamp on a stale value is the signature of a misroute, and per-station timing data is worth keeping anyway — the scan timestamps per workstation pattern gives you the tag layout.
Common mistakes
- Property written after the scan action: the string routes on the previous key. Fix — write first, scan second, same chain.
- View key kept in a view-local property: the Barcode Scanned event is session-level and cannot read it. Fix — session property or action context.
- Shared scan action with no context and nothing armed: every scan lands in the unknown-key branch and nothing is written. Fix — URL parameter or per-action context.
- Empty results written through: a failed scan wipes a good lot number. Fix — keep the empty-string guard.
- Back-to-back scans in one session: the second scan re-arms while the first event is still running. Fix — disable the trigger until the event completes, or queue the reads the way a PLC barcode handshake queues every scan.
When the scan comes from a line-side reader
None of this applies to hardware scanners. A fixed reader delivers the decoded string over Ethernet or serial, the HMI session event never fires, and routing belongs in the PLC: a station number travelling with each read selects the destination — the same origin-not-content idea in ladder logic. Wire the reader as a TCP server with the PLC as the client, pick the physical link from the scanner input methods to a PLC, then split the string into lot and part fields before it reaches the tags. If part of the plant runs a different HMI, the same context-scoping trick exists there: the tag prefix property for picture windows scopes tag addressing to a window instead of a session.
For stations that read a code printed on the part, a fixed code reader sends the decoded string straight to the controller. The MV-ID3013PM-12M-WBN has a 12 mm focal length and a Fast Ethernet interface.
- Interface
- Fast Ethernet
- Resolution
- Up to 3 MP
- Shutter
- Global
- Lens mount
- M12
Dense or small codes need more pixels: the LS-CRD-0028 captures 2560 x 2048 frames at 30 fps, up to 60 codes/s, through an 8 mm lens.
- Interface
- Fast Ethernet
- Resolution
- 5 MP
- Sensor format
- 1/1.7"
- Shutter
- Global
Bench checks that read at 60-120 mm fit the LS-CRD-0047 over USB.
- Resolution
- Up to 3 MP
- Shutter
- Global
- Interface
- USB
When one view must inspect the part as well as read the code, smart cameras run the inspection on the device, and glare on shiny labels is usually a lighting problem — code reader accessories carry the light boards and polarizing covers that clean it up.
The decision
Route by origin, not content. Arm the view with a session property or an action-context key, route in the Barcode Scanned event, keep the empty-string and unknown-key guards on the write, and add a timestamp so a misroute shows itself. When scans come from line-side hardware instead of the HMI client, move the same origin-not-content routing into the PLC. To pick hardware for that path, start from the camera finder or configure a station around a reader; more read-path patterns sit on the code-reading topic page.
Questions
Does the session property keep views apart when several clients scan at once?
Yes. A custom session property lives in one client session, so each tablet carries its own activeScanView and its scan events read their own value; two operators scanning in parallel never overwrite each other's key. What can still collide is two scans fired back-to-back inside one session before the first event finishes — disable the trigger until the event completes, or queue the reads.
Can the event write into a PLC tag instead of an internal HMI tag?
Yes. The routing logic only picks a tag path; whether that path points at an internal tag or a controller tag is your choice in the routing table. Use the platform's tag-write call with a timeout — 1,000 ms is a common value — and check the write result before clearing the scan state, so a failed write does not silently drop a lot number.
What happens when all three views share one view template?
Hardcoding a key per view stops working when one template serves all three pages. Give each page instance a URL parameter carrying its key, read that parameter in the scan button's event, and write it into the session property. The routing table and event script stay unchanged, and a duplicated template can no longer arm the wrong key.
Does a failed or empty scan wipe the destination tag?
Not if you guard the write. The Barcode Scanned event still fires, and an empty or failed result must not be written anywhere — otherwise it wipes a good lot number. Keep the empty-string check, and count failed attempts per view in a separate tag if the station needs scan-success statistics or an operator prompt to rescan.
Is one session property enough for four or more views?
Yes. The property holds one short string and the routing table scales to as many entries as you need. Keep the keys stable, mirror every key into the table, and walk the table once at startup so a renamed or deleted view surfaces immediately instead of quietly routing scans to nothing.


