在Home Assistant中实现ZHA特例的Zigpy库
项目描述
ZHA设备处理器,适用于Home Assistant
ZHA设备处理器是Zigpy的自定义特例实现,Zigpy是提供Zigbee支持的库,用于Home Assistant中的ZHA组件。
ZHA设备处理器通过解析Zigbee设备的自定义消息来处理制造商对ZCL规范的偏离和异常,从而填补了制造商偏离或不完全符合Zigbee联盟制定的标准规范时产生的功能差距。偏离或不符合Zigbee联盟制定的标准规范的可能需要开发自定义的ZHA设备处理器(ZHA自定义特例处理器实现),以便它们的所有功能都能在Home Assistant的ZHA组件中正常工作。
作为ZHA设备处理器实现的zigpy自定义特例与SmartThings Classics平台连接的设备处理器以及Zigbee2mqtt使用的Zigbee-Herdsman转换器(之前称为Zigbee-Shepherd转换器)类似,意味着它们是物理设备的虚拟表示,提供了这些平台之间现有集成未提供的额外功能。有关详细信息,请参阅设备特定信息。
如何贡献
简介
ZHA设备处理器及其提供的特例允许Zigpy、ZHA和Home Assistant与不符合标准的Zigbee设备一起工作。如果你正在阅读本指南,可能你有一个设备无法按预期工作。这可能由多种原因造成,但在这篇指南中,我们将涵盖设备制造商以非规范兼容的方式提供设备功能的情况。
这些规范是什么
参考来自连接性标准联盟(又称“CSA-IOT”,曾称“Zigbee联盟”)的官方Zigbee规范文档
- Zigbee集群库规范
- Zigbee协议规范(也称为“Zigbee Pro”规范)
- Zigbee设备规范
- Zigbee绿色电源(ZGP“绿色电源”配置文件)规范
- Zigbee智能能源(ZSE/ Zigbee SE“智能能源”配置文件)规范
- Zigbee智能能源标准1.4
- ZigBee智能能源标准(v1.2a)
此外,请参阅以下第三方和制造商特定文档
在人类术语中,什么是设备
设备是您希望连接到Zigbee网络的物理对象:灯泡、开关、传感器等。主机应用,在本例中为Zigpy,需要了解如何与设备交互,因此有标准定义了应用和设备如何通信。设备的功能由几个描述符描述,而设备本身包含端点,而端点包含集群。端点包含两种类型的集群
- in_clusters - 在ZCL术语中是“服务器”集群。这些集群控制设备,例如智能插头或灯泡将有一个
on_off
服务器集群。《in_clusters》也是那些发送属性报告的,或者您可以从in_cluster中读取属性。 - out_clusters - 是“客户端”集群。这些集群控制其他设备,因为“客户端”集群向“服务器”集群发送命令。例如,一个开/关遥控器将有一个
on_off
客户端集群,并生成集群命令并将这些命令发送到其他设备。Zigpy需要了解所有这些元素才能正确地与设备一起工作。
端点
端点实际上是功能分组。例如,典型的Zigbee灯泡将有一个用于灯的单个端点。多联开关可能每个开关都有一个端点,这样它们都可以单独控制。每个端点都有由集群表示的几个功能。
集群
集群是包含单个功能信息(属性和命令)的对象。可以打开和关闭开关,可能还有能源监控,可能还有将每个开关添加到单个组或场景的能力等。这些功能中的每一个都属于一个集群。
描述符
对于Zigpy和Quirks的目的,我们将关注两个描述符:节点描述符和简单描述符。
节点描述符
节点描述向Zigpy解释了一些基本设备属性。制造商代码和电源类型是我们通常关心的。在大多数情况下,你不必担心这个问题,但了解为什么它存在,以防你在查看现有奇点时遇到它。以下是一个示例:<Optional byte1=2 byte2=64 mac_capability_flags=128 manufacturer_code=4174 maximum_buffer_size=82 maximum_incoming_transfer_size=82 server_mask=0 maximum_outgoing_transfer_size=82 descriptor_capability_field=0>
简单描述符
简单描述符是对Zigbee设备端点的描述,负责解释端点的功能。它包含配置文件ID、设备类型和簇集合。配置文件ID告诉应用程序使用哪些Zigbee规则集。最常见的配置文件将是用于家庭自动化的260(0x0104)。设备类型告诉应用程序这是哪种逻辑类型的设备,例如:开关灯、调光灯等。簇解释了端点上存在哪些功能类型。以下是一个示例:<SimpleDescriptor endpoint=1 profile=260 device_type=1026 device_version=0 input_clusters=[0, 1, 3, 32, 1026, 1280, 2821] output_clusters=[25]>
什么是奇点
从人类的角度来看,你可以将奇点比作谷歌翻译。我知道这个比较很奇怪,但让我们深入探讨一下。你可能只会说一种语言,但有一篇用另一种语言写的有趣文章你真的很想读。谷歌翻译将原始文章转换成你理解的格式(语言)。奇点是一个文件,它将设备功能从制造商选择的格式转换为Zigpy和ZHA理解的格式。奇点的主要目的是作为翻译者。奇点包含几个部分
- 签名 - 用于识别并应用正确的奇点
- 替换 - 允许Zigpy和ZHA正确地与设备一起工作
- device_automation_triggers - 允许家庭助手设备自动化引擎和用户与设备交互
签名
奇点的签名标识了设备,就像制造商实施的那样。你可以将其视为指纹或设备的dna。签名是我们用来识别设备的东西。如果签名中的任何部分与设备在发现过程中返回的内容不匹配,奇点将不匹配,因此它将不会被应用。签名由几个部分组成
models_info
endpoints
模型信息告诉应用程序哪些设备应使用此特定奇点。端点是我们在设备上提到的简单描述符,完全按照它们在设备上的样子。 endpoints
是一个字典,其中键是端点的ID,值是一个具有以下属性的对象: profile_id
、device_type
、input_clusters
和 output_clusters
。创建签名元素通常是转录设备提供的内容的工作。以下是一个示例
signature = {
MODELS_INFO: [(LUMI, "lumi.plug.maus01")],
ENDPOINTS: {
# <SimpleDescriptor endpoint=1 profile=260 device_type=81
# device_version=1
# input_clusters=[0, 4, 3, 6, 16, 5, 10, 1, 2, 2820]
# output_clusters=[25, 10]>
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
INPUT_CLUSTERS: [
Basic.cluster_id,
PowerConfiguration.cluster_id,
DeviceTemperature.cluster_id,
Groups.cluster_id,
Identify.cluster_id,
OnOff.cluster_id,
Scenes.cluster_id,
BinaryOutput.cluster_id,
Time.cluster_id,
ElectricalMeasurement.cluster_id,
],
OUTPUT_CLUSTERS: [Ota.cluster_id, Time.cluster_id],
},
},
}
替换
奇点的替换是我们希望设备成为的样子。记住,我们说过奇点就像谷歌翻译……你可以把替换想象成谷歌翻译的输出。替换字典是Zigpy和ZHA实际用于与设备交互的内容。 replacement
的结构与签名相同,但有2个关键区别:models_info
通常被省略,还有一个额外的元素 skip_configuration
,它指示应用程序在必要时跳过配置。一些制造商没有正确实现规范,因此设备预先配置,因此配置调用失败(例如非Zigbee 3.0的小米设备)。通常,你不应该添加 skip_configuration
。
以下是一个示例
replacement = {
SKIP_CONFIGURATION: True,
ENDPOINTS: {
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
INPUT_CLUSTERS: [
BasicCluster,
PowerConfiguration.cluster_id,
DeviceTemperature.cluster_id,
Groups.cluster_id,
Identify.cluster_id,
OnOff.cluster_id,
Scenes.cluster_id,
BinaryOutput.cluster_id,
Time.cluster_id,
ElectricalMeasurementCluster,
],
OUTPUT_CLUSTERS: [Ota.cluster_id, Time.cluster_id],
},
},
}
device_automation_triggers
设备自动化触发器本质上是对设备在HA中引发的事件的表示。它们允许用户在UI中使用操作而不是使用原始事件。
构建一个特性
现在我们已经把那部分处理好了,我们可以专注于手头的任务:让我们的设备使用Zigpy和ZHA按照应有的方式工作。因为这个设备出厂时不能正常工作,所以我们必须为它编写一个特性。首先,让我们看看这个特性完成后的样子
class Plug(XiaomiCustomDevice):
"""lumi.plug.maus01 plug."""
def __init__(self, *args, **kwargs):
"""Init."""
self.voltage_bus = Bus()
self.consumption_bus = Bus()
self.power_bus = Bus()
super().__init__(*args, **kwargs)
signature = {
MODELS_INFO: [(LUMI, "lumi.plug.maus01")],
ENDPOINTS: {
# <SimpleDescriptor endpoint=1 profile=260 device_type=81
# device_version=1
# input_clusters=[0, 4, 3, 6, 16, 5, 10, 1, 2, 2820]
# output_clusters=[25, 10]>
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
INPUT_CLUSTERS: [
Basic.cluster_id,
PowerConfiguration.cluster_id,
DeviceTemperature.cluster_id,
Groups.cluster_id,
Identify.cluster_id,
OnOff.cluster_id,
Scenes.cluster_id,
BinaryOutput.cluster_id,
Time.cluster_id,
ElectricalMeasurement.cluster_id,
],
OUTPUT_CLUSTERS: [Ota.cluster_id, Time.cluster_id],
},
# <SimpleDescriptor endpoint=2 profile=260 device_type=9
# device_version=1
# input_clusters=[12]
# output_clusters=[12, 4]>
2: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.MAIN_POWER_OUTLET,
INPUT_CLUSTERS: [AnalogInput.cluster_id],
OUTPUT_CLUSTERS: [AnalogInput.cluster_id, Groups.cluster_id],
},
# <SimpleDescriptor endpoint=3 profile=260 device_type=83
# device_version=1
# input_clusters=[12]
# output_clusters=[12]>
3: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.METER_INTERFACE,
INPUT_CLUSTERS: [AnalogInput.cluster_id],
OUTPUT_CLUSTERS: [AnalogInput.cluster_id],
},
# <SimpleDescriptor endpoint=100 profile=260 device_type=263
# device_version=2
# input_clusters=[15]
# output_clusters=[15, 4]>
100: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.OCCUPANCY_SENSOR,
INPUT_CLUSTERS: [BinaryInput.cluster_id],
OUTPUT_CLUSTERS: [BinaryInput.cluster_id, Groups.cluster_id],
},
},
}
replacement = {
SKIP_CONFIGURATION: True,
ENDPOINTS: {
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
INPUT_CLUSTERS: [
BasicCluster,
PowerConfiguration.cluster_id,
DeviceTemperature.cluster_id,
Groups.cluster_id,
Identify.cluster_id,
OnOff.cluster_id,
Scenes.cluster_id,
BinaryOutput.cluster_id,
Time.cluster_id,
ElectricalMeasurementCluster,
],
OUTPUT_CLUSTERS: [Ota.cluster_id, Time.cluster_id],
},
2: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.MAIN_POWER_OUTLET,
INPUT_CLUSTERS: [AnalogInputCluster],
OUTPUT_CLUSTERS: [AnalogInput.cluster_id, Groups.cluster_id],
},
3: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.METER_INTERFACE,
INPUT_CLUSTERS: [AnalogInput.cluster_id],
OUTPUT_CLUSTERS: [AnalogInput.cluster_id],
},
100: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.OCCUPANCY_SENSOR,
INPUT_CLUSTERS: [BinaryInput.cluster_id],
OUTPUT_CLUSTERS: [BinaryInput.cluster_id, Groups.cluster_id],
},
},
}
这个特性是为美国版本的小米插线板设计的。小米因不遵循Zigbee规范而臭名昭著,它们的大部分非Zigbee 3.0设备都需要一个特性才能正确工作。在这种情况下,我们正在纠正《电气测量》集群的读取。小米决定在《模拟输入》集群上报告该集群的值。为了解决这个问题,我们将创建一个自定义集群来替换《模拟输入》和《电气测量》集群。我们将从《模拟输入》集群报告的值发布到《电气测量》集群。这样做可以让设备像小米一开始就实施了这一点一样工作。这就是上面提到的谷歌翻译类比中所说的翻译行为。
首先,所有特性中的设备定义都必须扩展CustomDevice
或其派生类,而你定义的所有集群都必须扩展CustomCluster
或其派生类。如果您想在我们这里发送CustomCluster
定义之间的消息,您需要创建通信通道。我们通过在我们的CustomDevice
实现中添加Bus
实例来实现这一点。Bus
是一个用于特定目的的实用程序类,将其添加到设备实现中可以确保您定义的所有集群都可以访问Bus
,以便它们可以相互通信。
class Plug(XiaomiCustomDevice):
"""lumi.plug.maus01 plug."""
def __init__(self, *args, **kwargs):
"""Init."""
self.voltage_bus = Bus()
self.consumption_bus = Bus()
self.power_bus = Bus()
super().__init__(*args, **kwargs)
您可以看到我们扩展了XiaomiCustomDevice
,它是小米设备共享的CustomDevice
的派生类。您还可以看到我们添加了一些Bus
实例,这样我们就可以在CustomCluster
定义之间传递消息。为了明确,这并不总是必要的。特性可以用来更改现有集群上的数据格式,向集群添加制造商特定的属性或命令等。在这些情况下,您只需创建CustomCluster
的派生类并添加您的逻辑。这是一个更高级的例子,用于说明可能做到的事情。
以下是自定义集群定义
class AnalogInputCluster(CustomCluster, AnalogInput):
"""Analog input cluster, only used to relay power consumption information to ElectricalMeasurementCluster."""
cluster_id = AnalogInput.cluster_id
def __init__(self, *args, **kwargs):
"""Init."""
self._current_state = {}
super().__init__(*args, **kwargs)
def _update_attribute(self, attrid, value):
super()._update_attribute(attrid, value)
if value is not None and value >= 0:
self.endpoint.device.power_bus.listener_event(POWER_REPORTED, value)
class ElectricalMeasurementCluster(LocalDataCluster, ElectricalMeasurement):
"""Electrical measurement cluster to receive reports that are sent to the basic cluster."""
cluster_id = ElectricalMeasurement.cluster_id
POWER_ID = 0x050B
VOLTAGE_ID = 0x0500
CONSUMPTION_ID = 0x0304
def __init__(self, *args, **kwargs):
"""Init."""
super().__init__(*args, **kwargs)
self.endpoint.device.voltage_bus.add_listener(self)
self.endpoint.device.consumption_bus.add_listener(self)
self.endpoint.device.power_bus.add_listener(self)
def power_reported(self, value):
"""Power reported."""
self._update_attribute(self.POWER_ID, value)
def voltage_reported(self, value):
"""Voltage reported."""
self._update_attribute(self.VOLTAGE_ID, value)
def consumption_reported(self, value):
"""Consumption reported."""
self._update_attribute(self.CONSUMPTION_ID, value)
在《模拟输入》集群中,我们重写了_update_attribute
方法,这样我们就可以访问设备发送报告时集群接收到的数据,并通过总线上的事件将数据发送到《电气测量》集群。这是执行大量工作的那一行
self.endpoint.device.power_bus.listener_event(POWER_REPORTED, value)
然后在《电气测量》集群中,我们需要订阅这些事件并处理它们。这是我们如何订阅我们的自定义事件的方式
self.endpoint.device.power_bus.add_listener(self)
并且这个方法(方法名必须与您发布的事件名完全匹配)
def power_reported(self, value):
"""Power reported."""
self._update_attribute(self.POWER_ID, value)
接收事件并处理在正确的zigbee集群上更新属性。如您所见,为了实现我们的目标,这里实际上没有多少事情要做。
一旦我们创建了我们的CustomCluster
实现,我们必须告诉CustomDevice
实现使用它们。我们在特性定义中的replacement
字典中这样做。首先,复制signature
字典并从中删除models_info
。然后,我们将要覆盖的集群id替换为我们创建的自定义CustomCluster
实现的名称。结果看起来像这样
replacement = {
SKIP_CONFIGURATION: True,
ENDPOINTS: {
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
INPUT_CLUSTERS: [
BasicCluster,
PowerConfiguration.cluster_id,
DeviceTemperature.cluster_id,
Groups.cluster_id,
Identify.cluster_id,
OnOff.cluster_id,
Scenes.cluster_id,
BinaryOutput.cluster_id,
Time.cluster_id,
ElectricalMeasurementCluster,
],
OUTPUT_CLUSTERS: [Ota.cluster_id, Time.cluster_id],
},
2: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.MAIN_POWER_OUTLET,
INPUT_CLUSTERS: [AnalogInputCluster],
OUTPUT_CLUSTERS: [AnalogInput.cluster_id, Groups.cluster_id],
},
3: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.METER_INTERFACE,
INPUT_CLUSTERS: [AnalogInput.cluster_id],
OUTPUT_CLUSTERS: [AnalogInput.cluster_id],
},
100: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.OCCUPANCY_SENSOR,
INPUT_CLUSTERS: [BinaryInput.cluster_id],
OUTPUT_CLUSTERS: [BinaryInput.cluster_id, Groups.cluster_id],
},
您可以看到,我们将端点1中的ElectricalMeasurement.cluster_id
从signature
字典替换为我们创建的簇名称:ElectricalMeasurementCluster
,在端点2中,我们将AnalogInput.cluster_id
替换为我们为其创建的实现:AnalogInputCluster
。这指示Zigpy使用这些CustomCluster
派生版本代替这些簇的正常簇定义,这就是为什么这个奇特的这部分被称为replacement
。
现在让我们将这些放在一起。如果您检查上面的设备定义,您将看到我们已经定义了我们的自定义设备,我们定义了signature
字典,其中我们记录了设备加入网络时获得的SimpleDescriptor
输出,并在其中定义了replacement
字典,其中我们用我们创建的CustomCluster
实现交换了要替换的簇的簇ID。
贡献指南
-
所有代码都使用黑色格式。CI中运行的检查格式脚本来确保代码满足此要求,并使用black正确格式化。有关在许多编辑器中安装black的说明,请参阅此处:https://github.com/psf/black#editor-integration
-
捕获设备每个端点的SimpleDescriptor日志条目。这些日志条目可以在设备加入后找到的HA日志中,它们看起来像这样:
<SimpleDescriptor endpoint=1 profile=260 device_type=1026 device_version=0 input_clusters=[0, 1, 3, 32, 1026, 1280, 2821] output_clusters=[25]>
。如果您想花费时间查询表并重构日志条目,您还可以从zigbee.db中获取这些信息。我发现只需移除并重新加入设备更容易。ZHA实体ID在大多数情况下是稳定的,因此不应该破坏您已配置的内容。这些需要与设备报告的完全匹配,否则Zigpy在设备加入时不会匹配它们,并且处理程序将不会用于该设备。您还可以从HA中设备的设备屏幕获取此信息。点击Zigbee Device Signature
按钮将启动一个包含创建奇克所需所有信息的对话框。 -
所有自定义设备定义都必须扩展
CustomDevice
或其派生版本 -
所有自定义簇定义都必须扩展
CustomCluster
或其派生版本 -
对所有属性值使用常量,并根据需要引用Zigpy / HA中的适当标签
-
将现有处理程序用作指南。signature和replacement字典是必需的。在定义端点的定义上方包含每个端点的SimpleDescriptor条目,格式如下
# <SimpleDescriptor endpoint=1 profile=260 device_type=1026 # device_version=0 # input_clusters=[0, 1, 3, 32, 1026, 1280, 2821] # output_clusters=[25]>
device_automation_triggers
如何工作
设备自动化触发器本质上是在HA中设备触发的事件的表示。它们允许用户在UI中使用操作,而不是使用原始事件。例如,对于Hue遥控器 - 开关按钮触发此事件
<Event zha_event[L]: unique_id=00:17:88:01:04:e7:f9:37:1:0x0006, device_ieee=00:17:88:01:04:e7:f9:37, endpoint_id=1, cluster_id=6, command=on, args=[]>
为此定义的操作是
(短按,打开):{COMMAND: COMMAND_ON}
第一部分(短按,打开)
对应于用户在UI中看到的文本
第二部分是事件数据。您只需要提供足够的事件数据来唯一匹配事件,在这种情况下,只是该设备触发的事件的命令:{COMMAND: COMMAND_ON}
如果您查看同一设备的另一个示例
(短按,调亮):{COMMAND: COMMAND_STEP, CLUSTER_ID: 8, ENDPOINT_ID: 1, PARAMS: {'step_mode': 0},}
您可以看到一个说明如何匹配更复杂事件的模式。在这种情况下,步进命令用于调亮和调暗按钮,因此我们需要匹配更多的事件数据来唯一匹配事件。
设置开发环境
在项目根目录中打开终端并运行设置脚本:script/setup
此脚本将安装所有必要的依赖项,并将安装预提交钩子。
测试使用的是pytest框架。
入门指南
为了设置环境,您需要安装测试依赖项
pip install -r requirements_test_all.txt
运行测试
有关如何运行测试的详细信息,请参阅pytest文档。例如,要运行所有test_tuya.py
测试
$ pytest --disable-warnings tests/test_tuya.py
Test session starts (platform: linux, Python 3.9.2, pytest 6.2.5, pytest-sugar 0.9.4)
collecting ...
tests/test_tuya.py ✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓ 100% ██████████
Results (3.58s):
41 passed
编写测试
要添加新的测试,首先在现有的测试文件之一中添加一个新的函数。您可以根据pytest文档中入门指南中的说明进行操作。
使用固定设置
为了编写测试,您需要访问一个quirk的实例来运行测试。pytest提供了一个有用的功能,称为固定设置(Fixtures),它允许您在一个地方编写和使用设置代码,类似于我们使用库为其他代码提供常用函数的方式。
您可以在这里了解更多关于固定设置的信息。
您可以在名为conftest.py
的文件中找到常见的固定设置。pytest将按以下方式为您列出它们
$ pytest --fixtures
[...]
--- fixtures defined from tests.conftest ---
MockAppController
App controller mock.
ieee_mock
Return a static ieee.
zigpy_device_mock
Zigpy device mock.
zigpy_device_from_quirk
Create zigpy device from Quirks signature.
[...]
--- fixtures defined from tests.test_tuya_clusters ---
TuyaCluster
Mock of the new Tuya manufacturer cluster.
一些固定设置,如app_controller_mock
,将提供一个可以直接使用的对象实例。其他,如zigpy_device_mock
,将返回一个函数,您可以在自己的设置期间调用它来创建定制的对象。
测试quirk签名匹配
固定设置assert_signature_matches_quirk
提供了一个函数,可以用来检查特定的设备签名是否与相应的quirk匹配。通过捕获签名并在测试文件中添加几行代码,这意味着您可以在不直接通过配对过程的情况下验证您的设备是否会与quirk匹配。
您需要捕获设备签名并将其保存。如果您之前已经在Home Assistant中启动了配对过程,您可以在设备页面上的“Zigbee设备签名”下找到签名。
现在您可以创建一个如下检查签名的测试
def test_ts0121_signature(assert_signature_matches_quirk):
signature = {
"node_descriptor": "NodeDescriptor(logical_type=<LogicalType.Router: 1>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.AllocateAddress|RxOnWhenIdle|MainsPowered|FullFunctionDevice: 142>, manufacturer_code=4098, maximum_buffer_size=82, maximum_incoming_transfer_size=82, server_mask=11264, maximum_outgoing_transfer_size=82, descriptor_capability_field=<DescriptorCapability.NONE: 0>, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=False, *is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, *is_security_capable=False)",
"endpoints": {
"1": {
"profile_id": 260,
"device_type": "0x0051",
"in_clusters": [
"0x0000",
"0x0004",
"0x0005",
"0x0006",
"0x0702",
"0x0b04"
],
"out_clusters": [
"0x000a",
"0x0019"
]
}
},
"manufacturer": "_TZ3000_g5xawfcq",
"model": "TS0121",
"class": "zhaquirks.tuya.ts0121_plug.Plug"
}
assert_signature_matches_quirk(zhaquirks.tuya.ts0121_plug.Plug, signature)
谢谢
- 特别感谢damarco为大多数设备跟踪代码做出的贡献
- 特别感谢Yoda-x为小米属性解析代码做出的贡献
- 特别感谢damarco和Adminiuga允许我向他们提出想法,并倾听我的唠叨
相关项目
Zigpy
zigpy是一个将Zigbee协议栈集成到Python 3库中,以实现Zigbee智能家居标准的开源项目。通过zigpy与Zigbee智能家居集成,您可以使用与zigpy兼容的Zigbee无线电库模块之一连接到许多现成的Zigbee适配器,以控制基于Zigbee的设备。目前支持控制二进制传感器(例如,运动和门传感器)、传感器(例如,温度传感器)、灯泡、开关、锁、风扇、遮盖物(百叶窗、帐篷等)。Zigpy的一个工作实现存在于Home Assistant(基于Python的开源智能家居软件)的ZHA组件中。
ZHA网络卡
zha-network-card是一个自定义的Lovelace卡片,用于在Home Assistant中显示ZHA网络和设备信息
项目详情
下载文件
下载适用于您平台的文件。如果您不确定选择哪个,请了解更多关于安装包的信息。
源分发
构建分发
zha_quirks-0.0.122.tar.gz的散列值
算法 | 散列摘要 | |
---|---|---|
SHA256 | bd14f3fd2bb22f4ff8d8c3c2bdf11dfdb90a3934d3a2a0b61c08469aaa09d31b |
|
MD5 | a8a5374889616e954662ed2ba13106e3 |
|
BLAKE2b-256 | 2849ca60cab3cd506783d393026e4ca0fc7433a9dc20397ecbfec87af4e27f36 |