Add nfc_card_id field (bytes 3-6 as decimal) for standard NFC reader compatibility

- TagInfo now includes nfc_card_id: the 10-digit decimal ID standard NFC readers display
- Calculated from bytes 3-6 of the 7-byte UID as big-endian uint32
- Example: UID 042B603A9A4080 -> nfc_card_id 983187584
- Updated standalone test to display nfc_card_id
- Version bump to 1.4.0
This commit is contained in:
2026-02-21 18:59:01 +11:00
parent 0da6f54889
commit 203ea48c21

View File

@@ -6,6 +6,11 @@ For Moonlight Drive-In Video Player System
Communicates with LEGO Dimensions USB portal (PS3/PS4/Wii U versions) Communicates with LEGO Dimensions USB portal (PS3/PS4/Wii U versions)
to detect character and vehicle disc placement/removal events. to detect character and vehicle disc placement/removal events.
v1.4.0 Changes:
- Added nfc_card_id field: decimal ID matching standard NFC readers
- Calculated from bytes 3-6 of UID as big-endian uint32
- Example: UID 042B603A9A4080 -> nfc_card_id 983187584
v1.3.0 Changes: v1.3.0 Changes:
- Removed default LED blink on tag insert (callbacks now control LEDs) - Removed default LED blink on tag insert (callbacks now control LEDs)
- Added software_flash() method for reliable flashing via solid color loop - Added software_flash() method for reliable flashing via solid color loop
@@ -81,7 +86,7 @@ VENDOR_ID = 0x0e6f
PRODUCT_ID = 0x0241 PRODUCT_ID = 0x0241
# Module version # Module version
__version__ = "1.3.0" __version__ = "1.4.0"
def get_usb_backend(): def get_usb_backend():
@@ -148,16 +153,28 @@ class TagInfo:
pad: Pad pad: Pad
event: TagEvent event: TagEvent
uid_hex: str = "" uid_hex: str = ""
legacy_key: int = 0 # Integer key for tag_colors.json lookup nfc_card_id: int = 0 # Standard NFC card ID (bytes 3-6 as decimal)
legacy_key: int = 0 # Legacy key (first 4 bytes, big-endian)
character_id: Optional[int] = None character_id: Optional[int] = None
character_name: Optional[str] = None character_name: Optional[str] = None
is_vehicle: bool = False is_vehicle: bool = False
def __post_init__(self): def __post_init__(self):
self.uid_hex = self.uid.hex().upper() self.uid_hex = self.uid.hex().upper()
# Calculate legacy key (32-bit int from first 4 bytes, big-endian) # Calculate legacy key (32-bit int from first 4 bytes, big-endian)
if len(self.uid) >= 4: if len(self.uid) >= 4:
self.legacy_key = int.from_bytes(self.uid[:4], 'big') self.legacy_key = int.from_bytes(self.uid[:4], 'big')
# Calculate NFC card ID (bytes 3-6 as big-endian uint32)
# This matches what standard NFC readers display (e.g., 983187584)
if len(self.uid) >= 7:
self.nfc_card_id = int.from_bytes(self.uid[3:7], 'big')
@property
def nfc_card_id_str(self) -> str:
"""Return NFC card ID as zero-padded 10-digit string."""
return f"{self.nfc_card_id:010d}"
class LegoDimensionsReader: class LegoDimensionsReader:
@@ -167,13 +184,14 @@ class LegoDimensionsReader:
Provides event-driven tag detection with callbacks for integration Provides event-driven tag detection with callbacks for integration
with the Moonlight Drive-In video player system. with the Moonlight Drive-In video player system.
v1.4.0: TagInfo now includes nfc_card_id matching standard NFC readers.
v1.3.0: No default LED behavior on tag insert/remove. v1.3.0: No default LED behavior on tag insert/remove.
Callbacks are fully responsible for LED control. Callbacks are fully responsible for LED control.
Usage: Usage:
reader = LegoDimensionsReader() reader = LegoDimensionsReader()
reader.on_tag_insert = lambda tag: print(f"Tag placed: {tag.uid_hex}") reader.on_tag_insert = lambda tag: print(f"Tag placed: {tag.nfc_card_id}")
reader.on_tag_remove = lambda tag: print(f"Tag removed: {tag.uid_hex}") reader.on_tag_remove = lambda tag: print(f"Tag removed: {tag.nfc_card_id}")
reader.start() reader.start()
""" """
@@ -629,7 +647,7 @@ class LegoDimensionsReader:
event = TagEvent.INSERTED if action == 0 else TagEvent.REMOVED event = TagEvent.INSERTED if action == 0 else TagEvent.REMOVED
tag_info = TagInfo(uid=uid, pad=pad, event=event) tag_info = TagInfo(uid=uid, pad=pad, event=event)
# v1.3.0: NO default LED behavior - callbacks control LEDs # v1.3.0+: NO default LED behavior - callbacks control LEDs
if event == TagEvent.INSERTED: if event == TagEvent.INSERTED:
self._active_tags[pad_num] = tag_info self._active_tags[pad_num] = tag_info
if self.on_tag_insert: if self.on_tag_insert:
@@ -797,7 +815,7 @@ if __name__ == "__main__":
print(f"\n{'='*50}") print(f"\n{'='*50}")
print(f"[+] TAG PLACED on {tag.pad.name} pad") print(f"[+] TAG PLACED on {tag.pad.name} pad")
print(f" UID: {tag.uid_hex}") print(f" UID: {tag.uid_hex}")
print(f" Legacy Key: {tag.legacy_key}") print(f" NFC Card ID: {tag.nfc_card_id} ({tag.nfc_card_id_str})")
print(f" Password: {generate_password(tag.uid).hex().upper()}") print(f" Password: {generate_password(tag.uid).hex().upper()}")
print(f"{'='*50}") print(f"{'='*50}")
@@ -816,8 +834,8 @@ if __name__ == "__main__":
print(f"\nLEGO Dimensions Portal Reader v{__version__}") print(f"\nLEGO Dimensions Portal Reader v{__version__}")
print(f"Platform: {platform.system()}") print(f"Platform: {platform.system()}")
print("="*50) print("="*50)
print("NOTE: v1.3.0 - No default LED blink on tag insert") print("v1.4.0: Now shows NFC Card ID (decimal) for compatibility")
print(" Callbacks control all LED behavior") print(" with standard NFC readers and mapping files")
print("="*50) print("="*50)
reader = LegoDimensionsReader() reader = LegoDimensionsReader()
@@ -841,4 +859,4 @@ if __name__ == "__main__":
print(f"\nConnection failed: {e}") print(f"\nConnection failed: {e}")
finally: finally:
reader.disconnect() reader.disconnect()
print("Goodbye!") print("Goodbye!")