HAP-python Documentation

repository·dev·Indexed 20 days ago

https://github.com/ikalchev/hap-python

A Python 3 implementation of the HomeKit Accessory Protocol (HAP) that enables developers to integrate custom smart devices into the Apple Home app and control them via Siri. The library provides core classes such as Accessory, Bridge, AccessoryDriver, and Service to manage device lifecycles, networking, and state within the HomeKit ecosystem.

Tokens
5.7K
Snippets
25
Records
26
Agent score
70%

What's inside HAP-python

  1. Use Service Callbacks for tightly coupled characteristics

    dev

    When multiple characteristics are updated together (e.g., 'On' and 'Brightness' for a lightbulb), using individual characteristic callbacks can cause race conditions or redundant updates.

    To handle these as a single atomic request, use a Service Callback. Instead of setting callbacks on individual characteristics, set the setter_callback on the Service itself. The callback receives a dictionary of all changed characteristic values.

    from pyhap.accessory import Accessory
    from pyhap.const import Category
    
    class Light(Accessory):
        category = Category.CATEGORY_LIGHTBULB
    
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            
            serv_light = self.add_preload_service('Lightbulb')
            # Configure characteristics
            self.char_on = serv_light.configure_char('On', value=False)
            self.char_brightness = serv_light.configure_char('Brightness', value=100)
    
            # Set the callback on the SERVICE, not the characteristic
            serv_light.setter_callback = self._set_chars
    
        def _set_chars(self, char_values):
            # char_values is a dict containing all changed keys
            if "On" in char_values:
                print('On changed to: ', char_values["On"])
            if "Brightness" in char_values:
                print('Brightness changed to: ', char_values["Brightness"])
    
        @Accessory.run_at_interval(3)
        def run(self):
            import random
            self.char_on.set_value(random.randint(0, 1))
            self.char_brightness.set_value(random.randint(1, 100))
    
        def stop(self):
            print('Stopping accessory.')
  2. Use the Bridge class to host multiple Accessories

    dev

    The pyhap.accessory.Bridge class acts as a central host for multiple HAP Accessories. In the HomeKit architecture, a Bridge allows you to group several individual accessories together so they can be presented to a HomeKit controller as a single unit or a collection of devices. When building a complex HAP server, you should use the Bridge class to manage the lifecycle and connectivity of your various accessories.

    from pyhap.accessory import Bridge
    
    # Initialize the bridge
    bridge = Bridge()
    
    # You can then add multiple accessories to this bridge instance
    # bridge.add_accessory(my_accessory)
  3. Install HAP-python

    dev

    HAP-python requires Python 3.6 or newer due to its use of asyncio.

    Prerequisites: You must have Avahi/Bonjour installed for the zeroconf package to work. On Raspberry Pi, install it using:

    sudo apt-get install libavahi-compat-libdnssd-dev

    Installation: Install the package via pip3. It is recommended to include the [QRCode] extra to support QR code scanning for pairing.

    pip3 install HAP-python[QRCode]

    Once installed, you can import the library in your Python code as pyhap.

    pip3 install HAP-python[QRCode]
  4. Configure a Shutdown Switch for Raspberry Pi

    dev

    You can add a ShutdownSwitch accessory (found in pyhap/accessories/ShutdownSwitch.py) to your HomeKit setup. When triggered, this switch executes sudo shutdown -h now, allowing you to safely power down and unplug your Raspberry Pi.

    Configuration Requirement: For the switch to function, the user running the HAP-python process must be able to execute /sbin/shutdown without a password.

    To configure this, edit your sudoers file using sudo visudo and add the following line (replacing <hap-user> with the actual username used in your service configuration):

    <hap-user> ALL=NOPASSWD: /sbin/shutdown

    $ sudo visudo # and add the line: "<hap-user> ALL=NOPASSWD: /sbin/shutdown".
  5. View generated documentation

    dev
    After compiling the documentation, you can view it in your default web browser by running the make htmlview command. Note that this command requires the documentation to have been previously generated via make html.
    make htmlview
  6. Install HAP-python using a virtualenv

    dev

    It is recommended to install HAP-python within a Python 3 virtual environment.

    1. Ensure python3-venv is installed on your system.
    2. Create a project directory and navigate into it.
    3. Create and activate the virtual environment.
    4. Install HAP-python using pip.
    # Install venv module if not present
    sudo apt install python3-venv
    
    # Setup project directory
    mkdir hk_project
    cd hk_project
    
    # Create and activate virtualenv
    python3 -m venv venv
    source venv/bin/activate
    
    # Install HAP-python
    pip install HAP-python
  7. Configure and customize Camera accessories

    dev

    The Camera accessory handles HomeKit stream negotiation. By default, HAP-python uses ffmpeg to manage streams via the Camera.FFMPEG_CMD command.

    Customizing the Stream Command

    If the default ffmpeg command doesn't work for your platform, you can provide a custom command via the options dictionary passed to the Camera constructor using the start_stream_cmd key.

    Variables like {width}, {height}, and {audio_channels} can be used in your command string and will be replaced by the negotiated values.

    Example: start_stream_cmd: 'foo start -width {width}' becomes foo start -width 640.

    Implementing Custom Stream Logic

    For maximum control, override these Camera methods:

    • start(self, width, height, audio_channels, ...): Called when the stream starts.
    • stop(self): Called when the stream stops.
    • reconfigure(self, width, height, ...): Called when stream parameters change.
    • snapshot(self): Override this to provide custom logic for taking snapshots (the default returns a stock photo).
    # Example of passing a custom command via options
    # options = {'start_stream_cmd': 'my_custom_tool --w {width} --h {height}'}
    # camera = Camera(options=options, ...)
  8. Run HAP-python at boot on Raspberry Pi

    dev

    To run HAP-python as a background daemon that starts automatically on boot, create a systemd service file at /etc/systemd/system/HAP-python.service.

    Prerequisites:

    • It is recommended to enable "Wait for network" in raspi-config to ensure network services are available.
    • If your implementation depends on pigpiod, include it in the Wants and After directives. Otherwise, remove it.
    • Use an unprivileged system user (e.g., lesserdaemon) for the User directive for better security.
    • Ensure all paths in ExecStart (for the Python interpreter and your script) and any paths used for state persistence are absolute and correct.

    Service Management Commands:

    • Start the service: sudo systemctl start HAP-python
    • Check status: systemctl status HAP-python
    • View logs: sudo journalctl -u HAP-python
    • Stop the service: sudo systemctl stop HAP-python
    • Enable auto-start at boot: sudo systemctl enable HAP-python
    • Disable auto-start at boot: sudo systemctl disable HAP-python
    [Unit]
    Description = HAP-python daemon
    Wants = pigpiod.service
    After = local-fs.target network-online.target pigpiod.service
    
    [Service]
    User = lesserdaemon
    ExecStart = /usr/bin/python3 /home/lesserdaemon/.hap-python/hap-python.py
    
    [Install]
    WantedBy = multi-user.target
  9. Create a HAP-python accessory subpackage

    dev

    You can share custom device implementations as subpackages of pyhap.accessories using native Python namespace packages. This allows your accessory to be imported under the pyhap.accessories.<your_accessory> namespace without requiring __init__.py files in the parent pyhap or accessories directories.

    Directory Structure

    Ensure your project follows this structure (note the absence of __init__.py in the parent directories):

    pyhap/
        # NO __init__.py here !!!
        accessories/
            # NO __init__.py here !!!
            bulb/
                __init__.py
                ... the code for the bulb accessory ...

    Packaging with setup.py

    In your setup.py file, explicitly include the specific subpackage path in the packages list:

    setup(
        ...
        packages=['pyhap.accessories.bulb'],
        ...
    )

    Installation and Usage

    Users can install your accessory via pip (if uploaded) or by cloning the repository:

    # Via pip
    pip install HAP-python-bulb
    
    # Or via git clone
    git clone <repository_url>
    python3 setup.py install

    Once installed, the accessory can be used in Python code via:

    import pyhap.accessories.bulb