From 6a2304baf8ee9b450bb5c5161f971c32f41d354a Mon Sep 17 00:00:00 2001 From: jessikitty Date: Sat, 21 Feb 2026 18:59:39 +1100 Subject: [PATCH] Update to use nfc_card_id (decimal) for API calls and mappings - Mapping file now uses decimal card IDs: "983187584": "video.mp4" - API calls include card_id as decimal integer - Displays NFC Card ID in logs for easy mapping creation - Version bump to 1.1.0 --- moonlight_integration.py | 78 +++++++++++++++++++++++++++++----------- 1 file changed, 58 insertions(+), 20 deletions(-) diff --git a/moonlight_integration.py b/moonlight_integration.py index 10c1b0f..bc69cce 100644 --- a/moonlight_integration.py +++ b/moonlight_integration.py @@ -1,12 +1,17 @@ #!/usr/bin/env python3 """ -LEGO Dimensions + Moonlight Drive-In Integration Example +LEGO Dimensions + Moonlight Drive-In Integration -This example shows how to integrate the LEGO Dimensions portal reader -with the Moonlight Drive-In video player system. +Integrates the LEGO Dimensions portal reader with the Moonlight Drive-In +video player system using NFC card IDs (decimal format). When a LEGO Dimensions disc is placed on the portal, it triggers video playback. When removed, playback stops. + +v1.1.0 Changes: +- Now uses nfc_card_id (decimal) for lookups and API calls +- Mapping file keys can be decimal strings: "983187584": "path/to/video.mp4" +- API sends card_id as decimal integer for compatibility """ import sys @@ -22,11 +27,16 @@ from lego_dimensions_reader import ( COLORS ) +__version__ = "1.1.0" + class MoonlightDimensionsClient: """ Integration client connecting LEGO Dimensions portal to Moonlight Drive-In video player. + + Uses NFC card ID (decimal) format for compatibility with + standard NFC readers and existing mapping systems. """ def __init__(self, api_url: str, mapping_file: Optional[str] = None): @@ -35,12 +45,13 @@ class MoonlightDimensionsClient: Args: api_url: Base URL for Moonlight Drive-In API (e.g., "http://drive-in:8547") - mapping_file: Optional JSON file mapping UIDs to video paths + mapping_file: Optional JSON file mapping card IDs to video paths """ self.api_url = api_url.rstrip('/') self.reader = LegoDimensionsReader() - # Load UID to video mapping + # Load card ID to video mapping + # Keys can be decimal strings like "983187584" self.video_mapping: Dict[str, str] = {} if mapping_file: self._load_mapping(mapping_file) @@ -54,13 +65,21 @@ class MoonlightDimensionsClient: # Track currently playing self._current_video: Optional[str] = None + self._current_card_id: Optional[int] = None def _load_mapping(self, filepath: str): - """Load UID to video mapping from JSON file.""" + """Load card ID to video mapping from JSON file.""" try: with open(filepath, 'r') as f: data = json.load(f) - self.video_mapping = data.get('mappings', data) + # Support both "mappings" wrapper and direct dict + raw_mappings = data.get('mappings', data) + + # Normalize keys to strings + for key, value in raw_mappings.items(): + # Accept both string and numeric keys + self.video_mapping[str(key)] = value + print(f"Loaded {len(self.video_mapping)} video mappings") except FileNotFoundError: print(f"Warning: Mapping file not found: {filepath}") @@ -90,19 +109,25 @@ class MoonlightDimensionsClient: print(f"\n{'='*50}") print(f"✓ TAG DETECTED on {tag.pad.name} pad") print(f" UID: {tag.uid_hex}") + print(f" NFC Card ID: {tag.nfc_card_id}") - # Check if we have a video mapped for this UID - video_path = self.video_mapping.get(tag.uid_hex) + # Look up video by decimal card ID + card_id_str = str(tag.nfc_card_id) + video_path = self.video_mapping.get(card_id_str) + + # Also try zero-padded format + if not video_path: + video_path = self.video_mapping.get(tag.nfc_card_id_str) if video_path: print(f" Video: {video_path}") - self._play_video(video_path) + self._play_video(video_path, tag.nfc_card_id) # Set pad to green to indicate playing self.reader.set_pad_color(tag.pad, COLORS['GREEN']) else: print(f" No video mapped for this tag") - print(f" Add mapping: \"{tag.uid_hex}\": \"path/to/video.mp4\"") + print(f" Add mapping: \"{tag.nfc_card_id}\": \"path/to/video.mp4\"") # Flash yellow to indicate unmapped tag self.reader.flash_pad(tag.pad, COLORS['YELLOW'], count=3) @@ -112,6 +137,7 @@ class MoonlightDimensionsClient: def _on_tag_remove(self, tag: TagInfo): """Handle tag removal - stop playback.""" print(f"\n✗ TAG REMOVED from {tag.pad.name} pad") + print(f" NFC Card ID: {tag.nfc_card_id}") # Stop video if one is playing if self._current_video: @@ -120,17 +146,21 @@ class MoonlightDimensionsClient: # Turn off pad LED self.reader.set_pad_color(tag.pad, COLORS['OFF']) - def _play_video(self, video_path: str): - """Send play command to Moonlight API.""" + def _play_video(self, video_path: str, card_id: int): + """Send play command to Moonlight API with card ID.""" try: response = requests.post( f"{self.api_url}/api/play", - json={"path": video_path}, + json={ + "path": video_path, + "card_id": card_id # Send decimal card ID + }, timeout=5 ) if response.ok: self._current_video = video_path + self._current_card_id = card_id print(f" ▶ Playing: {video_path}") else: print(f" ⚠ API Error: {response.status_code}") @@ -145,27 +175,33 @@ class MoonlightDimensionsClient: try: response = requests.post( f"{self.api_url}/api/stop", + json={ + "card_id": self._current_card_id + } if self._current_card_id else {}, timeout=5 ) if response.ok: print(f" ⏹ Stopped playback") self._current_video = None + self._current_card_id = None except requests.exceptions.RequestException: pass # Ignore stop errors - def add_mapping(self, uid: str, video_path: str): - """Add a UID to video mapping at runtime.""" - self.video_mapping[uid.upper()] = video_path + def add_mapping(self, card_id: int, video_path: str): + """Add a card ID to video mapping at runtime.""" + self.video_mapping[str(card_id)] = video_path def start(self): """Start the integration client.""" print("\n" + "="*50) print(" LEGO Dimensions + Moonlight Drive-In") + print(f" Integration v{__version__}") print("="*50) print(f"\nMoonlight API: {self.api_url}") print(f"Video mappings: {len(self.video_mapping)}") + print("Using NFC Card ID format (decimal)") print("\nStarting portal connection...") self.reader.start() @@ -184,9 +220,11 @@ def main(): # Example mapping file format (video_mappings.json): # { - # "04A1B2C3D4E5F6": "videos/batman_intro.mp4", - # "04D5E6F7A8B9C0": "videos/gandalf_intro.mp4" + # "983187584": "videos/batman_intro.mp4", + # "1234567890": "videos/gandalf_intro.mp4" # } + # + # Keys are decimal NFC card IDs (what standard NFC readers show) client = MoonlightDimensionsClient( api_url=MOONLIGHT_API, @@ -194,7 +232,7 @@ def main(): ) # You can also add mappings programmatically: - # client.add_mapping("04AABBCCDDEE00", "videos/custom.mp4") + # client.add_mapping(983187584, "videos/custom.mp4") try: client.start()