Update README with comprehensive documentation

This commit is contained in:
2026-01-24 10:34:58 +11:00
parent a4650b33af
commit dc4c30dcd0

247
README.md
View File

@@ -1,3 +1,246 @@
# lego-dimensions-reader # LEGO Dimensions NFC Portal Reader
LEGO Dimensions NFC Portal reader module for Python on Windows - integrates with Moonlight Drive-In video player system Python module for reading LEGO Dimensions character and vehicle discs using the USB portal (PS3/PS4/Wii U versions) on Windows.
Designed to integrate with the [Moonlight Drive-In](https://gitea.hideawaygaming.com.au/jessikitty/moonlight-drive-in) video player system.
## Features
- **Event-driven tag detection** - Callbacks for tag insert/remove events
- **LED control** - Set colors, flash, and fade effects on portal pads
- **Thread-safe** - Background polling thread with proper locking
- **Character database** - Built-in lookup for 80+ characters and vehicles
- **TEA encryption** - Full encryption/decryption support for character IDs
## Hardware Requirements
| Portal Version | Compatible |
|----------------|------------|
| PS3 | ✅ Yes |
| PS4 | ✅ Yes |
| Wii U | ✅ Yes |
| Xbox 360 | ❌ No |
| Xbox One | ❌ No |
**USB Identifiers:**
- Vendor ID: `0x0e6f`
- Product ID: `0x0241`
## Installation
### 1. Install Python Package
```bash
pip install pyusb
```
### 2. Install Windows USB Driver (Required)
The portal's default Windows HID driver must be replaced with WinUSB:
1. Download **Zadig** from https://zadig.akeo.ie/
2. Connect the LEGO Dimensions portal via USB
3. Run Zadig **as Administrator**
4. Select **Options → List All Devices**
5. Choose **"LEGO READER V2.10"** from the dropdown
6. Select **WinUSB** as the target driver
7. Click **"Replace Driver"**
8. Unplug and reconnect the portal
## Quick Start
```python
from lego_dimensions_reader import LegoDimensionsReader, COLORS
def on_tag_placed(tag):
print(f"Tag detected: {tag.uid_hex} on {tag.pad.name}")
def on_tag_removed(tag):
print(f"Tag removed from {tag.pad.name}")
reader = LegoDimensionsReader()
reader.on_tag_insert = on_tag_placed
reader.on_tag_remove = on_tag_removed
reader.start()
# Keep running...
import time
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
reader.disconnect()
```
## API Reference
### LegoDimensionsReader
Main class for portal communication.
#### Callbacks
| Callback | Signature | Description |
|----------|-----------|-------------|
| `on_tag_insert` | `(TagInfo) -> None` | Called when tag is placed |
| `on_tag_remove` | `(TagInfo) -> None` | Called when tag is removed |
| `on_connect` | `() -> None` | Called on successful connection |
| `on_disconnect` | `() -> None` | Called on disconnection |
| `on_error` | `(Exception) -> None` | Called on errors |
#### Methods
```python
reader.connect() # Connect to portal (called automatically by start())
reader.disconnect() # Disconnect and cleanup
reader.start() # Start event polling thread
reader.stop() # Stop polling thread
# LED Control
reader.set_pad_color(Pad.CENTER, COLORS['RED'])
reader.flash_pad(Pad.LEFT, COLORS['GREEN'], on_time=10, off_time=10, count=5)
reader.fade_pad(Pad.RIGHT, COLORS['BLUE'], speed=10, count=1)
# State
reader.get_active_tags() # Dict of tags currently on pads
reader.is_connected # Boolean
reader.is_running # Boolean
```
### TagInfo
Data class returned in callbacks.
| Property | Type | Description |
|----------|------|-------------|
| `uid` | `bytes` | 7-byte tag UID |
| `uid_hex` | `str` | UID as hex string |
| `pad` | `Pad` | Which pad (CENTER, LEFT, RIGHT) |
| `event` | `TagEvent` | INSERTED or REMOVED |
### Pad Enum
```python
from lego_dimensions_reader import Pad
Pad.ALL # All pads
Pad.CENTER # Center pad
Pad.LEFT # Left pad
Pad.RIGHT # Right pad
```
### Colors
```python
from lego_dimensions_reader import COLORS
COLORS['OFF'] # [0, 0, 0]
COLORS['RED'] # [255, 0, 0]
COLORS['GREEN'] # [0, 255, 0]
COLORS['BLUE'] # [0, 0, 255]
COLORS['WHITE'] # [255, 255, 255]
COLORS['YELLOW'] # [255, 255, 0]
COLORS['CYAN'] # [0, 255, 255]
COLORS['MAGENTA'] # [255, 0, 255]
COLORS['ORANGE'] # [255, 128, 0]
COLORS['PURPLE'] # [128, 0, 255]
```
## Integration with Moonlight Drive-In
Example integration for triggering video playback:
```python
import requests
from lego_dimensions_reader import LegoDimensionsReader
# Map tag UIDs to video files
VIDEO_MAPPING = {
"04A1B2C3D4E5F6": "videos/batman_intro.mp4",
"04D5E6F7A8B9C0": "videos/gandalf_intro.mp4",
}
MOONLIGHT_API = "http://drive-in:8547"
def on_tag_insert(tag):
video = VIDEO_MAPPING.get(tag.uid_hex)
if video:
requests.post(f"{MOONLIGHT_API}/api/play", json={"path": video})
def on_tag_remove(tag):
requests.post(f"{MOONLIGHT_API}/api/stop")
reader = LegoDimensionsReader()
reader.on_tag_insert = on_tag_insert
reader.on_tag_remove = on_tag_remove
reader.start()
```
## TEA Encryption Functions
For advanced tag reading/writing:
```python
from lego_dimensions_reader import (
generate_password,
generate_tea_key,
decrypt_character_id,
encrypt_character_id
)
uid = bytes.fromhex("04A1B2C3D4E5F6")
# Generate tag password
password = generate_password(uid)
# Decrypt character ID from tag data
encrypted_data = bytes.fromhex("...") # 8 bytes from pages 0x24-0x25
character_id = decrypt_character_id(uid, encrypted_data)
# Encrypt character ID for writing
encrypted = encrypt_character_id(uid, character_id=1) # Batman
```
## Troubleshooting
### "LEGO Dimensions Portal not found"
- Ensure portal is connected via USB
- Check you're using PS3/PS4/Wii U portal (NOT Xbox)
- Verify Zadig driver installation
### "Access denied" error
- Run your script as Administrator
- Re-run Zadig driver installation
### Portal detected but no tag events
- Try unplugging and reconnecting portal
- Check USB cable connection
- Ensure tag is placed flat on the pad
## Technical Details
### NFC Tags
- Tag type: NTAG213 (Mifare Ultralight C)
- Memory: 144 bytes (45 pages × 4 bytes)
- Character data: Pages 0x24-0x25 (TEA encrypted)
- Vehicle data: Page 0x24 (unencrypted)
- Password protection: Pages 0x24+
### USB Protocol
- Packet size: 32 bytes (fixed)
- Endpoint OUT: 0x01
- Endpoint IN: 0x81
- Tag events start with byte 0x56
## Credits
Based on reverse-engineering work by:
- ags131 (node-ld)
- bettse
- socram8888
- Ellerbach (LegoDimensions .NET library)
## License
MIT License