# ESP32 Bluetooth Relay Integration Guide Complete guide for integrating ESP32 8-channel Bluetooth relay controller with the Moonlight Drive-In Theatre system. ## ๐ŸŽฏ Overview This integration allows the theatre software to automatically control: - **House lights** - Main theatre lighting - **Screen lights** - Illumination around the screen - **Marquee lights** - External entrance/sign lighting - **Speaker power** - Audio system power - **Projector power** - Video projector control - **Effect lights** - Special effect lighting - **Concession lights** - Snack bar area - **Parking lights** - Parking area illumination ## ๐Ÿ“ฆ Prerequisites ### Hardware Required 1. **ESP32 Development Board** (with Bluetooth) 2. **8-Channel Relay Module** (5V) 3. **Wiring components** (jumper wires, power supply) 4. **Computer with Bluetooth** (for Python script communication) ### Software Required ```bash pip install pyserial ``` The ESP32 firmware is in the separate `esp32-bluetooth-relay` repository. ## ๐Ÿ”ง Hardware Setup ### Step 1: Build ESP32 Relay Controller Follow the complete guide in the `esp32-bluetooth-relay` repository: - Wire ESP32 to relay module - Upload firmware to ESP32 - Test basic relay operation ### Step 2: Connect Loads to Relays Map your theatre equipment to relays (default configuration): | Relay | Function | Theatre Equipment | |-------|----------|-------------------| | 1 | House Lights | Main overhead lights | | 2 | Screen Lights | Screen border lighting | | 3 | Marquee Lights | Entrance sign | | 4 | Speaker Power | Audio amplifier | | 5 | Projector Power | Video projector | | 6 | Effect Lights | RGB/effect lighting | | 7 | Concession Lights | Snack bar | | 8 | Parking Lights | Outdoor parking | **โš ๏ธ SAFETY:** Only qualified electricians should wire AC-powered equipment. Start with low-voltage DC loads for testing. ### Step 3: Pair ESP32 with Computer **Windows:** 1. Open Bluetooth settings 2. Search for "ESP32-Relay-8CH" 3. Pair the device 4. Note the COM port assigned (e.g., COM4) **Linux:** ```bash # Scan for ESP32 hcitool scan # Pair with ESP32 (replace XX:XX... with actual MAC) bluetoothctl > pair XX:XX:XX:XX:XX:XX > trust XX:XX:XX:XX:XX:XX > connect XX:XX:XX:XX:XX:XX # Bind to serial port sudo rfcomm bind /dev/rfcomm0 XX:XX:XX:XX:XX:XX ``` ## ๐Ÿš€ Software Integration ### Step 1: Install Python Dependencies ```bash cd moonlight-drive-in pip install pyserial ``` ### Step 2: Configure Theatre Automation Edit `config.py` and add the relay configuration section: ```python # ESP32 Relay Controller Configuration RELAY_CONFIG = { # Enable/disable features 'enabled': True, 'auto_theatre_lights': True, # Auto dim lights during movies 'auto_speaker_power': True, # Auto power speakers 'light_dim_delay': 5, # Seconds before dimming # Serial port (None = auto-detect, or specify like 'COM4' or '/dev/rfcomm0') 'relay_port': None, # Custom relay mapping (optional - override defaults) 'relay_mapping': { 'HOUSE_LIGHTS': 1, 'SCREEN_LIGHTS': 2, 'MARQUEE_LIGHTS': 3, 'SPEAKER_POWER': 4, 'PROJECTOR_POWER': 5, 'EFFECT_LIGHTS': 6, 'CONCESSION_LIGHTS': 7, 'PARKING_LIGHTS': 8, } } ``` ### Step 3: Modify MPV Player Integration Edit `mpv_seamless_player.py` to add automation hooks: ```python # At top of file, add imports from theatre_automation import TheatreAutomation, RelayFunction import config # In __init__ method, add: self.theatre = None if config.RELAY_CONFIG.get('enabled', False): try: self.theatre = TheatreAutomation(config.RELAY_CONFIG) if self.theatre.connect(): logger.info("Theatre automation enabled") else: logger.warning("Failed to connect to theatre automation") self.theatre = None except Exception as e: logger.error(f"Theatre automation error: {e}") self.theatre = None # Before playing trailer, add: if self.theatre: self.theatre.movie_starting(is_trailer=True) # After trailer ends, add: if self.theatre: self.theatre.movie_ended(is_trailer=True) # Before playing main movie, add: if self.theatre: self.theatre.movie_starting(is_trailer=False) # After movie ends, add: if self.theatre: self.theatre.movie_ended(is_trailer=False) # On shutdown/cleanup, add: if self.theatre: self.theatre.disconnect() ``` ### Step 4: Add Web Interface Controls Edit `web_interface.py` to add relay control routes: ```python from theatre_automation import TheatreAutomation, RelayFunction # Add global theatre variable theatre_automation = None # Initialize in app startup if config.RELAY_CONFIG.get('enabled'): theatre_automation = TheatreAutomation(config.RELAY_CONFIG) theatre_automation.connect() # Add API endpoints @app.route('/api/relay/status') def relay_status(): """Get status of all relays""" if theatre_automation and theatre_automation.connected: return jsonify(theatre_automation.get_status()) return jsonify({'error': 'Theatre automation not connected'}), 503 @app.route('/api/relay//') def relay_control(function_name, state): """Control a specific relay""" if not theatre_automation or not theatre_automation.connected: return jsonify({'error': 'Not connected'}), 503 try: function = RelayFunction[function_name.upper()] state_bool = state.lower() == 'on' if theatre_automation.set_relay(function, state_bool): return jsonify({'success': True}) else: return jsonify({'error': 'Command failed'}), 500 except KeyError: return jsonify({'error': 'Invalid function'}), 400 @app.route('/api/relay/effect/') def relay_effect(effect_name): """Run a lighting effect""" if theatre_automation and theatre_automation.connected: theatre_automation.effect_sequence(effect_name) return jsonify({'success': True}) return jsonify({'error': 'Not connected'}), 503 ``` ## ๐Ÿงช Testing ### Test 1: Basic Connection ```bash python esp32_relay_controller.py ``` This will: - List available serial ports - Connect to ESP32 - Run interactive test mode ### Test 2: Theatre Automation ```bash python theatre_automation.py ``` This will: - Initialize theatre automation - Run a demo sequence (trailer โ†’ movie โ†’ closing) - Test all automation functions ### Test 3: Integration Test 1. Start the theatre software normally 2. Watch for log messages: "Theatre automation enabled" 3. Scan an NFC tag to start a movie 4. Observe lights dimming after delay 5. Movie ends and lights come back up ## ๐ŸŽฎ Manual Control ### Command Line Control ```python from theatre_automation import TheatreAutomation, RelayFunction theatre = TheatreAutomation() theatre.connect() # Manual relay control theatre.set_relay(RelayFunction.HOUSE_LIGHTS, False) # Lights off theatre.set_relay(RelayFunction.SPEAKER_POWER, True) # Speakers on # Run effects theatre.effect_sequence("flash") theatre.effect_sequence("pulse") # Get status status = theatre.get_status() print(status) theatre.disconnect() ``` ### Web Dashboard Control Add to `dashboard.html`: ```html

Theatre Automation

House Lights
Speaker Power
``` ## ๐Ÿ“‹ Automation Sequences ### Movie Starting 1. Wait for light_dim_delay (default 5 seconds) 2. Turn off house lights 3. Turn off screen lights (main movie only) 4. Turn on speaker power ### Movie Ending 1. Turn on house lights 2. Turn on screen lights 3. Turn off speaker power (if no other content playing) ### Intermission 1. Turn on house lights 2. Turn on concession lights 3. Keep speakers powered ### Closing 1. Turn off speakers 2. Turn off screen lights 3. Turn off effect lights 4. Keep parking and marquee lights on ### Emergency 1. Turn ALL lights ON immediately ## โš™๏ธ Customization ### Change Relay Assignments Edit `config.py`: ```python 'relay_mapping': { 'HOUSE_LIGHTS': 2, # Changed from 1 to 2 'SCREEN_LIGHTS': 1, # Swapped with house lights # ... etc } ``` ### Adjust Timing ```python 'light_dim_delay': 10, # Wait 10 seconds before dimming ``` ### Disable Auto-Features ```python 'auto_theatre_lights': False, # Manual light control only 'auto_speaker_power': False, # Manual speaker control ``` ### Add Custom Functions Edit `theatre_automation.py`: ```python class RelayFunction(Enum): # Add new function FOG_MACHINE = 5 # Use relay 5 for fog machine # Add method to control it def activate_fog(self, duration=5): self.set_relay(RelayFunction.FOG_MACHINE, True) time.sleep(duration) self.set_relay(RelayFunction.FOG_MACHINE, False) ``` ## ๐Ÿ› Troubleshooting ### ESP32 Not Found **Problem:** "No serial ports found" **Solutions:** 1. Ensure ESP32 is powered on 2. Verify Bluetooth pairing 3. Check Bluetooth COM port in Device Manager (Windows) 4. Run `hcitool scan` to verify device (Linux) ### Connection Fails **Problem:** "Failed to connect to relay controller" **Solutions:** 1. Check COM port in config matches actual port 2. Verify no other program is using the port 3. Try manual port specification: `relay_port: 'COM4'` 4. Test with standalone script: `python esp32_relay_controller.py` ### Relays Don't Respond **Problem:** Commands sent but relays don't switch **Solutions:** 1. Test ESP32 with Serial Bluetooth Terminal app 2. Check ESP32 is running and Bluetooth is active 3. Verify relay module has power 4. Check wiring between ESP32 and relay module ### Lights Don't Dim **Problem:** Automation enabled but lights stay on **Solutions:** 1. Check `auto_theatre_lights: True` in config 2. Verify relay wiring to light switch/relay 3. Check relay polarity (active HIGH vs LOW) 4. Test manual control: `theatre.set_relay(RelayFunction.HOUSE_LIGHTS, False)` ## ๐Ÿ“š API Reference ### ESP32RelayController ```python controller = ESP32RelayController() # Connection controller.connect(port='COM4') controller.disconnect() # Basic Control controller.turn_on(1) # Turn on relay 1 controller.turn_off(1) # Turn off relay 1 controller.toggle(1) # Toggle relay 1 controller.all_on() # All relays on controller.all_off() # All relays off # Status controller.get_status() # Request status update controller.get_relay_state(1) # Get cached state of relay 1 controller.get_all_states() # Get all cached states # Callbacks controller.register_callback('connect', on_connect_func) controller.register_callback('disconnect', on_disconnect_func) controller.register_callback('status_update', on_status_func) ``` ### TheatreAutomation ```python theatre = TheatreAutomation(config) # Connection theatre.connect(port='COM4') theatre.disconnect() # Automation Sequences theatre.movie_starting(is_trailer=True) theatre.movie_ended(is_trailer=False) theatre.intermission() theatre.closing_sequence() theatre.emergency_lights_on() # Manual Control theatre.set_relay(RelayFunction.HOUSE_LIGHTS, True) theatre.toggle_relay(RelayFunction.EFFECT_LIGHTS) theatre.effect_sequence("flash") # Status status = theatre.get_status() ``` ## ๐ŸŽฌ Example Workflows ### Unattended Mode Integration ```python # In unattend mode cycle handler def cycle_content(): if theatre: # Starting trailer theatre.movie_starting(is_trailer=True) play_trailer() if theatre: theatre.movie_ended(is_trailer=True) time.sleep(2) # Brief pause theatre.movie_starting(is_trailer=False) play_movie() if theatre: theatre.movie_ended(is_trailer=False) ``` ### NFC Tag Triggered Effects ```python # Map NFC tags to lighting effects NFC_EFFECTS = { 'AAAAAAAA': 'flash', 'BBBBBBBB': 'pulse', 'CCCCCCCC': 'marquee', } def handle_nfc(tag_id): if tag_id in NFC_EFFECTS and theatre: theatre.effect_sequence(NFC_EFFECTS[tag_id]) ``` ## ๐Ÿ” Safety Notes 1. **AC Power:** Only qualified electricians should work with mains voltage 2. **Fusing:** Use appropriate fuses for all loads 3. **Ratings:** Don't exceed relay current/voltage ratings 4. **Failsafe:** Ensure system fails to a safe state (lights ON) 5. **Testing:** Test thoroughly with low-voltage loads first ## ๐Ÿ“– Additional Resources - **ESP32 Relay Repository:** `esp32-bluetooth-relay` - **ESP32 Documentation:** Full wiring and setup guide - **Python Serial:** https://pyserial.readthedocs.io/ - **Bluetooth Serial:** https://learn.adafruit.com/android-bluetooth-serial --- **Version:** 1.0 **Last Updated:** December 2025 **Integration Status:** Ready for testing