### Importing Installed Subpackage Source: https://github.com/ikalchev/hap-python/blob/dev/pyhap/accessories/README.md After installation via pip or `setup.py install`, users can import your accessory subpackage directly. ```python import pyhap.accessories.bulb ``` -------------------------------- ### Install HAP-python with QRCode support Source: https://github.com/ikalchev/hap-python/blob/dev/README.md Installs HAP-python along with QRCode support for secure pairing. Ensure Avahi/Bonjour is installed as a prerequisite. ```sh pip3 install HAP-python[QRCode] ``` -------------------------------- ### Install Dependencies Source: https://github.com/ikalchev/hap-python/blob/dev/docs/README.rst Installs Sphinx and its dependencies from the requirements file. Run this command from the project directory. ```bash pip install -r requirements.txt ``` -------------------------------- ### Start Accessory Driver with Custom Outlet Source: https://context7.com/ikalchev/hap-python/llms.txt Initializes the AccessoryDriver and adds the custom 'MyOutlet' accessory, then starts the driver. This is the main execution block for the outlet accessory. ```python driver = AccessoryDriver(port=51826) driver.add_accessory(accessory=MyOutlet(driver, 'Smart Outlet')) driver.start() ``` -------------------------------- ### Start Accessory Driver Source: https://context7.com/ikalchev/hap-python/llms.txt Initializes and starts the HAP accessory driver, adding accessories and handling signals. ```python driver = AccessoryDriver(port=51826) driver.add_accessory(accessory=GPIOLightBulb(driver, 'LED Light', pin=17)) signal.signal(signal.SIGTERM, driver.signal_handler) driver.start() ``` ```python driver = AccessoryDriver(port=51826) driver.add_accessory(accessory=GarageDoor(driver, 'Garage Door')) signal.signal(signal.SIGTERM, driver.signal_handler) driver.start() ``` -------------------------------- ### Setup.py Configuration for Subpackage Source: https://github.com/ikalchev/hap-python/blob/dev/pyhap/accessories/README.md Configure your `setup.py` to include the accessory subpackage. This allows it to be installed and imported by other users. ```python setup( ... packages=['pyhap.accessories.bulb'], ... ) ``` -------------------------------- ### Install Avahi/Bonjour on Raspbian Stretch Source: https://github.com/ikalchev/hap-python/blob/dev/docs/source/intro/install.md Installs the necessary Avahi/Bonjour development files on Raspbian Stretch. This is a prerequisite for the `zeroconf` package. ```default sudo apt install libavahi-compat-libdnssd-dev ``` -------------------------------- ### Start Accessory Driver with Custom Accessory Source: https://context7.com/ikalchev/hap-python/llms.txt This snippet shows how to initialize the AccessoryDriver and add a custom accessory to it, then start the driver. This is the main entry point for running a HAP-Python accessory. ```python driver = AccessoryDriver(port=51826) driver.add_accessory(accessory=CustomSensorAccessory(driver, 'Custom Sensor')) signal.signal(signal.SIGTERM, driver.signal_handler) driver.start() ``` -------------------------------- ### GPIO Integration Example Source: https://context7.com/ikalchev/hap-python/llms.txt This snippet is a placeholder for controlling real hardware using GPIO pins with HAP-python accessories on a Raspberry Pi. Uncomment the import for actual usage. ```python from pyhap.accessory import Accessory from pyhap.accessory_driver import AccessoryDriver from pyhap.const import CATEGORY_LIGHTBULB, CATEGORY_SWITCH import signal # Uncomment for real Raspberry Pi usage ``` -------------------------------- ### List and Get Services/Characteristics Source: https://context7.com/ikalchev/hap-python/llms.txt Demonstrates how to list available services, retrieve a specific service by name, and get a characteristic by name. Requires a loaded service definition. ```python print("Available services:") for service_name in list(loader.serv_types.keys())[:10]: print(f" - {service_name}") # Get a specific service temp_service = loader.get_service('TemperatureSensor') print(f"\nTemperatureSensor UUID: {temp_service.type_id}") # Get a specific characteristic temp_char = loader.get_char('CurrentTemperature') print(f"CurrentTemperature format: {temp_char.properties['Format']}") ``` -------------------------------- ### Create a Basic Temperature Sensor Accessory Source: https://context7.com/ikalchev/hap-python/llms.txt Subclass `Accessory` to define a custom HomeKit device. This example creates a temperature sensor that reports random temperatures every 3 seconds. Ensure `pyhap` is installed. ```python import logging import signal import random from pyhap.accessory import Accessory from pyhap.accessory_driver import AccessoryDriver from pyhap.const import CATEGORY_SENSOR logging.basicConfig(level=logging.INFO, format="[%(module)s] %(message)s") class TemperatureSensor(Accessory): """A temperature sensor accessory that reports random temperatures.""" category = CATEGORY_SENSOR # Icon category in iOS Home app def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Add the TemperatureSensor service with CurrentTemperature characteristic serv_temp = self.add_preload_service('TemperatureSensor') self.char_temp = serv_temp.configure_char('CurrentTemperature') @Accessory.run_at_interval(3) # Execute every 3 seconds async def run(self): """Update temperature value periodically.""" self.char_temp.set_value(random.randint(18, 26)) async def stop(self): """Clean up resources when accessory stops.""" print('Stopping temperature sensor.') # Create driver and start the accessory driver = AccessoryDriver(port=51826) driver.add_accessory(accessory=TemperatureSensor(driver, 'MyTempSensor')) signal.signal(signal.SIGTERM, driver.signal_handler) driver.start() ``` -------------------------------- ### Install Avahi/Bonjour on Raspberry Pi Source: https://github.com/ikalchev/hap-python/blob/dev/README.md Installs the necessary Avahi/Bonjour dependencies required for HAP-python's zeroconf package on a Raspberry Pi. ```sh sudo apt-get install libavahi-compat-libdnssd-dev ``` -------------------------------- ### Install Avahi/Bonjour and Python Dev on Ubuntu 16.04 LTS Source: https://github.com/ikalchev/hap-python/blob/dev/docs/source/intro/install.md Installs Avahi/Bonjour development files and the Python 3 development package on Ubuntu 16.04 LTS. These are prerequisites for HAP-python. ```default sudo apt install libavahi-compat-libdnssd-dev python3-dev ``` -------------------------------- ### Watch for Documentation Changes Source: https://github.com/ikalchev/hap-python/blob/dev/docs/README.rst Recreates the documentation automatically when changes are made. Requires 'watchdog' to be installed ('pip install watchdog'). Run this command from the project directory. ```bash make watch ``` -------------------------------- ### Install HAP-python with Pip Source: https://github.com/ikalchev/hap-python/blob/dev/docs/source/intro/install.md Installs the HAP-python package using pip within an activated virtual environment. This command should be run after setting up and activating your virtual environment. ```default pip install HAP-python ``` -------------------------------- ### Camera Accessory Setup with Video Streaming Source: https://context7.com/ikalchev/hap-python/llms.txt Create a camera accessory with video streaming capabilities using ffmpeg. Configure video and audio codecs, resolutions, and an optional custom ffmpeg command. ```python from pyhap.accessory_driver import AccessoryDriver from pyhap.camera import ( Camera, VIDEO_CODEC_PARAM_PROFILE_ID_TYPES, VIDEO_CODEC_PARAM_LEVEL_TYPES, ) import signal # Camera configuration options options = { "video": { "codec": { "profiles": [ VIDEO_CODEC_PARAM_PROFILE_ID_TYPES["BASELINE"], VIDEO_CODEC_PARAM_PROFILE_ID_TYPES["MAIN"], VIDEO_CODEC_PARAM_PROFILE_ID_TYPES["HIGH"], ], "levels": [ VIDEO_CODEC_PARAM_LEVEL_TYPES["TYPE3_1"], VIDEO_CODEC_PARAM_LEVEL_TYPES["TYPE3_2"], VIDEO_CODEC_PARAM_LEVEL_TYPES["TYPE4_0"], ], }, "resolutions": [ [1920, 1080, 30], # Width, Height, FPS [1280, 720, 30], [640, 480, 30], [640, 360, 30], [480, 360, 30], [320, 240, 15], ], }, "audio": { "codecs": [ {"type": "OPUS", "samplerate": 24}, {"type": "AAC-eld", "samplerate": 16}, ], }, "address": "192.168.1.100", # Camera's streaming address "srtp": True, # Enable SRTP encryption "stream_count": 2, # Support 2 simultaneous streams } # Custom ffmpeg command (optional) options["start_stream_cmd"] = ( "ffmpeg -re -f avfoundation -framerate {fps} -i 0:0 " "-vcodec libx264 -an -pix_fmt yuv420p -r {fps} " "-vf scale={width}:{height} -b:v {v_max_bitrate}k " "-payload_type 99 -ssrc {v_ssrc} -f rtp " "-srtp_out_suite AES_CM_128_HMAC_SHA1_80 " "-srtp_out_params {v_srtp_key} " "srtp://{address}:{v_port}?rtcpport={v_port}&pkt_size=1378" ) class MyCamera(Camera): """Custom camera with snapshot support.""" def get_snapshot(self, image_size): """Return a JPEG snapshot from the camera.""" # Implement actual snapshot capture here # image_size contains 'image-width' and 'image-height' import subprocess result = subprocess.run( ['ffmpeg', '-f', 'avfoundation', '-i', '0', '-vframes', '1', '-f', 'mjpeg', '-'], capture_output=True ) return result.stdout driver = AccessoryDriver(port=51826) camera = MyCamera(options, driver, 'Front Door Camera') driver.add_accessory(accessory=camera) signal.signal(signal.SIGTERM, driver.signal_handler) driver.start() ``` -------------------------------- ### Implement Lightbulb Accessory with Service Callback Source: https://github.com/ikalchev/hap-python/blob/dev/README.md This example demonstrates how to create a Lightbulb accessory that uses a service callback to handle changes to 'On' and 'Brightness' characteristics. The `_set_chars` method is invoked when either characteristic's value is updated. ```python from pyhap.accessory import Accessory from pyhap.const import Category import pyhap.loader as loader import random class Light(Accessory): """Implementation of a mock light accessory.""" category = Category.CATEGORY_LIGHTBULB # This is for the icon in the iOS Home app. def __init__(self, *args, **kwargs): """Here, we just store a reference to the on and brightness characteristics and add a method that will be executed every time their value changes. """ # If overriding this method, be sure to call the super's implementation first. super().__init__(*args, **kwargs) # Add the services that this Accessory will support with add_preload_service here serv_light = self.add_preload_service('Lightbulb') self.char_on = serv_light.configure_char('On', value=self._state) self.char_brightness = serv_light.configure_char('Brightness', value=100) serv_light.setter_callback = self._set_chars def _set_chars(self, char_values): """This will be called every time the value of the on of the characteristics on the service changes. """ 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) # Run this method every 3 seconds # The `run` method can be `async` as well def run(self): """We override this method to implement what the accessory will do when it is started. We set the current temperature to a random number. The decorator runs this method every 3 seconds. """ self.char_on.set_value(random.randint(0, 1)) self.char_brightness.set_value(random.randint(1, 100)) # The `stop` method can be `async` as well def stop(self): """We override this method to clean up any resources or perform final actions, as this is called by the AccessoryDriver when the Accessory is being stopped. """ print('Stopping accessory.') ``` -------------------------------- ### Install Python 3 Venv Module Source: https://github.com/ikalchev/hap-python/blob/dev/docs/source/intro/install.md Installs the `venv` module for Python 3, which is required for creating virtual environments. This ensures project dependencies are isolated. ```default sudo apt install python3-venv ``` -------------------------------- ### Create and Activate Virtual Environment Source: https://github.com/ikalchev/hap-python/blob/dev/docs/source/intro/install.md Creates a Python 3 virtual environment named 'venv' and activates it. Activating the environment ensures that subsequent package installations are isolated to this project. ```default python3 -m venv venv source venv/bin/activate ``` -------------------------------- ### Clean Documentation Files Source: https://github.com/ikalchev/hap-python/blob/dev/docs/README.rst Removes all generated documentation files to start from scratch. This command does not affect source files. Run this command from the project directory. ```bash make clean ``` -------------------------------- ### Configure AccessoryDriver with Custom Options Source: https://context7.com/ikalchev/hap-python/llms.txt The `AccessoryDriver` manages mDNS advertising, HAP server, and accessory lifecycle. This example shows how to configure the driver with a specific port, IP address, state persistence file, custom PIN, MAC address, and listen/advertised addresses. ```python from pyhap.accessory_driver import AccessoryDriver from pyhap.accessory import Accessory from pyhap.const import CATEGORY_LIGHTBULB class MyLight(Accessory): category = CATEGORY_LIGHTBULB def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) serv = self.add_preload_service('Lightbulb') self.char_on = serv.configure_char('On', setter_callback=self.on_change) def on_change(self, value): print(f"Light is now {'on' if value else 'off'}") # Full driver configuration driver = AccessoryDriver( port=51826, # HAP server port address='192.168.1.100', # Local IP address (auto-detected if None) persist_file='~/myaccessory.state', # State persistence file path pincode=b'123-45-678', # Custom pairing PIN (auto-generated if None) mac='AA:BB:CC:DD:EE:FF', # Custom MAC address (auto-generated if None) listen_address='0.0.0.0', # Address to bind server advertised_address='192.168.1.100', # Address announced via mDNS (for NAT) ) # Add accessory and start accessory = MyLight(driver, 'Kitchen Light') accessory.set_info_service( firmware_revision='1.0.0', manufacturer='My Company', model='Smart Light v1', serial_number='ABC123' ) driver.add_accessory(accessory=accessory) driver.start() ``` -------------------------------- ### Start Event Loop with loop.run_forever() in HAP-Python Source: https://github.com/ikalchev/hap-python/blob/dev/CHANGELOG.md The `driver.start` method initiates the event loop using `loop.run_forever()`. This ensures the driver remains active and responsive. ```python driver.start starts the event loop with loop.run_forever() ``` -------------------------------- ### Enable/Disable HAP-python at Boot Source: https://github.com/ikalchev/hap-python/blob/dev/README.md Commands to enable or disable the HAP-python service from starting automatically at boot. ```sh sudo systemctl enable HAP-python ``` ```sh sudo systemctl disable HAP-python ``` -------------------------------- ### Manage HAP-python Systemd Service Source: https://github.com/ikalchev/hap-python/blob/dev/README.md Commands to start, check status, view logs, and stop the HAP-python systemd service. Use 'journalctl' to view output from the startup script. ```sh sudo systemctl start HAP-python ``` ```sh systemctl status HAP-python ``` ```sh sudo journalctl -u HAP-python # to see the output of the start up script. ``` ```sh sudo systemctl stop HAP-python ``` -------------------------------- ### Control Accessory Availability Status Source: https://context7.com/ikalchev/hap-python/llms.txt Override the 'available' property to control accessory visibility in the Home app. This example shows a network sensor that reports unavailable when its connection is lost. ```python from pyhap.accessory import Accessory from pyhap.accessory_driver import AccessoryDriver from pyhap.const import CATEGORY_SENSOR import signal class NetworkSensor(Accessory): """Sensor that reports unavailable when network connection is lost.""" category = CATEGORY_SENSOR def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._connected = True serv = self.add_preload_service('TemperatureSensor') self.char_temp = serv.configure_char('CurrentTemperature') @property def available(self): """Return False to show accessory as unavailable in Home app.""" return self._connected def set_connection_status(self, connected): """Call this when network status changes.""" self._connected = connected if connected: print("Sensor connected - accessory available") else: print("Sensor disconnected - accessory unavailable") @Accessory.run_at_interval(5) async def run(self): if self._connected: # Simulate reading from remote sensor self.char_temp.set_value(22.5) driver = AccessoryDriver(port=51826) sensor = NetworkSensor(driver, 'Network Sensor') driver.add_accessory(accessory=sensor) signal.signal(signal.SIGTERM, driver.signal_handler) # Simulate connection loss # sensor.set_connection_status(False) driver.start() ``` -------------------------------- ### Manage HAP-Python Systemd Service Source: https://context7.com/ikalchev/hap-python/llms.txt Contains bash commands to manage the HAP-Python systemd service, including reloading the daemon, enabling/disabling it to start on boot, starting/stopping the service, and viewing its status and logs. ```bash # Enable and manage the service sudo systemctl daemon-reload sudo systemctl enable hap-python sudo systemctl start hap-python sudo systemctl status hap-python # View logs sudo journalctl -u hap-python -f ``` -------------------------------- ### Customize Fan Rotation Speed Properties Source: https://context7.com/ikalchev/hap-python/llms.txt Override characteristic properties to customize constraints like minValue, maxValue, and minStep for the RotationSpeed characteristic. This example also shows how to set valid_values for specific string representations. ```python from pyhap.accessory import Accessory from pyhap.accessory_driver import AccessoryDriver from pyhap.const import CATEGORY_FAN import signal class CustomFan(Accessory): """Fan with custom rotation speed constraints.""" category = CATEGORY_FAN def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) serv = self.add_preload_service('Fan', chars=['RotationSpeed']) # Override properties to customize the characteristic self.char_speed = serv.configure_char( 'RotationSpeed', value=0, setter_callback=self.set_speed, properties={ 'minValue': 0, 'maxValue': 100, 'minStep': 25 # Only allow 0, 25, 50, 75, 100 } ) # Alternative: override properties after configuration self.char_speed.override_properties( properties={'minStep': 10}, # Change step to 10 valid_values={'off': 0, 'low': 25, 'medium': 50, 'high': 75, 'max': 100} ) def set_speed(self, value): print(f"Fan speed set to: {value}%") driver = AccessoryDriver(port=51826) driver.add_accessory(accessory=CustomFan(driver, 'Custom Fan')) signal.signal(signal.SIGTERM, driver.signal_handler) driver.start() ``` -------------------------------- ### View Generated Documentation Source: https://github.com/ikalchev/hap-python/blob/dev/docs/README.rst Fires up the default browser to open the main page of the previously generated HTML documentation. Run this command from the project directory. ```bash make htmlview ``` -------------------------------- ### Compile Documentation to HTML Source: https://github.com/ikalchev/hap-python/blob/dev/docs/README.rst Compiles the documentation into classic HTML output. The generated files will be located in the 'build/html' directory. Run this command from the project directory. ```bash make html ``` -------------------------------- ### Create and Navigate to Project Directory Source: https://github.com/ikalchev/hap-python/blob/dev/docs/source/intro/install.md Creates a new directory for your HAP-python project and changes the current directory into it. This is the first step in setting up your project. ```default ~ $ mkdir hk_project ~ $ cd hk_project ~/hk_project $ ``` -------------------------------- ### Create Custom Loader from Dictionaries Source: https://context7.com/ikalchev/hap-python/llms.txt Shows how to define custom characteristics and services using dictionaries and then create a custom Loader instance from them. This is useful for defining accessories with non-standard features. ```python custom_chars = { "CustomSensorValue": { "Format": "float", "Permissions": ["pr", "ev"], "UUID": "00000001-0000-1000-8000-AABBCCDDEEFF", "minValue": 0, "maxValue": 1000, } } custom_services = { "CustomSensor": { "UUID": "00000002-0000-1000-8000-AABBCCDDEEFF", "RequiredCharacteristics": ["CustomSensorValue"] } } custom_loader = Loader.from_dict(char_dict=custom_chars, serv_dict=custom_services) ``` -------------------------------- ### Implement Smart Thermostat with Callbacks Source: https://context7.com/ikalchev/hap-python/llms.txt Configure getter and setter callbacks for thermostat characteristics like CurrentTemperature and TargetTemperature. This allows dynamic value retrieval and reaction to client-initiated changes. ```python from pyhap.accessory import Accessory from pyhap.accessory_driver import AccessoryDriver from pyhap.const import CATEGORY_THERMOSTAT import signal class SmartThermostat(Accessory): """Thermostat with getter/setter callbacks for dynamic values.""" category = CATEGORY_THERMOSTAT def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._current_temp = 20.0 self._target_temp = 22.0 self._mode = 0 # 0=Off, 1=Heat, 2=Cool, 3=Auto serv = self.add_preload_service('Thermostat') # Getter callback: called when iOS reads the value serv.configure_char( 'CurrentTemperature', getter_callback=self.get_current_temp ) # Setter callback: called when iOS writes a value serv.configure_char( 'TargetTemperature', value=self._target_temp, setter_callback=self.set_target_temp, properties={'minValue': 16, 'maxValue': 30, 'minStep': 0.5} ) serv.configure_char( 'CurrentHeatingCoolingState', getter_callback=self.get_current_mode ) serv.configure_char( 'TargetHeatingCoolingState', value=self._mode, setter_callback=self.set_mode ) def get_current_temp(self): """Called when iOS requests current temperature.""" # Read from actual sensor here self._current_temp = self._read_temperature_sensor() return self._current_temp def _read_temperature_sensor(self): """Simulate reading from a temperature sensor.""" import random return round(random.uniform(18.0, 25.0), 1) def set_target_temp(self, value): """Called when user sets target temperature in Home app.""" self._target_temp = value print(f"Target temperature set to: {value}°C") def get_current_mode(self): """Return current heating/cooling state.""" return self._mode def set_mode(self, value): """Set heating/cooling mode.""" modes = {0: 'Off', 1: 'Heat', 2: 'Cool', 3: 'Auto'} self._mode = value print(f"Mode set to: {modes.get(value, 'Unknown')}") driver = AccessoryDriver(port=51826) driver.add_accessory(accessory=SmartThermostat(driver, 'Smart Thermostat')) signal.signal(signal.SIGTERM, driver.signal_handler) driver.start() ``` -------------------------------- ### Remove iid_manager and setup_id from Accessory/Bridge Init Source: https://github.com/ikalchev/hap-python/blob/dev/CHANGELOG.md The `iid_manager` and `setup_id` parameters have been removed from the `init` calls for `accessory` and `bridge`. Initialization parameters have been streamlined. ```python iid_manager and setup_id parameter from accessory and bridge init calls ``` -------------------------------- ### Configure HAP-python Systemd Service Source: https://github.com/ikalchev/hap-python/blob/dev/README.md This is the content for the HAP-python systemd service file. Ensure 'Wants = pigpiod.service' is removed if pigpiod is not used. The 'User' should be an unprivileged system user, and 'ExecStart' must point to the correct Python script path. ```ini [Unit] Description = HAP-python daemon Wants = pigpiod.service # Remove this if you don't depend on pigpiod After = local-fs.target network-online.target pigpiod.service [Service] User = lesserdaemon # It's a good idea to use some unprivileged system user # Script starting HAP-python, e.g. main.py # Be careful to set any paths you use, e.g. for persisting the state. ExecStart = /usr/bin/python3 /home/lesserdaemon/.hap-python/hap-python.py [Install] WantedBy = multi-user.target ``` -------------------------------- ### Create a Bridge with Multiple Accessories Source: https://context7.com/ikalchev/hap-python/llms.txt Use the `Bridge` class to group multiple accessories under a single HomeKit pairing. This allows for a larger number of accessories (up to 150) to be exposed through one pairing. Ensure the `AccessoryDriver` is configured with a port and a persistent state file. ```python import signal import random from pyhap.accessory import Accessory, Bridge from pyhap.accessory_driver import AccessoryDriver from pyhap.const import CATEGORY_FAN, CATEGORY_LIGHTBULB, CATEGORY_SENSOR class TemperatureSensor(Accessory): category = CATEGORY_SENSOR def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) serv = self.add_preload_service('TemperatureSensor') self.char_temp = serv.configure_char('CurrentTemperature') @Accessory.run_at_interval(5) async def run(self): self.char_temp.set_value(random.uniform(18.0, 26.0)) class LightBulb(Accessory): category = CATEGORY_LIGHTBULB def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) serv = self.add_preload_service('Lightbulb') self.char_on = serv.configure_char('On', setter_callback=self.set_bulb) def set_bulb(self, value): print(f"Light set to: {value}") class Fan(Accessory): category = CATEGORY_FAN def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Add optional characteristics to the service serv = self.add_preload_service('Fan', chars=['RotationSpeed', 'RotationDirection']) serv.configure_char('RotationSpeed', setter_callback=self.set_speed) serv.configure_char('RotationDirection', setter_callback=self.set_direction) def set_speed(self, value): print(f"Fan speed: {value}%") def set_direction(self, value): print(f"Fan direction: {'clockwise' if value == 0 else 'counter-clockwise'}") # Create bridge with multiple accessories driver = AccessoryDriver(port=51826, persist_file='bridge.state') bridge = Bridge(driver, 'My Smart Home') bridge.add_accessory(TemperatureSensor(driver, 'Living Room Temp')) bridge.add_accessory(TemperatureSensor(driver, 'Bedroom Temp')) bridge.add_accessory(LightBulb(driver, 'Kitchen Light')) bridge.add_accessory(Fan(driver, 'Ceiling Fan')) driver.add_accessory(accessory=bridge) signal.signal(signal.SIGTERM, driver.signal_handler) driver.start() ``` -------------------------------- ### Directory Structure for Subpackage Source: https://github.com/ikalchev/hap-python/blob/dev/pyhap/accessories/README.md Ensure this directory structure when creating a subpackage for HAP-python accessories. Note the absence of `__init__.py` in parent directories. ```text pyhap/ # NO __init__.py here !!! accessories/ # NO __init__.py here !!! bulb/ __init__.py ... the code for the bulb accessory ... ``` -------------------------------- ### Implement a TemperatureSensor Accessory in Python Source: https://github.com/ikalchev/hap-python/blob/dev/README.md Subclass Accessory to create a custom accessory. Use add_preload_service to add supported services and get_characteristic to access characteristics. Define setter_callback for characteristic value changes and use @Accessory.run_at_interval to schedule periodic tasks. The stop method is for cleanup. ```python from pyhap.accessory import Accessory, Category import pyhap.loader as loader import random class TemperatureSensor(Accessory): """Implementation of a mock temperature sensor accessory.""" category = Category.SENSOR # This is for the icon in the iOS Home app. def __init__(self, *args, **kwargs): """Here, we just store a reference to the current temperature characteristic and add a method that will be executed every time its value changes. """ # If overriding this method, be sure to call the super's implementation first. super().__init__(*args, **kwargs) # Add the services that this Accessory will support with add_preload_service here temp_service = self.add_preload_service('TemperatureSensor') self.temp_char = temp_service.get_characteristic('CurrentTemperature') # Having a callback is optional, but you can use it to add functionality. self.temp_char.setter_callback = self.temperature_changed def temperature_changed(self, value): """This will be called every time the value of the CurrentTemperature is changed. Use setter_callbacks to react to user actions, e.g. setting the lights On could fire some GPIO code to turn on a LED (see pyhap/accessories/LightBulb.py). """ print('Temperature changed to: ', value) @Accessory.run_at_interval(3) # Run this method every 3 seconds # The `run` method can be `async` as well def run(self): """We override this method to implement what the accessory will do when it is started. We set the current temperature to a random number. The decorator runs this method every 3 seconds. """ self.temp_char.set_value(random.randint(18, 26)) # The `stop` method can be `async` as well def stop(self): """We override this method to clean up any resources or perform final actions, as this is called by the AccessoryDriver when the Accessory is being stopped. """ print('Stopping accessory.') ``` -------------------------------- ### Garage Door Opener with State Synchronization Source: https://context7.com/ikalchev/hap-python/llms.txt Implements a garage door accessory that synchronizes current and target states, simulating a 3-second operation time. Includes basic obstruction detection logic. ```python from pyhap.accessory import Accessory from pyhap.accessory_driver import AccessoryDriver from pyhap.const import CATEGORY_GARAGE_DOOR_OPENER import signal import asyncio class GarageDoor(Accessory): """Garage door with synchronized state updates.""" category = CATEGORY_GARAGE_DOOR_OPENER # Door states: 0=Open, 1=Closed, 2=Opening, 3=Closing, 4=Stopped OPEN = 0 CLOSED = 1 OPENING = 2 CLOSING = 3 def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._current_state = self.CLOSED self._target_state = self.CLOSED serv = self.add_preload_service('GarageDoorOpener') self.char_current = serv.configure_char( 'CurrentDoorState', value=self._current_state ) self.char_target = serv.configure_char( 'TargetDoorState', value=self._target_state, setter_callback=self.set_target_state ) self.char_obstruction = serv.configure_char( 'ObstructionDetected', value=False ) def set_target_state(self, value): """Handle door open/close request from Home app.""" self._target_state = value if value == self.OPEN: print("Opening garage door...") self.char_current.set_value(self.OPENING) self.driver.add_job(self._simulate_door_operation, self.OPEN) else: print("Closing garage door...") self.char_current.set_value(self.CLOSING) self.driver.add_job(self._simulate_door_operation, self.CLOSED) async def _simulate_door_operation(self, final_state): """Simulate door taking time to open/close.""" await asyncio.sleep(3) # Door operation takes 3 seconds # Check for obstruction if self._check_obstruction(): self.char_obstruction.set_value(True) self.char_current.set_value(self.OPEN) return self.char_current.set_value(final_state) self._current_state = final_state action = "opened" if final_state == self.OPEN else "closed" print(f"Garage door {action}") def _check_obstruction(self): """Check for physical obstruction (implement with sensors).""" return False ``` -------------------------------- ### Load and Add Service/Chars to Accessory in HAP-Python Source: https://github.com/ikalchev/hap-python/blob/dev/CHANGELOG.md A helper method is provided to load a service and its characteristics and add them to an accessory. This streamlines the process of building complex accessories. ```python add it to an accessory ``` -------------------------------- ### Add Camera Accessory Support Source: https://github.com/ikalchev/hap-python/blob/dev/CHANGELOG.md Introduced support for the camera accessory, enabling new functionalities for camera devices within the HomeKit ecosystem. -------------------------------- ### Namespace Package for pyhap.accessories in HAP-Python Source: https://github.com/ikalchev/hap-python/blob/dev/CHANGELOG.md The `pyhap.accessories` module is now a native namespace package. Refer to `pyhap/accessories/README.md` for details on integrating third-party accessories. ```python pyhap/accessories/README.md ``` -------------------------------- ### Define Custom Accessory with Custom Loader Source: https://context7.com/ikalchev/hap-python/llms.txt Illustrates creating a custom accessory class that utilizes a custom loader. The accessory defines a custom service and characteristic, overriding the default loader before initializing the superclass. ```python class CustomSensorAccessory(Accessory): """Accessory using custom service definitions.""" def __init__(self, driver, name): # Override loader before calling super().__init__ driver.loader = custom_loader super().__init__(driver, name) # Use custom service serv = self.add_preload_service('CustomSensor') self.char_value = serv.configure_char('CustomSensorValue') ``` -------------------------------- ### Load Default HAP Loader Source: https://context7.com/ikalchev/hap-python/llms.txt Initializes the HAP loader to access Apple-defined services and characteristics. This is a prerequisite for defining accessories. ```python from pyhap.loader import Loader, get_loader from pyhap.service import Service from pyhap.characteristic import Characteristic from pyhap.accessory import Accessory from pyhap.accessory_driver import AccessoryDriver import signal from uuid import UUID # Get the default loader with Apple-defined types loader = get_loader() ``` -------------------------------- ### Create Characteristics and Services from Dictionary in HAP-Python Source: https://github.com/ikalchev/hap-python/blob/dev/CHANGELOG.md Characteristics and Services can be instantiated from a JSON dictionary using the `from_dict` class method. This allows for dynamic creation and configuration. ```python from_dict ``` -------------------------------- ### Move Pairing Variables to driver.state in HAP-Python Source: https://github.com/ikalchev/hap-python/blob/dev/CHANGELOG.md Variables related to pairing and static information have been moved to `driver.state`. This includes attributes and methods previously found in `accessory` and `accessory_driver`. ```python driver.state ``` ```python accessory: config_version, mac, setup_id, private_key, public_key and paired_clients as well as the add_paired_client and removed_paired_client methods ``` ```python accessory_driver: address and port ``` -------------------------------- ### Control LED via GPIO Source: https://context7.com/ikalchev/hap-python/llms.txt Controls an LED connected to a GPIO pin. Uncomment GPIO lines for actual hardware interaction. Includes cleanup on stop. ```python import RPi.GPIO as GPIO class GPIOLightBulb(Accessory): """Control an LED via GPIO pin.""" category = CATEGORY_LIGHTBULB def __init__(self, *args, pin=17, **kwargs): super().__init__(*args, **kwargs) self.pin = pin # GPIO setup (uncomment for real usage) # GPIO.setmode(GPIO.BCM) # GPIO.setup(self.pin, GPIO.OUT) serv = self.add_preload_service('Lightbulb') self.char_on = serv.configure_char('On', setter_callback=self.set_led) def set_led(self, value): """Turn LED on or off.""" print(f"Setting GPIO {self.pin} to {"HIGH" if value else "LOW"}") # GPIO.output(self.pin, GPIO.HIGH if value else GPIO.LOW) async def stop(self): """Clean up GPIO on stop.""" # GPIO.cleanup(self.pin) print(f"Cleaned up GPIO {self.pin}") ``` -------------------------------- ### Configure Characteristic Shortcut in HAP-Python Source: https://github.com/ikalchev/hap-python/blob/dev/CHANGELOG.md The `service.configure_char` method provides a shortcut for configuring characteristics within a service. This simplifies the process of setting up accessory characteristics. ```python service.configure_char ``` -------------------------------- ### Systemd Service Configuration for HAP-Python Source: https://context7.com/ikalchev/hap-python/llms.txt Provides a systemd service unit file configuration to run a HAP-Python application as a background service on Linux systems. It specifies user, working directory, and restart behavior. ```ini [Unit] Description=HAP-python HomeKit Accessory After=network-online.target Wants=network-online.target [Service] Type=simple User=pi WorkingDirectory=/home/pi/hap-python ExecStart=/usr/bin/python3 /home/pi/hap-python/main.py Restart=on-failure RestartSec=10 [Install] WantedBy=multi-user.target ``` -------------------------------- ### Service Callbacks for Coordinated Updates Source: https://context7.com/ikalchev/hap-python/llms.txt Implement service-level callbacks to handle multiple characteristic changes within a single request. This is useful for tightly coupled characteristics, such as 'On' and 'Brightness' for a lightbulb, ensuring coordinated updates. ```python from pyhap.accessory import Accessory from pyhap.accessory_driver import AccessoryDriver from pyhap.const import CATEGORY_LIGHTBULB import signal class DimmableLight(Accessory): """Light with coordinated On/Brightness updates via service callback.""" category = CATEGORY_LIGHTBULB def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._on = False self._brightness = 100 # Add Lightbulb service with Brightness characteristic serv_light = self.add_preload_service('Lightbulb', chars=['Brightness']) self.char_on = serv_light.configure_char('On', value=self._on) self.char_brightness = serv_light.configure_char('Brightness', value=self._brightness) # Service callback receives all changes at once serv_light.setter_callback = self._set_light_state def _set_light_state(self, char_values): """Handle coordinated updates to On and Brightness.""" # char_values is dict like: {"On": True, "Brightness": 75} if "On" in char_values: self._on = char_values["On"] print(f"Light power: {'ON' if self._on else 'OFF'}") if "Brightness" in char_values: self._brightness = char_values["Brightness"] print(f"Light brightness: {self._brightness}%") # Apply combined state to hardware if self._on: self._apply_brightness(self._brightness) else: self._apply_brightness(0) def _apply_brightness(self, level): """Apply brightness to actual hardware (GPIO PWM, etc.).""" print(f"Applying brightness level: {level}%") driver = AccessoryDriver(port=51826) driver.add_accessory(accessory=DimmableLight(driver, 'Dimmable Light')) signal.signal(signal.SIGTERM, driver.signal_handler) driver.start() ``` -------------------------------- ### Run Accessory with Event Loop in HAP-Python Source: https://github.com/ikalchev/hap-python/blob/dev/CHANGELOG.md The `Accessory.run` method is now executed via an event loop. You can inherit from `Accessory` (run in a thread) or `AsyncAccessory` (run in the event loop) to manage execution. ```python Accessory.run method is now called through an event loop ``` ```python inherit from AsyncAccessory and implement async def run ``` -------------------------------- ### Run Accessory Repeatedly in HAP-Python Source: https://github.com/ikalchev/hap-python/blob/dev/CHANGELOG.md Use `Accessory.repeat(time)` or `AsyncAccessory.repeat(time)` to run the driver's `run` method repeatedly until the driver is stopped. This is useful for continuous operation. ```python Accessory.repeat(time) ``` ```python AsyncAccessory.repeat(time) ``` -------------------------------- ### State Helper Class for Pairing Information in HAP-Python Source: https://github.com/ikalchev/hap-python/blob/dev/CHANGELOG.md A `State` helper class has been introduced to manage pairing-related and semi-static information. This centralizes state management. ```python State helper class ``` -------------------------------- ### Define a Custom Outlet Accessory Source: https://context7.com/ikalchev/hap-python/llms.txt Creates a custom accessory class 'MyOutlet' that inherits from Accessory and sets its category to CATEGORY_OUTLET. It configures an 'Outlet' service with 'On' and 'OutletInUse' characteristics. ```python from pyhap.accessory import Accessory from pyhap.accessory_driver import AccessoryDriver class MyOutlet(Accessory): category = CATEGORY_OUTLET # Shows outlet icon in Home app def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) serv = self.add_preload_service('Outlet') serv.configure_char('On', setter_callback=lambda v: print(f"Outlet: {v}")) serv.configure_char('OutletInUse', value=True) ``` -------------------------------- ### Remove Accessory.create Method in HAP-Python Source: https://github.com/ikalchev/hap-python/blob/dev/CHANGELOG.md The unused `accessory.create` method has been removed. This simplifies the accessory API. ```python accessory.create ``` -------------------------------- ### Assign Pincode as Driver Parameter in HAP-Python Source: https://github.com/ikalchev/hap-python/blob/dev/CHANGELOG.md The `pincode` can now be assigned directly as a parameter for the driver. This simplifies the driver initialization process. ```python pincode can now be assigned as a parameter for the driver ``` -------------------------------- ### Configure Passwordless Shutdown for HAP-user Source: https://github.com/ikalchev/hap-python/blob/dev/README.md This command adds an entry to the sudoers file, allowing the specified HAP user to execute the shutdown command without a password. Replace '' with the actual username running HAP-python. ```sh $ sudo visudo # and add the line: " ALL=NOPASSWD: /sbin/shutdown". ``` -------------------------------- ### Disable Accessory Advertisement Updates Source: https://github.com/ikalchev/hap-python/blob/dev/CHANGELOG.md Set `driver.safe_mode = True` before `driver.start` to disable `update_advertisement` calls for pairing and unpairing. A restart is necessary after unpairing. ```python driver.safe_mode = True ``` -------------------------------- ### Run Static Code Checks Locally in HAP-Python Source: https://github.com/ikalchev/hap-python/blob/dev/CHANGELOG.md To run static code checks locally, use the commands `tox -e lint` for linting and `tox -e pylint` for Pylint checks. These help maintain code quality. ```python tox -e lint ``` ```python tox -e pylint ``` -------------------------------- ### Accessory Structure Change in HAP-Python Source: https://github.com/ikalchev/hap-python/blob/dev/CHANGELOG.md All accessories have been moved from `pyhap.accessories` to a new `accessories` folder at the project root. This reorganizes the library structure. ```python pyhap.accessories ``` -------------------------------- ### Deprecated Accessory and Bridge Parameters in HAP-Python Source: https://github.com/ikalchev/hap-python/blob/dev/CHANGELOG.md The `mac` and `pincode` parameters for `accessory` and `bridge` are now deprecated. Use alternative methods for configuration as indicated by newer versions. ```python mac and pincode are now deprecated ``` -------------------------------- ### Replace Accessory.config_changed with driver.config_changed in HAP-Python Source: https://github.com/ikalchev/hap-python/blob/dev/CHANGELOG.md The `Accessory.config_changed` method is deprecated. Use `driver.config_changed` instead for updating accessory configurations. ```python Accessory.config_changed, use driver.config_changed instead ``` -------------------------------- ### Read Physical Button State Source: https://context7.com/ikalchev/hap-python/llms.txt Reads the state of a physical button connected to a GPIO pin and updates HomeKit. Includes a simulated button press for testing. ```python class GPIOSwitch(Accessory): """Read a physical button state.""" category = CATEGORY_SWITCH def __init__(self, *args, pin=27, **kwargs): super().__init__(*args, **kwargs) self.pin = pin # GPIO.setmode(GPIO.BCM) # GPIO.setup(self.pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) serv = self.add_preload_service('Switch') self.char_on = serv.configure_char('On') @Accessory.run_at_interval(0.5) async def run(self): """Poll button state and update HomeKit.""" # button_pressed = not GPIO.input(self.pin) button_pressed = False # Simulated current = self.char_on.value if button_pressed != current: self.char_on.set_value(button_pressed) ``` -------------------------------- ### AccessoryInformation Service IID in HAP-Python Source: https://github.com/ikalchev/hap-python/blob/dev/CHANGELOG.md The `AccessoryInformation` service is now guaranteed to have an `iid` of 1. This ensures consistent identification of this essential service. ```python AccessoryInformation service will always have the iid=1 ``` -------------------------------- ### Debug Logs for Characteristic Updates in HAP-Python Source: https://github.com/ikalchev/hap-python/blob/dev/CHANGELOG.md Debug logs have been added for `char.set_value` and `char.client_update_value` operations. These logs help in tracing value changes and client interactions. ```python char.set_value ``` ```python char.client_update_value ``` -------------------------------- ### Typo Fix in accessory_driver.stop Log Message Source: https://github.com/ikalchev/hap-python/blob/dev/CHANGELOG.md A typo in the log message within the `accessory_driver.stop` method has been corrected. This ensures accurate logging. ```python accessory_driver.stop ``` -------------------------------- ### Uninstall HAP-python Source: https://github.com/ikalchev/hap-python/blob/dev/README.md Removes HAP-python from your Python packages. ```sh pip3 uninstall HAP-python ``` -------------------------------- ### Replace Accessory.paired with driver.state.paired in HAP-Python Source: https://github.com/ikalchev/hap-python/blob/dev/CHANGELOG.md The `Accessory.paired` attribute is deprecated. Access the pairing status through `driver.state.paired` for current information. ```python Accessory.paired, use driver.state.paired instead ``` -------------------------------- ### Override AccessoryInformation Service in HAP-Python Source: https://github.com/ikalchev/hap-python/blob/dev/CHANGELOG.md Helper methods are available to easily override the default `AccessoryInformation` service. This allows for customization of accessory identification details. ```python AccessoryInformation ``` -------------------------------- ### Getter Callback for Characteristics in HAP-Python Source: https://github.com/ikalchev/hap-python/blob/dev/CHANGELOG.md A `getter_callback` has been added to Characteristics. This allows for dynamic retrieval of characteristic values when they are accessed. ```python getter_callback to Characteristics ```