or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/pypi-cec

Python bindings for libcec to control CEC-compliant HDMI devices from Python scripts

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
pypipkg:pypi/cec@0.2.x

To install, run

npx @tessl/cli install tessl/pypi-cec@0.2.0

index.mddocs/

CEC (Consumer Electronics Control)

Python bindings for libcec, enabling control of CEC-compliant HDMI devices (TVs, receivers, etc.) from Python scripts. The library provides a comprehensive API for device discovery, power management, volume control, input switching, and event-driven programming through callbacks.

Package Information

  • Package Name: cec
  • Language: Python (C++ extension)
  • Installation: pip install cec
  • Hardware Requirements: CEC-capable hardware (Pulse-Eight USB-CEC adapter, Raspberry Pi, etc.)

Core Imports

import cec

Basic Usage

import cec

# Initialize CEC library with default adapter
cec.init()

# Create a device object for the TV
tv = cec.Device(cec.CECDEVICE_TV)

# Control the TV
tv.power_on()
print("TV is on:", tv.is_on())

# Volume control
cec.volume_up()
cec.volume_down()
cec.toggle_mute()

# Clean shutdown (when supported)
# cec.close()  # Not implemented in current version

Capabilities

Adapter Management

Initialize and manage CEC adapters for communication with the CEC bus.

def list_adapters():
    """
    List available CEC adapters on the system.
    
    Returns:
        list: Available adapter names/paths
    """

def init():
    """
    Initialize CEC library with the default adapter.
    
    Returns:
        bool: True if initialization successful
        
    Raises:
        RuntimeError: If initialization fails
    """

def init(adapter):
    """
    Initialize CEC library with a specific adapter.
    
    Args:
        adapter (str): Adapter name/path from list_adapters()
        
    Returns:
        bool: True if initialization successful
        
    Raises:
        RuntimeError: If initialization fails
    """

Device Discovery

Discover and enumerate CEC devices on the bus.

def list_devices():
    """
    List all discovered CEC devices on the bus.
    
    Returns:
        dict: Dictionary mapping device logical addresses (int) to Device objects
    """

Event System

Register and manage event callbacks for CEC events like key presses, commands, and state changes.

def add_callback(handler, events):
    """
    Add an event callback handler.
    
    Args:
        handler (callable): Function to handle events, signature varies by event type
        events (int): Bitmask of event types to listen for
        
    Returns:
        bool: True if callback was registered successfully
    """

def remove_callback(handler, events):
    """
    Remove an event callback handler.
    
    Args:
        handler (callable): Previously registered callback function
        events (int): Bitmask of event types to stop listening for
        
    Returns:
        bool: True if callback was removed successfully
    """

Raw Communication

Send raw CEC commands directly to devices on the bus.

def transmit(destination, opcode, parameters=None, initiator=None):
    """
    Transmit a raw CEC command to a specific device.
    
    Args:
        destination (int): Target device logical address (0-15)
        opcode (int): CEC opcode for the command
        parameters (bytes, optional): Command parameters as byte string
        initiator (int, optional): Source logical address (0-15). If not specified, uses primary adapter address
        
    Returns:
        bool: True if transmission successful
    """

Active Source Management

Manage which device is the active source on the CEC bus.

def is_active_source(addr):
    """
    Check if device at the given address is the active source.
    
    Args:
        addr (int): Device logical address
        
    Returns:
        bool: True if device is active source
    """

def set_active_source():
    """
    Set the default device as the active source.
    
    Returns:
        bool: True if successful
    """

def set_active_source(device_type):
    """
    Set a specific device type as the active source.
    
    Args:
        device_type (int): CEC device type constant
        
    Returns:
        bool: True if successful
    """

Volume Control

Control audio volume and mute state through CEC.

def volume_up():
    """
    Increase the volume via CEC.
    
    Returns:
        bool: True if command sent successfully
    """

def volume_down():
    """
    Decrease the volume via CEC.
    
    Returns:
        bool: True if command sent successfully
    """

def toggle_mute():
    """
    Toggle mute state via CEC.
    Available in libcec 2.0+ only.
    
    Returns:
        bool: True if command sent successfully
    """

Physical Address Management

Configure HDMI physical addresses and stream paths.

def set_stream_path(path):
    """
    Set the HDMI stream path.
    
    Args:
        path (int): Physical address as integer
        
    Returns:
        bool: True if successful
    """

def set_physical_addr(addr):
    """
    Set the HDMI physical address.
    
    Args:
        addr (int): Physical address as integer
        
    Returns:
        bool: True if successful
    """

Configuration Persistence

Manage CEC configuration persistence to adapter hardware.

def can_persist_config():
    """
    Check if the current adapter supports configuration persistence.
    
    Returns:
        bool: True if adapter can persist configuration
    """

def persist_config():
    """
    Persist the current CEC configuration to the adapter.
    
    Returns:
        bool: True if configuration was persisted successfully
    """

def set_port(device, port):
    """
    Set upstream HDMI port for a device.
    
    Args:
        device (int): Device logical address
        port (int): HDMI port number
        
    Returns:
        bool: True if successful
    """

Device Objects

The Device class represents individual CEC devices and provides methods for device-specific control.

class Device:
    """
    Represents a CEC device on the bus.
    """
    
    def __init__(self, id):
        """
        Create a Device object for the given logical address.
        
        Args:
            id (int): Logical address of the device (0-15)
        """
    
    # Read-only properties
    @property
    def address(self):
        """
        Logical address of the device.
        
        Returns:
            int: Device logical address (0-15)
        """
    
    @property
    def physical_address(self):
        """
        Physical address of the device in HDMI topology.
        
        Returns:
            int: Physical address as integer
        """
    
    @property
    def vendor(self):
        """
        Vendor ID of the device.
        
        Returns:
            int: Vendor identification number
        """
    
    @property
    def osd_string(self):
        """
        On-Screen Display name of the device.
        
        Returns:
            str: Device OSD name
        """
    
    @property
    def cec_version(self):
        """
        CEC version supported by the device.
        
        Returns:
            int: CEC version number
        """
    
    @property
    def language(self):
        """
        Menu language of the device.
        
        Returns:
            str: ISO language code
        """
    
    # Methods
    def is_on(self):
        """
        Get the power status of the device.
        
        Returns:
            bool: True if device is powered on
        """
    
    def power_on(self):
        """
        Power on the device.
        
        Returns:
            bool: True if command sent successfully
        """
    
    def standby(self):
        """
        Put the device into standby mode.
        
        Returns:
            bool: True if command sent successfully
        """
    
    def is_active(self):
        """
        Check if this device is the active source.
        
        Returns:
            bool: True if device is active source
        """
    
    def set_av_input(self, input):
        """
        Select AV input on the device.
        
        Args:
            input (int): Input number/identifier
            
        Returns:
            bool: True if command sent successfully
        """
    
    def set_audio_input(self, input):
        """
        Select audio input on the device.
        
        Args:
            input (int): Audio input number/identifier
            
        Returns:
            bool: True if command sent successfully
        """
    
    def transmit(self, opcode, parameters):
        """
        Transmit a raw CEC command to this device.
        
        Args:
            opcode (int): CEC opcode for the command
            parameters (bytes): Command parameters as byte string
            
        Returns:
            bool: True if transmission successful
        """

Constants

Event Types

Event type constants for use with callback registration:

EVENT_LOG = 1           # Log message events
EVENT_KEYPRESS = 2      # Key press events
EVENT_COMMAND = 4       # CEC command events
EVENT_CONFIG_CHANGE = 8 # Configuration change events (not implemented)
EVENT_ALERT = 16        # Alert events
EVENT_MENU_CHANGED = 32 # Menu state change events
EVENT_ACTIVATED = 64    # Device activation events
EVENT_ALL = 127         # All event types combined

Alert Types

Alert type constants for EVENT_ALERT callbacks:

CEC_ALERT_SERVICE_DEVICE = 1         # Service device alert
CEC_ALERT_CONNECTION_LOST = 2        # Connection lost alert
CEC_ALERT_PERMISSION_ERROR = 3       # Permission error alert
CEC_ALERT_PORT_BUSY = 4              # Port busy alert
CEC_ALERT_PHYSICAL_ADDRESS_ERROR = 5 # Physical address error alert
CEC_ALERT_TV_POLL_FAILED = 6         # TV polling failed alert

Menu States

Menu state constants for EVENT_MENU_CHANGED callbacks:

CEC_MENU_STATE_ACTIVATED = 0    # Menu activated state
CEC_MENU_STATE_DEACTIVATED = 1  # Menu deactivated state

Device Types

Device type constants for device classification:

CEC_DEVICE_TYPE_TV = 0               # TV device type
CEC_DEVICE_TYPE_RECORDING_DEVICE = 1 # Recording device type
CEC_DEVICE_TYPE_RESERVED = 2         # Reserved device type
CEC_DEVICE_TYPE_TUNER = 3            # Tuner device type
CEC_DEVICE_TYPE_PLAYBACK_DEVICE = 4  # Playback device type
CEC_DEVICE_TYPE_AUDIO_SYSTEM = 5     # Audio system device type

Logical Addresses

Logical address constants for device identification:

CECDEVICE_UNKNOWN = -1          # Unknown device address
CECDEVICE_TV = 0                # TV logical address
CECDEVICE_RECORDINGDEVICE1 = 1  # Recording device 1 address
CECDEVICE_RECORDINGDEVICE2 = 2  # Recording device 2 address
CECDEVICE_TUNER1 = 3            # Tuner 1 address
CECDEVICE_PLAYBACKDEVICE1 = 4   # Playback device 1 address
CECDEVICE_AUDIOSYSTEM = 5       # Audio system address
CECDEVICE_TUNER2 = 6            # Tuner 2 address
CECDEVICE_TUNER3 = 7            # Tuner 3 address
CECDEVICE_PLAYBACKDEVICE2 = 8   # Playback device 2 address
CECDEVICE_RECORDINGDEVICE3 = 9  # Recording device 3 address
CECDEVICE_TUNER4 = 10           # Tuner 4 address
CECDEVICE_PLAYBACKDEVICE3 = 11  # Playback device 3 address
CECDEVICE_RESERVED1 = 12        # Reserved address 1
CECDEVICE_RESERVED2 = 13        # Reserved address 2
CECDEVICE_FREEUSE = 14          # Free use address
CECDEVICE_UNREGISTERED = 15     # Unregistered device address
CECDEVICE_BROADCAST = 15        # Broadcast address

CEC Opcodes

CEC command opcodes for raw communication (selection of commonly used opcodes):

# Power Management
CEC_OPCODE_STANDBY = 0x36                      # Put device in standby
CEC_OPCODE_IMAGE_VIEW_ON = 0x04                # Turn on and show image
CEC_OPCODE_TEXT_VIEW_ON = 0x0D                 # Turn on and show text
CEC_OPCODE_GIVE_DEVICE_POWER_STATUS = 0x8F     # Request power status
CEC_OPCODE_REPORT_POWER_STATUS = 0x90          # Report power status

# Active Source Management  
CEC_OPCODE_ACTIVE_SOURCE = 0x82                # Set active source
CEC_OPCODE_INACTIVE_SOURCE = 0x9D              # Set inactive source
CEC_OPCODE_REQUEST_ACTIVE_SOURCE = 0x85        # Request active source
CEC_OPCODE_SET_STREAM_PATH = 0x86              # Set stream path
CEC_OPCODE_ROUTING_CHANGE = 0x80               # Routing change
CEC_OPCODE_ROUTING_INFORMATION = 0x81          # Routing information

# Device Information
CEC_OPCODE_GIVE_PHYSICAL_ADDRESS = 0x83        # Request physical address
CEC_OPCODE_REPORT_PHYSICAL_ADDRESS = 0x84      # Report physical address  
CEC_OPCODE_GIVE_OSD_NAME = 0x46                # Request OSD name
CEC_OPCODE_SET_OSD_NAME = 0x47                 # Set OSD name
CEC_OPCODE_GIVE_DEVICE_VENDOR_ID = 0x8C        # Request vendor ID
CEC_OPCODE_DEVICE_VENDOR_ID = 0x87             # Report vendor ID
CEC_OPCODE_GET_CEC_VERSION = 0x9F              # Request CEC version
CEC_OPCODE_CEC_VERSION = 0x9E                  # Report CEC version

# Audio System
CEC_OPCODE_GIVE_AUDIO_STATUS = 0x71            # Request audio status
CEC_OPCODE_REPORT_AUDIO_STATUS = 0x7A          # Report audio status
CEC_OPCODE_GIVE_SYSTEM_AUDIO_MODE_STATUS = 0x7D # Request system audio mode
CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS = 0x7E      # Report system audio mode
CEC_OPCODE_SET_SYSTEM_AUDIO_MODE = 0x72         # Set system audio mode
CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST = 0x70     # Request system audio mode

# User Control
CEC_OPCODE_USER_CONTROL_PRESSED = 0x44         # User pressed button
CEC_OPCODE_USER_CONTROL_RELEASE = 0x45         # User released button

# Menu Control
CEC_OPCODE_MENU_REQUEST = 0x8D                 # Menu request
CEC_OPCODE_MENU_STATUS = 0x8E                  # Menu status

# Recording/Timer Control
CEC_OPCODE_RECORD_OFF = 0x0B                   # Stop recording
CEC_OPCODE_RECORD_ON = 0x09                    # Start recording
CEC_OPCODE_RECORD_STATUS = 0x0A                # Report recording status
CEC_OPCODE_RECORD_TV_SCREEN = 0x0F             # Record TV screen
CEC_OPCODE_CLEAR_ANALOGUE_TIMER = 0x33         # Clear analogue timer
CEC_OPCODE_CLEAR_DIGITAL_TIMER = 0x99          # Clear digital timer
CEC_OPCODE_CLEAR_EXTERNAL_TIMER = 0xA1         # Clear external timer
CEC_OPCODE_SET_ANALOGUE_TIMER = 0x34           # Set analogue timer
CEC_OPCODE_SET_DIGITAL_TIMER = 0x97            # Set digital timer
CEC_OPCODE_SET_EXTERNAL_TIMER = 0xA2           # Set external timer
CEC_OPCODE_SET_TIMER_PROGRAM_TITLE = 0x67      # Set timer program title
CEC_OPCODE_TIMER_CLEARED_STATUS = 0x43         # Timer cleared status
CEC_OPCODE_TIMER_STATUS = 0x35                 # Timer status

# Deck Control
CEC_OPCODE_DECK_CONTROL = 0x42                 # Deck control command
CEC_OPCODE_DECK_STATUS = 0x1B                  # Deck status report
CEC_OPCODE_GIVE_DECK_STATUS = 0x1A             # Request deck status
CEC_OPCODE_PLAY = 0x41                         # Play command

# Tuner Control
CEC_OPCODE_GIVE_TUNER_DEVICE_STATUS = 0x08     # Request tuner status
CEC_OPCODE_SELECT_ANALOGUE_SERVICE = 0x92      # Select analogue service
CEC_OPCODE_SELECT_DIGITAL_SERVICE = 0x93       # Select digital service
CEC_OPCODE_TUNER_DEVICE_STATUS = 0x07          # Report tuner status
CEC_OPCODE_TUNER_STEP_DECREMENT = 0x06         # Tuner step down
CEC_OPCODE_TUNER_STEP_INCREMENT = 0x05         # Tuner step up

# Menu/Language Control
CEC_OPCODE_GET_MENU_LANGUAGE = 0x91            # Request menu language
CEC_OPCODE_SET_MENU_LANGUAGE = 0x32            # Set menu language
CEC_OPCODE_SET_OSD_STRING = 0x64               # Set OSD string

# Vendor Commands
CEC_OPCODE_VENDOR_COMMAND = 0x89               # Vendor-specific command
CEC_OPCODE_VENDOR_COMMAND_WITH_ID = 0xA0       # Vendor command with ID
CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN = 0x8A    # Vendor remote button down
CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP = 0x8B      # Vendor remote button up

# Audio Return Channel (ARC)
CEC_OPCODE_START_ARC = 0xC0                    # Start audio return channel
CEC_OPCODE_REPORT_ARC_STARTED = 0xC1           # Report ARC started
CEC_OPCODE_REPORT_ARC_ENDED = 0xC2             # Report ARC ended
CEC_OPCODE_REQUEST_ARC_START = 0xC3            # Request ARC start
CEC_OPCODE_REQUEST_ARC_END = 0xC4              # Request ARC end
CEC_OPCODE_END_ARC = 0xC5                      # End audio return channel

# Audio Rate Control
CEC_OPCODE_SET_AUDIO_RATE = 0x9A               # Set audio sample rate

# Special/Advanced
CEC_OPCODE_CDC = 0xF8                          # Capability Discovery and Control
CEC_OPCODE_NONE = 0xFD                         # No operation

# General
CEC_OPCODE_FEATURE_ABORT = 0x00                # Feature not supported
CEC_OPCODE_ABORT = 0xFF                        # Abort message

Library Feature Constants

Feature availability constants for checking library capabilities:

HAVE_CEC_ADAPTER_DESCRIPTOR = 0 or 1    # Whether library supports adapter descriptors

Advanced Usage Examples

Event Handling

import cec

def log_callback(event, level, time, message):
    """Handle log messages."""
    print(f"CEC Log [{level}]: {message}")

def command_callback(event, source, destination, opcode, parameters):
    """Handle CEC commands."""
    print(f"CEC Command: {source} -> {destination}, opcode: {opcode}")

def key_callback(event, key_code, duration):
    """Handle key press events."""
    print(f"Key pressed: {key_code}, duration: {duration}")

# Register callbacks
cec.add_callback(log_callback, cec.EVENT_LOG)
cec.add_callback(command_callback, cec.EVENT_COMMAND)
cec.add_callback(key_callback, cec.EVENT_KEYPRESS)

# Initialize and use CEC
cec.init()

# Your application logic here...

# Remove callbacks when done
cec.remove_callback(log_callback, cec.EVENT_LOG)
cec.remove_callback(command_callback, cec.EVENT_COMMAND)
cec.remove_callback(key_callback, cec.EVENT_KEYPRESS)

Device Enumeration and Control

import cec

# Initialize CEC
adapters = cec.list_adapters()
if adapters:
    print(f"Available adapters: {adapters}")
    cec.init(adapters[0])  # Use first adapter
else:
    cec.init()  # Use default adapter

# Discover devices
devices = cec.list_devices()
print(f"Discovered devices: {devices}")

# Create device objects and query information
for device_addr in devices:
    device = cec.Device(device_addr)
    print(f"Device {device_addr}:")
    print(f"  Physical Address: {device.physical_address}")
    print(f"  OSD Name: {device.osd_string}")
    print(f"  Vendor: {device.vendor}")
    print(f"  CEC Version: {device.cec_version}")
    print(f"  Language: {device.language}")
    print(f"  Is On: {device.is_on()}")
    print(f"  Is Active: {device.is_active()}")

Raw Command Transmission

import cec

cec.init()

# Set arbitrary device as active source (physical address 2.0.0.0)
destination = cec.CECDEVICE_BROADCAST
opcode = cec.CEC_OPCODE_ACTIVE_SOURCE
parameters = b'\x20\x00'  # Physical address 2.0.0.0

success = cec.transmit(destination, opcode, parameters)
print(f"Command transmission {'successful' if success else 'failed'}")

# Send standby command to TV
tv_addr = cec.CECDEVICE_TV
standby_opcode = cec.CEC_OPCODE_STANDBY
success = cec.transmit(tv_addr, standby_opcode, b'')
print(f"Standby command {'sent' if success else 'failed'}")

Configuration Management

import cec

cec.init()

# Check if adapter supports configuration persistence
if cec.can_persist_config():
    print("Adapter supports configuration persistence")
    
    # Set physical address
    success = cec.set_physical_addr(0x2000)  # Physical address 2.0.0.0
    if success:
        print("Physical address set")
        
        # Persist configuration
        if cec.persist_config():
            print("Configuration persisted to adapter")
        else:
            print("Failed to persist configuration")
    else:
        print("Failed to set physical address")
else:
    print("Adapter does not support configuration persistence")

Error Handling

The CEC library may raise exceptions or return False/None for failed operations:

  • RuntimeError: Raised during initialization failures or critical errors
  • False return values: Most functions return False when commands fail to send
  • None return values: Some functions return None when unable to retrieve information
  • Empty lists: Device/adapter listing functions return empty lists when none found

Always check return values and handle potential exceptions:

import cec

try:
    # Initialize with error handling
    adapters = cec.list_adapters()
    if not adapters:
        print("No CEC adapters found")
        exit(1)
    
    cec.init(adapters[0])
    print("CEC initialized successfully")
    
    # Device operations with return value checking
    tv = cec.Device(cec.CECDEVICE_TV)
    
    if tv.power_on():
        print("TV power on command sent")
    else:
        print("Failed to send TV power on command")
        
    # Volume control with return value checking
    if cec.volume_up():
        print("Volume up command sent")
    else:
        print("Failed to send volume up command")
        
except RuntimeError as e:
    print(f"CEC initialization failed: {e}")
except Exception as e:
    print(f"Unexpected error: {e}")

Platform Considerations

  • Linux: Requires libcec development libraries and appropriate permissions for CEC device access
  • Windows: Requires building libcec from source as binary distributions don't include required development files
  • macOS: Install libcec via Homebrew (brew install libcec)
  • Raspberry Pi: Built-in CEC support, no additional hardware required
  • Hardware: Most computer graphics cards don't support CEC; requires dedicated CEC adapter (Pulse-Eight USB-CEC) or compatible hardware