Code readingTroubleshooting

Barcode scanner first scan ignored: fix the null previousValue

Your barcode scanner popup opens on the second scan only? The first scan is ignored because previousValue is null on the first change. Fix it with one guard.

LumaSpec Vision9 min read Share on LinkedIn

On this page 9 sections
  1. 01Why does the popup open only on the second scan?
  2. 02What does the 'NoneType' object has no attribute 'value' error mean?
  3. 03How do you fix the script so the first scan fires?
  4. 04How do you prove the fix with logging?
  5. 05Should the change script sit on the data property or the array?
  6. 06Why does scanning the same code twice not fire the popup?
  7. 07Does the scanner or its interface change anything?
  8. 08What checks catch this before production?
  9. 09Questions

You wire a barcode scanner into a web HMI session, scan a part, and nothing happens. The popup opens on the second scan and only on the second scan. The scanner is not the problem: the property-change script on the scanner component's data property compares against a previousValue that does not exist yet on the first change. Here is why the first scan is dropped, what the 'NoneType' traceback means, the one-line guard that fixes it, and the logging test that proves it before the station ships.

Why does the popup open only on the second scan?

Because on the first scan the change script compares currentValue.value against a previousValue that is None, the script stops with an AttributeError before the popup call runs, and only the second scan arrives with a real previousValue to compare against.

The barcode scanner component fires a property-change script every time the watched property — the traceback names it BarcodeScannerInput.props.data — is written. The event hands the script two objects: currentValue for the new value and previousValue for the one before it. On the first write after the session starts there is nothing before it, so the platform passes None for the whole previousValue object, not an object holding a null value.

The original comparison never completes on that first scan:

if currentValue.value != previousValue.value:
    system.perspective.openPopup('myPopupId', 'PopUp')

Reading previousValue.value on None raises AttributeError, the exception goes to the platform log, and on the screen the scan simply looks ignored. The second scan has a previousValue, the comparison runs, the popup opens. That is the reported symptom, exactly.

What does the 'NoneType' object has no attribute 'value' error mean?

It means the script reached for .value on None itself: previousValue was the null object on the first change, so the failure sits at the object level, not inside a value wrapper.

The log entry for this fault reads:

Error running property change script on BarcodeScannerInput.props.data
File "function:valueChanged", line 3, in valueChanged
AttributeError: 'NoneType' object has no attribute 'value'

Line 3 is the comparison. There are two places a null can sit, and the fix depends on knowing which one you have:

  • previousValue is None — the whole object is missing. This is the first-change case.
  • previousValue.value is null — the object exists, its wrapped value is empty.

A guard written as previousValue.value is None or ... still crashes on the first change, because Python evaluates previousValue.value before testing it. That variant was tried on this component and raised the same traceback. The test must run on the object first.

How do you fix the script so the first scan fires?

Test the object before the value — if previousValue is None or previousValue.value != currentValue.value: — because the or short-circuits: when previousValue is None the first half is True and Python never evaluates the .value access that was crashing.

The working script, complete:

# Property-change script on the scanner component's data property.
# currentValue: event object wrapping the new scan value.
# previousValue: event object, or None on the very first change.
# 'myPopupId' and 'PopUp' are your popup id and view name.
if previousValue is None or previousValue.value != currentValue.value:
    system.perspective.openPopup('myPopupId', 'PopUp')

Each half earns its place:

  • previousValue is None fires the action on the first change of the session, where no previous value can exist.
  • previousValue.value != currentValue.value fires it on every genuine value change after that.

Drop the second half and the action fires on every write to the property, including writes that repeat the same value. Drop the first half and you are back to the silent first scan.

How do you prove the fix with logging?

Put one logger line above the if, scan three times, and read the pairs: the first line must show None as the previous value, and with the guard installed the popup must open on that same first scan.

# 'MyLogger' is your logger name; read its output in the platform log.
system.util.getLogger('MyLogger').infof('valueChange(%s, %s)', previousValue, currentValue)
if previousValue is None or previousValue.value != currentValue.value:
    system.perspective.openPopup('myPopupId', 'PopUp')

Run three example scans — 'ABC-001', the same code again, then 'DEF-002' — and the log plus the popup behavior give you this trace:

Scan previousValue currentValue.value previousValue is None != comparison Popup
1 None 'ABC-001' True — short-circuits not evaluated opens
2 wraps 'ABC-001' 'ABC-001' False False suppressed
3 wraps 'ABC-001' 'DEF-002' False True opens

Scan 1 is the fix working: the object test fires before the value test can crash. Scan 2 is a second behavior you have now chosen deliberately, covered below.

Should the change script sit on the data property or the array?

Keep it on the single data property the scanner writes — the traceback's own path, BarcodeScannerInput.props.data, is the correct home — and reach for a subscript after .value only when you deliberately watch an array of queued changes.

A change script runs on whichever property it is attached to. On the scalar data property, one scan is one event with one value to compare. Attached to an array the component fills with change records, every comparison needs an index on both sides — previousValue.value[i] against currentValue.value[i], where i selects the entry you care about. Watching both properties doubles the events and doubles the places the null can appear. One property, one script, one guard.

Why does scanning the same code twice not fire the popup?

Because the second half of the guard only fires when the value differs, an operator who rescans the same code back to back gets one popup, not two — so decide duplicate handling on purpose, not by accident.

Two behaviors, two implementations:

  • Value-changed, what the guard gives you: the same code scanned twice is one event. Right when the popup exists to announce that a new part arrived.
  • Scan-received: every physical scan acts. Compare a token that changes with every decode — a counter or a timestamp — or write the data property back to an empty string after handling, so the next scan is always a change.

Writing to the watched property from inside its own change script fires the script again; that re-entry loop and how to break it is covered in barcode scan event handling without recursive updates.

The compare-against-previous pattern is not specific to HMI scripts. PLC code that detects direction or change from the previous scan value carries the same first-pass trap; direction detection using the previous scan value in PLC code shows the pattern handled on that side.

Does the scanner or its interface change anything?

Not for this fault — the null previousValue is the platform's event contract and hits every reader equally — but the interface decides where the scan string enters the session and who frames it, which changes where your script lives.

A USB keyboard-wedge reader types into whatever field holds focus, so the change lands in an input property the way keystrokes do; scripting that path is covered in barcode scanner to a PLC tag: keyboard wedge scripting. Serial and Ethernet readers push framed strings you parse yourself; the trade-offs are laid out in barcode scanner input methods to a PLC: serial, USB and Ethernet, and the framing pieces in prefix and suffix framing for barcode scanner input.

Once the script is fixed, pick hardware for the station. For a fixed mount over Ethernet, start from the MV-ID3013PM-12M-WBN in the fixed code readers:

Fixed code readersHikrobot MV-ID3013PM-12M-WBN 12mm focal length 1.3 MP Compact Industrial Code ReaderMV-ID3013PM-12M-WBN
Interface
Fast Ethernet
Resolution
Up to 3 MP
Shutter
Global
Lens mount
M12
$1,979.00View part

For USB stations and manual stations, the compact and handheld options:

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
$559.00View part
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
$539.00View part

The MV-ID3013PM-12M-WBN is a compact industrial code reader with a 12 mm focal length and 1.3 MP on Fast Ethernet. The LS-CRD-0047 is a compact fixed reader on USB 2.0 with a 60-120 mm reading distance. The LS-HCR-0001 is the handheld 1.0 MP USB 2.0 option, and both USB units deliver their string into the same kind of input property, so the same guard applies. Browse the full ranges in the reader finder or in handheld code readers.

Scans can also go missing for reasons that are not this script — trigger timing, framing, cabling. The missed-scan checklist for a SCADA-linked scanner runs through those: missed scans from a SCADA-linked barcode scanner.

What checks catch this before production?

Five checks: log both event objects, scan three times (new code, same code, new code), confirm popups on scans 1 and 3, read the log for AttributeError after every script edit, and settle duplicate handling before an operator finds it.

  • Open a fresh session, scan once, and confirm the action fires on that first scan — the null only exists on the first change of a session.
  • Scan the same code twice and confirm the behavior in code matches what the station needs.
  • Keep the logger line in place during commissioning and read it after every edit to the guard.
  • Decide what the script does when the property initializes empty, and code that case once.
  • Give every scan a visible outcome — a popup, a field write, a log line — so a dropped scan is seen the moment it happens.

For the wider station, plan the whole chain before the first script: barcode reader PLC communication: plan a reliable link covers the reader-to-host side. More scanner integration guides sit on the code-reading topic page, and the team answers script and hardware questions through the contact page.

Questions

Do tag change scripts have the same first-fire problem?

They can. Any event that hands you a previous value has a first firing where that value does not exist. The tag change event object identifies which tag changed and carries its new value; log the whole event object once and you will see exactly what the previous field holds on the first fire. Apply the same order: test for the missing object before reading anything from it.

How do you stop the guard firing when the property initializes empty?

Add a non-empty test on the action side: `if (previousValue is None or previousValue.value != currentValue.value) and currentValue.value:`. An initialization write carries an empty string, the truthy test fails, and no popup opens; the first real scan passes both tests. Alternatively, bind the watched property to an empty string at session start so the None case appears only on genuine first changes.

Is the null previous value a fault in the scanner?

No. It is the event contract of the platform: the first change of a property has nothing before it, so the previous value is null by design, on every reader interface. The scanner delivered its string; the script dropped it. For proof, the logger line shows the new value arriving on the first scan while the previous value prints as None.

Can the popup script re-trigger itself?

Yes, if it writes to the property it watches. A change script fires on every write to that property, including writes made from inside the script, so clearing the scan value in the same script re-fires it with the cleared value. Keep state in a different property, or guard the action so an empty value never opens the popup.

How do you test the first scan without a physical scanner?

Write a test value straight into the watched property and watch the logger: the first write after the session opens must show None as the previous value and fire the action, and an identical second write must not. Repeat with a freshly opened session each time, because the None case only exists on the first change of a session.