Station flow: ID first, EAN optional, re-measure by ID
Every run opens with the freshly allocated L#### and then asks for the EAN, which Enter skips. Typing an existing ID re-measures that lamp with all identification and rated values pre-filled, which also rewrites old bundles in the current metrics format. Unused IDs are never burned since numbering derives from written bundles.
This commit is contained in:
@@ -97,9 +97,13 @@ end to end. Every lamp gets an internal ID (L0001, L0002, ...) as primary key;
|
||||
the EAN barcode is optional metadata, so one barcode can cover daylight/warm
|
||||
white variants (distinct IDs + variant field) and unbranded lamps work too.
|
||||
|
||||
Per lamp: scan the box (or 'n' for no barcode), the EAN is checksum-validated
|
||||
and resolved to manufacturer/model (previously measured lamps, local cache,
|
||||
then upcitemdb.com; GS1-restricted 20-29 barcodes are flagged as
|
||||
Every run opens with a freshly allocated ID (the ID only becomes real once a
|
||||
bundle is written, so aborting never burns a number). Then: scan the box's EAN
|
||||
(optional, Enter skips it), or type an existing ID like L0004 to re-measure
|
||||
that lamp with everything pre-filled, which also rewrites its bundle in the
|
||||
current metrics format. Scanned EANs are checksum-validated and resolved to
|
||||
manufacturer/model (previously measured lamps, local cache, then
|
||||
upcitemdb.com; GS1-restricted 20-29 barcodes are flagged as
|
||||
retailer-internal), lamps already measured under the same EAN are offered for
|
||||
re-measurement, you confirm the identification and type the ADVERTISED values
|
||||
from the packaging (flux, CCT, power, CRI, lifetime, equivalent W -> stored
|
||||
|
||||
+42
-28
@@ -7,11 +7,15 @@ EAN barcode is optional metadata. This keeps lamps distinct when one barcode
|
||||
covers several versions (daylight / warm white in the same box art) and
|
||||
supports unbranded lamps without any barcode.
|
||||
|
||||
1. Scan the box with a keyboard-wedge barcode scanner (types EAN + Enter),
|
||||
or type 'n' for a lamp without a barcode.
|
||||
2. The EAN is checksum-validated. Lamps already measured with the same
|
||||
EAN are listed: pick one to re-measure, or continue as a new lamp
|
||||
(that is how same-EAN variants get their own IDs). Identification is
|
||||
1. Every run opens with a freshly allocated ID (L0012, ...). The ID only
|
||||
becomes real once the bundle is written, so aborting never burns one.
|
||||
2. Scan the box with a keyboard-wedge barcode scanner (types EAN +
|
||||
Enter), press Enter for a lamp without a barcode, or type an existing
|
||||
ID (e.g. L0004) to re-measure that lamp with everything pre-filled,
|
||||
which also rewrites its bundle in the current metrics format. Scanned
|
||||
EANs are checksum-validated; lamps already measured with the same EAN
|
||||
are listed (pick one to re-measure, or continue as the new lamp: that
|
||||
is how same-EAN variants get their own IDs). Identification is
|
||||
suggested from previous lamps, a local cache, then upcitemdb.com
|
||||
(best effort; GS1-restricted 20-29 barcodes skip the online lookup).
|
||||
3. Confirm or edit manufacturer / model / variant / notes, then type the
|
||||
@@ -203,31 +207,32 @@ def commit_bundle(data_repo, lamp_id, label, existed, push):
|
||||
print("Pushed.")
|
||||
|
||||
|
||||
def measure_one(ean, args, data_repo):
|
||||
lamps = lamp_index(data_repo)
|
||||
|
||||
# Same-EAN lamps already in the database: re-measure or new variant.
|
||||
lamp_id, previous = None, {}
|
||||
if ean:
|
||||
def measure_one(new_id, ean, lamps, args, data_repo, existing_id=None):
|
||||
# The run already owns its fresh ID (new_id). Typing an existing ID at
|
||||
# the scan prompt re-measures that lamp instead (all its identification
|
||||
# pre-filled, bundle rewritten in the current format); an EAN may also
|
||||
# redirect to a re-measure when it matches an existing lamp.
|
||||
lamp_id, previous = new_id, {}
|
||||
if existing_id:
|
||||
lamp_id = existing_id
|
||||
previous = lamps[existing_id]
|
||||
ean = previous.get("ean", "")
|
||||
print(f" Re-measuring {lamp_id}" + (f" (EAN {ean})" if ean else ""))
|
||||
elif ean:
|
||||
same = {i: m for i, m in lamps.items() if m.get("ean") == ean}
|
||||
if same:
|
||||
print(" Lamps already measured with this EAN:")
|
||||
for i, m in same.items():
|
||||
variant = f", {m['variant']}" if m.get("variant") else ""
|
||||
print(f" {i}: {m.get('manufacturer', '')} {m.get('model', '')}{variant}")
|
||||
choice = prompt("Re-measure one of these (type its ID) or Enter for a NEW lamp/variant").strip()
|
||||
choice = prompt(f"Re-measure one of these (type its ID) or Enter to continue as {new_id}").strip()
|
||||
if choice:
|
||||
if choice.upper() not in same:
|
||||
print(f" Unknown ID {choice!r}, aborting this scan.")
|
||||
print(f" Unknown ID {choice!r}, aborting this run.")
|
||||
return
|
||||
lamp_id = choice.upper()
|
||||
previous = same[lamp_id]
|
||||
|
||||
if lamp_id is None:
|
||||
lamp_id = next_lamp_id(data_repo)
|
||||
print(f" New lamp: {lamp_id}" + (f" (EAN {ean})" if ean else " (no barcode)"))
|
||||
else:
|
||||
print(f" Re-measuring {lamp_id}")
|
||||
print(f" Re-measuring {lamp_id}")
|
||||
|
||||
if previous:
|
||||
manufacturer, model = previous.get("manufacturer", ""), previous.get("model", "")
|
||||
@@ -323,25 +328,34 @@ def main():
|
||||
print(f"ERROR: {data_repo} is not a git checkout of comparison-data.")
|
||||
sys.exit(1)
|
||||
|
||||
print("Lamp station ready. Scan a barcode, 'n' for a lamp without one, 'q' to quit.")
|
||||
print("Lamp station ready. Every run starts a new lamp ID; the EAN is optional")
|
||||
print("(scan it, or press Enter to skip). 'q' quits.")
|
||||
while True:
|
||||
# A fresh ID opens every run. It only becomes real once a bundle is
|
||||
# written, so quitting or re-measuring never burns a number.
|
||||
lamps = lamp_index(data_repo)
|
||||
new_id = next_lamp_id(data_repo)
|
||||
print(f"\n--- New lamp {new_id} ---")
|
||||
try:
|
||||
code = input("\nScan barcode: ").strip()
|
||||
code = input("Scan EAN (Enter to skip, L#### re-measures an existing lamp, q quits): ").strip()
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
break
|
||||
if code == "":
|
||||
continue
|
||||
if code.lower() in ("q", "quit", "exit"):
|
||||
break
|
||||
if code.lower() in ("n", "none"):
|
||||
ean = ""
|
||||
else:
|
||||
existing_id = None
|
||||
ean = ""
|
||||
if ID_RE.match(code.upper()):
|
||||
existing_id = code.upper()
|
||||
if existing_id not in lamps:
|
||||
print(f" No lamp {existing_id} in the database.")
|
||||
continue
|
||||
elif code and code.lower() not in ("n", "none"):
|
||||
ean = ean_normalize(code)
|
||||
if not ean:
|
||||
print(f" Not a valid EAN-13/UPC-A: {code!r}")
|
||||
print(f" Not a valid EAN-13/UPC-A: {code!r} (Enter would skip the EAN)")
|
||||
continue
|
||||
try:
|
||||
measure_one(ean, args, data_repo)
|
||||
measure_one(new_id, ean, lamps, args, data_repo, existing_id=existing_id)
|
||||
except KeyboardInterrupt:
|
||||
print("\n Aborted; lamp skipped. (PSU is switched off by the driver.)")
|
||||
except (subprocess.CalledProcessError, SystemExit) as e:
|
||||
|
||||
Reference in New Issue
Block a user