# HDMI-CEC Integration Flow Diagram ## System Architecture ``` ┌─────────────────────────────────────────────────────────────────┐ │ Infoscreen Client System │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ MQTT Client │◄───────►│Display Manager│ │ │ │ (simclient) │ │ │ │ │ └──────┬───────┘ └───────┬──────┘ │ │ │ │ │ │ │ Writes Events │ Reads Events │ │ ▼ ▼ │ │ ┌────────────────────────────────────┐ │ │ │ current_event.json │ │ │ └────────────────────────────────────┘ │ │ │ │ │ Display Manager Components │ │ │ ┌──────────────────────────────┴─────────────┐ │ │ │ │ │ │ ▼ ▼ │ │ ┌──────────────┐ ┌────────────────┐ │ │ │ Event Handler│ │HDMI CEC Control│ │ │ │ │───────────────────────────│ │ │ │ │ - Reads │ 1. Turn TV ON when │ - turn_on() │ │ │ │ - Validates │ event starts │ - turn_off() │ │ │ │ - Schedules │ 2. Cancel turn-off │ - cancel() │ │ │ │ │ when active │ │ │ │ └──────┬───────┘ 3. Schedule turn-off └────────┬───────┘ │ │ │ when ends │ │ │ │ │ │ │ ▼ ▼ │ │ ┌────────────────┐ ┌────────────────┐ │ │ │Display Processes│ │ cec-client │ │ │ │- Impressive │ │ (binary) │ │ │ │- Chromium │ └───────┬────────┘ │ │ │- VLC │ │ │ │ └────────────────┘ │ │ │ │ │ └──────────────────────────────────────────────────────┼──────────┘ │ ┌────────▼────────┐ │ HDMI-CEC Bus │ └────────┬────────┘ │ ┌────────▼────────┐ │ TV Display │ │ │ │ ON ◄─────► OFF │ └─────────────────┘ ``` ## Event Lifecycle with CEC ### 1. Event Starts ``` MQTT Event Arrives │ ├─► Write to current_event.json │ ▼ Display Manager Detects New Event │ ├─► Turn TV ON via CEC ──► echo "on 0" | cec-client -s -d 1 │ │ ├─► Cancel any pending │ │ turn-off timer ▼ │ TV Powers ON ▼ Start Display Process (Impressive/Chromium/VLC) ``` ### 2. Event Active (Continuous) ``` Main Loop (every 5s) │ ├─► Check if event still active │ ├─► Process still running? │ └─► Cancel turn-off timer ──► Keep TV ON (prevents premature shutdown) ``` ### 3. Event Ends ``` No Active Event Detected │ ├─► Stop Display Process │ ▼ Schedule TV Turn-Off (with delay) │ ├─► threading.Timer(30s) │ ▼ [DELAY] │ ├─► Can be cancelled if new event arrives │ ▼ Delay Expires │ ▼ Turn TV OFF ──► echo "standby 0" | cec-client -s -d 1 │ ▼ TV Powers OFF (Standby) ``` ### 4. Event Switching (No TV Off) ``` Event A Running │ ▼ Event B Arrives │ ├─► Stop Event A Display (turn_off_tv=False) │ ├─► TV stays ON │ ├─► Cancel any pending turn-off │ ▼ Start Event B Display │ └─► TV remains ON (seamless transition) ``` ## CEC Command Flow ### Turn On Sequence ``` Python Code Shell Command CEC Bus ───────────── ────────────── ───────── turn_on() called │ ├─► Check if already ON ──► Skip if tv_state == True │ ├─► Build command │ ▼ subprocess.run() ──────────► echo "on 0" | ────────► CEC: Power On (0x04) cec-client -s -d 1 Device 0 (TV) │ │ ▼ ▼ Parse output STDOUT: "power status changed..." │ ├─► Success indicators found? │ ├─► Update tv_state = True │ └─► Return True ``` ### Turn Off (Delayed) Sequence ``` Python Code Timer Thread Shell Command ───────────── ────────────── ────────────── turn_off(delayed=True) │ ├─► Create threading.Timer(30s, _turn_off_now) │ ├─► timer.daemon = True │ └─► timer.start() │ │ [30 seconds pass] │ ▼ _turn_off_now() ──────────► subprocess.run() │ │ │ ▼ │ echo "standby 0" | cec-client -s -d 1 │ │ ▼ ▼ Update tv_state = False TV enters standby ``` ### Cancel Turn-Off Sequence ``` Timer Active (counting down) │ ▼ cancel_turn_off() called │ ├─► timer.cancel() │ └─► Timer stopped, TV stays ON ``` ## State Diagram ``` ┌──────────────┐ │ System Init │ └──────┬───────┘ │ ▼ ┌──────────────┐ ┌───────────│ Detect TV │───────────┐ │ │ State │ │ │ └──────────────┘ │ │ │ ┌──────▼─────┐ ┌──────▼─────┐ │ TV is ON │ │ TV is OFF │ │ (or unknown)│ │ (standby) │ └──────┬─────┘ └──────┬─────┘ │ │ ┌──────────┴──────────────────────────────────────┘ │ │ Event Arrives ▼ ┌────────────┐ │ Turn TV ON │────► CEC Command: "on 0" └──────┬─────┘ │ ▼ ┌────────────┐ │ TV is ON │ │ Event Active│◄────┐ └──────┬─────┘ │ │ │ │ Event │ Event Still │ Ends │ Running │ │ ▼ │ ┌────────────┐ │ │Start Timer │ │ │ (30s) │───────┘ └──────┬─────┘ Cancel Timer │ │ Timer │ Expires ▼ ┌────────────┐ │Turn TV OFF │────► CEC Command: "standby 0" └──────┬─────┘ │ ▼ ┌────────────┐ │ TV is OFF │ │ (standby) │ └────────────┘ │ │ New Event └─────────► Turn TV ON (cycle repeats) ``` ## Configuration Impact ### CEC_TURN_OFF_DELAY Values ``` Delay = 0 seconds (Immediate) ──────────────────────────────── Event End ──► TV OFF (no delay) ⚠️ May cause flicker if events are close together Delay = 30 seconds (Default) ──────────────────────────────── Event End ──► [Wait 30s] ──► TV OFF ✓ Balanced approach ✓ Prevents flicker for events within 30s ✓ Still saves power Delay = 120 seconds (Conservative) ──────────────────────────────── Event End ──► [Wait 2m] ──► TV OFF ✓ Very smooth for frequent events ⚠️ May waste power if events are sparse ``` ## Integration Points in Code ### 1. Initialization (DisplayManager.__init__) ```python self.cec = HDMICECController( enabled=CEC_ENABLED, device=CEC_DEVICE, turn_off_delay=CEC_TURN_OFF_DELAY ) ``` ### 2. Signal Handler (Graceful Shutdown) ```python def _signal_handler(self, signum, frame): self.stop_current_display() self.cec.turn_off(delayed=True) # TV off on shutdown sys.exit(0) ``` ### 3. Event Processing (Main Loop) ```python # Turn on TV before starting display self.cec.turn_on() # During event self.cec.cancel_turn_off() # Keep TV on # When stopping self.stop_current_display(turn_off_tv=True) ``` ### 4. Stop Display ```python def stop_current_display(self, turn_off_tv: bool = True): # ... terminate process ... if turn_off_tv: self.cec.turn_off(delayed=True) ``` ## Logging Flow ``` Display Manager Startup │ ├──► [INFO] HDMI-CEC controller initialized (device: TV, turn_off_delay: 30s) │ ├──► [INFO] TV detected as ON │ └──► [INFO] Display Manager starting... Event Arrives │ ├──► [INFO] Starting display for event: presentation_slides.pdf │ ├──► [INFO] Turning TV ON via HDMI-CEC... │ ├──► [DEBUG] CEC command 'on 0' executed successfully │ ├──► [INFO] TV turned ON successfully │ └──► [INFO] Display started successfully Event Ends │ ├──► [INFO] No active events - stopping current display │ ├──► [INFO] Scheduling TV turn-off in 30s... │ └──► [INFO] Stopping current display 30 Seconds Later │ ├──► [INFO] Turning TV OFF via HDMI-CEC... │ ├──► [DEBUG] CEC command 'standby 0' executed successfully │ └──► [INFO] TV turned OFF successfully New Event Before Timeout │ ├──► [DEBUG] Cancelled TV turn-off timer │ └──► [INFO] Turning TV ON via HDMI-CEC... ``` ## Error Scenarios ### 1. cec-client Not Installed ``` HDMICECController.__init__() │ ├──► _check_cec_available() │ ├──► [WARNING] cec-client not found - HDMI-CEC control disabled │ ├──► [INFO] Install with: sudo apt-get install cec-utils │ └──► self.enabled = False (System continues without TV control) ``` ### 2. TV Not Responding ``` turn_on() called │ ├──► subprocess.run(...) │ ├──► Exit code != 0 │ ├──► [WARNING] CEC command 'on 0' may have failed │ └──► Return False (Logged but not critical) ``` ### 3. CEC Command Timeout ``` _run_cec_command("on 0") │ ├──► subprocess.run(..., timeout=5) │ ├──► TimeoutExpired after 5s │ ├──► [ERROR] CEC command 'on 0' timed out after 5s │ └──► Return False ``` ## Summary The HDMI-CEC integration provides: - ✅ Automatic TV control based on events - ✅ Configurable behavior via environment variables - ✅ Smart delay mechanism to prevent flicker - ✅ Graceful fallback if CEC unavailable - ✅ Comprehensive logging for troubleshooting - ✅ Minimal performance impact - ✅ Production-ready reliability