跳转到主要内容

Python中的HomeKit配件协议实现

项目描述

PyPI version Build Status codecov Python Versions Documentation Status Downloads

ha-HAP-python

这是HAP-python的一个分支,用于在Home Assistant中提供对HAP-python的修复或故障排除。

Python 3中的HomeKit配件协议实现。使用此项目,您可以将自己的智能设备集成到iOS Home应用中。由于Siri与Home应用集成,您可以直接开始语音控制您的配件。

主要功能

  • 摄像头 - HAP-python从2.3.0版本开始支持摄像头配件!
  • asyncio支持 - 您可以在事件循环中运行各种任务或配件。
  • 内置对Apple定义的服务支持 - 在资源文件夹中查看。
  • 通过扫描二维码即可安全配对。
  • 与智能家居框架Home Assistant集成。

该项目是为树莓派开发的,但它应该可以在其他平台上运行。为了启动,你可以打开 main.pybusy_home.py,在那里你会找到一些虚拟配件。只需运行其中一个,例如 python3 busy_home.py,然后你可以在“家居”应用中添加它(确保在同一网络中)。通过按Ctrl+C停止它。

配件文件夹中有示例配件以及与真实产品的集成。在camera_main.py中查看如何配置你的相机。

目录

  1. API
  2. 安装
  3. 设置相机
  4. 开机运行(并切换到关闭设备)
  5. 注意

安装

从版本3.5.1开始,HAP-python不再支持低于3.6的Python版本,因为我们正在转向asyncio。如果你的平台默认没有兼容的Python,你可以手动安装它,或者只使用HAP-python的旧版本。

作为先决条件,你需要安装Avahi/Bonjour(由于zeroconf包)。在树莓派上,你可以使用以下命令获取它

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

avahi-utils也可能符合要求。然后,你可以使用pip3安装(安装时可能需要sudo--user

$ pip3 install HAP-python[QRCode]

这将把HAP-python安装到你的Python包中,这样你就可以将其导入为pyhap。要卸载,只需执行

$ pip3 uninstall HAP-python

API

使用HAP-python的典型流程是从实现配件开始。这是通过从Accessory派生并放置一些细节来完成的(见下文)。之后,你将配件交给配件驱动器来管理。这将负责在本地网络上广告它,设置HAP服务器并运行配件。查看main.py以快速入门。

from pyhap.accessory import Accessory, Category
import pyhap.loader as loader

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)

    @Acessory.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.')

服务回调

当你处理如“开启”和“亮度”这样的紧密耦合特性时,你可能需要使用服务回调来接收单个请求中的所有更改。

使用特性回调,你现在知道在“开启”之后,“亮度”特性即将被处理,最终可能会将灯泡设置为100%,然后将其调暗到预期水平。

from pyhap.accessory import Accessory
from pyhap.const import Category
import pyhap.loader as loader

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"])

    @Acessory.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.')

设置相机

Camera配件实现了HomeKit协议,用于协商流设置,如图片宽度和高度、音频通道数量等。启动视频和/或音频流非常特定于平台。因此,你需要确定你的相机支持哪些视频和音频设置,并将它们设置在传递给Camera配件的options参数中。请参考Camera构造函数的文档,以了解你需要指定的设置。

默认情况下,HAP-python将在流应该启动时执行带有协商参数的ffmpeg命令,并在流应该停止时terminate启动的过程(参见默认值:Camera.FFMPEG_CMD)。如果默认命令不受支持或格式不正确,流可能失败。

对于这些情况,HAP-python有钩子,你可以插入自己的命令或实现启动或停止流的逻辑。有两种选择

  1. 传递自己的命令,在流应该启动时执行。

    你将命令作为值传递给Camera配件构造函数的options参数中的start_stream_cmd键。该命令使用协商的流配置参数进行格式化。例如,如果协商的宽度为640,你传递foo start -width {width},则命令将格式化为foo start -width 640

    协商的流配置参数的完整列表可以在Camera.start方法的文档中找到。

  2. 实现自己的逻辑来启动、停止和重新配置流。

    如果您需要更灵活地管理流,您可以直接实现 Camera 方法的 startstopreconfigure。每个方法将在分别启动、停止或重新配置流时被调用。启动和重新配置方法将提供协商的流配置参数。

    请查看这些方法的文档以获取更多信息。

最后,如果您可以从相机获取快照,您可能需要实现 Camera.snapshot 方法。默认情况下,它提供了一个库存照片。

在启动时运行

这是在 Raspberry Pi 上让 HAP-python 在启动时运行的一个快速方法。建议在 raspi-config 中打开“等待网络”。如果这变得不可靠,请参阅 这里

将以下内容复制到 /etc/systemd/system/HAP-python.service(需要sudo)。

[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

通过以下方式测试一切是否正常:

> sudo systemctl start HAP-python
> systemctl status HAP-python
> sudo journalctl -u HAP-python  # to see the output of the start up script.
> sudo systemctl stop HAP-python

要启用或禁用在启动时运行,请执行

> sudo systemctl enable HAP-python
> sudo systemctl disable HAP-python

关机开关

如果您在 Raspberry Pi 上运行 HAP-python,您可能想在您的家中添加一个 关机开关。这是一个开关配件,当触发时,将执行 sudo shutdown -h now,即关闭并停止 Pi。这允许您安全地拔掉它。

要使上述功能正常工作,您需要为运行 HAP-python 的用户启用无密码的 /sbin/shutdown。例如,执行

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

注意

一些 HAP 知识来自 KhaosT 的 HAP-NodeJS

我不知道有任何错误,但我非常确信确实存在。如果您发现任何错误,请报告,我将尽力修复它们。

建议总是受欢迎的。

祝您玩得开心!

项目详情


下载文件

下载适用于您平台的文件。如果您不确定要选择哪个,请了解有关 安装包 的更多信息。

源代码发行版

ha-HAP-python-4.5.2.tar.gz (314.6 kB 查看哈希值)

上传时间 源代码

构建发行版

ha_HAP_python-4.5.2-py3-none-any.whl (261.3 kB 查看哈希值)

上传时间 Python 3

支持者

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误日志 StatusPage StatusPage 状态页面