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
|
the EAN barcode is optional metadata, so one barcode can cover daylight/warm
|
||||||
white variants (distinct IDs + variant field) and unbranded lamps work too.
|
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
|
Every run opens with a freshly allocated ID (the ID only becomes real once a
|
||||||
and resolved to manufacturer/model (previously measured lamps, local cache,
|
bundle is written, so aborting never burns a number). Then: scan the box's EAN
|
||||||
then upcitemdb.com; GS1-restricted 20-29 barcodes are flagged as
|
(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
|
retailer-internal), lamps already measured under the same EAN are offered for
|
||||||
re-measurement, you confirm the identification and type the ADVERTISED values
|
re-measurement, you confirm the identification and type the ADVERTISED values
|
||||||
from the packaging (flux, CCT, power, CRI, lifetime, equivalent W -> stored
|
from the packaging (flux, CCT, power, CRI, lifetime, equivalent W -> stored
|
||||||
|
|||||||
+40
-26
@@ -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
|
covers several versions (daylight / warm white in the same box art) and
|
||||||
supports unbranded lamps without any barcode.
|
supports unbranded lamps without any barcode.
|
||||||
|
|
||||||
1. Scan the box with a keyboard-wedge barcode scanner (types EAN + Enter),
|
1. Every run opens with a freshly allocated ID (L0012, ...). The ID only
|
||||||
or type 'n' for a lamp without a barcode.
|
becomes real once the bundle is written, so aborting never burns one.
|
||||||
2. The EAN is checksum-validated. Lamps already measured with the same
|
2. Scan the box with a keyboard-wedge barcode scanner (types EAN +
|
||||||
EAN are listed: pick one to re-measure, or continue as a new lamp
|
Enter), press Enter for a lamp without a barcode, or type an existing
|
||||||
(that is how same-EAN variants get their own IDs). Identification is
|
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
|
suggested from previous lamps, a local cache, then upcitemdb.com
|
||||||
(best effort; GS1-restricted 20-29 barcodes skip the online lookup).
|
(best effort; GS1-restricted 20-29 barcodes skip the online lookup).
|
||||||
3. Confirm or edit manufacturer / model / variant / notes, then type the
|
3. Confirm or edit manufacturer / model / variant / notes, then type the
|
||||||
@@ -203,30 +207,31 @@ def commit_bundle(data_repo, lamp_id, label, existed, push):
|
|||||||
print("Pushed.")
|
print("Pushed.")
|
||||||
|
|
||||||
|
|
||||||
def measure_one(ean, args, data_repo):
|
def measure_one(new_id, ean, lamps, args, data_repo, existing_id=None):
|
||||||
lamps = lamp_index(data_repo)
|
# 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
|
||||||
# Same-EAN lamps already in the database: re-measure or new variant.
|
# pre-filled, bundle rewritten in the current format); an EAN may also
|
||||||
lamp_id, previous = None, {}
|
# redirect to a re-measure when it matches an existing lamp.
|
||||||
if ean:
|
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}
|
same = {i: m for i, m in lamps.items() if m.get("ean") == ean}
|
||||||
if same:
|
if same:
|
||||||
print(" Lamps already measured with this EAN:")
|
print(" Lamps already measured with this EAN:")
|
||||||
for i, m in same.items():
|
for i, m in same.items():
|
||||||
variant = f", {m['variant']}" if m.get("variant") else ""
|
variant = f", {m['variant']}" if m.get("variant") else ""
|
||||||
print(f" {i}: {m.get('manufacturer', '')} {m.get('model', '')}{variant}")
|
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:
|
||||||
if choice.upper() not in same:
|
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
|
return
|
||||||
lamp_id = choice.upper()
|
lamp_id = choice.upper()
|
||||||
previous = same[lamp_id]
|
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:
|
if previous:
|
||||||
@@ -323,25 +328,34 @@ def main():
|
|||||||
print(f"ERROR: {data_repo} is not a git checkout of comparison-data.")
|
print(f"ERROR: {data_repo} is not a git checkout of comparison-data.")
|
||||||
sys.exit(1)
|
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:
|
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:
|
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):
|
except (EOFError, KeyboardInterrupt):
|
||||||
break
|
break
|
||||||
if code == "":
|
|
||||||
continue
|
|
||||||
if code.lower() in ("q", "quit", "exit"):
|
if code.lower() in ("q", "quit", "exit"):
|
||||||
break
|
break
|
||||||
if code.lower() in ("n", "none"):
|
existing_id = None
|
||||||
ean = ""
|
ean = ""
|
||||||
else:
|
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)
|
ean = ean_normalize(code)
|
||||||
if not ean:
|
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
|
continue
|
||||||
try:
|
try:
|
||||||
measure_one(ean, args, data_repo)
|
measure_one(new_id, ean, lamps, args, data_repo, existing_id=existing_id)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
print("\n Aborted; lamp skipped. (PSU is switched off by the driver.)")
|
print("\n Aborted; lamp skipped. (PSU is switched off by the driver.)")
|
||||||
except (subprocess.CalledProcessError, SystemExit) as e:
|
except (subprocess.CalledProcessError, SystemExit) as e:
|
||||||
|
|||||||
Reference in New Issue
Block a user