许多ZigBee协议的行业规范都定义有网关设备,当运行相应的ZigBee SE Framework程序时,Digi的网关就成为真正意义的行业网关设备。此时,可以通过向网关的IP地址发送基于HTTP协议的Web Service API请求,从而实现对网内设备的信息采集和控制。
这类基于http的Web Service API也称为RPC(远程过程调用),你可以从本地内网的主控发起这样的请求,但Digi提供有一个基于设备云的工具,让您无需编写本地程序,实现通过公有云向网内设备发起RPC请求,同时能返回相应的请求响应,您只需有浏览器就可以观察RCP API调用的结果。这个工具称为Digi-SE Console,除了调试web service API外,该工具还可以列出网络的拓扑和网内设备支持的Cluster和Endpoints.让您在编写和测试RPC接口程序更加方便。为了使用该调试工具,您需要首先注册一个免费的设备云帐号,并将设备添加到您的帐号下。
Digi-SE Console托管在谷歌的Appspot.com上,国内的用户可能需要翻墙才能访问。首先,给设备和网关上电,确保网关能连上互联网,然后打开Digi-SE Console网址。您需要输入设备云的帐号并登录,这样在网关的下拉列表上,你可以找到这台已经连上云的设备。
在Network>Tree菜单项下,可以列出网内所有设备的状态,包括活动的Endpoints和可用的Cluster和对应的属性等。在Debug菜单项,下可以向网关发各种RPC的API调用,并在右上方的窗口上观察所有的消息。
事实上,上面的这张图也是通过RPC命令读取到的。通过ZCL的RPC调用,您可以获取ZigBee网络内设备的信息和状态。RPC命令的API调试窗口在Debug菜单项下。
网关上电后,SE Framework的主程序运行,会自动报告ZCL的一些事件消息,参考网关总体运行和一般操作获取更多信息。 首先会有这几条信息:
<message timestamp="1517886352.0"> <status type="int">0x0</status> <description type="string">Initialization complete, starting main loop</description> <severity type="int">0x1</severity> </message>
上面这条消息是在SE Framework程序完成初始化,开始主循环时发出的,表明网关设备开始工作。
<message timestamp="1517886352.0"> <status type="int">0x1</status> <description type="string">Local device detected that it is joined to a ZigBee network</description> <severity type="int">0x1</severity> </message>
上面这条消息是网关的XBee无线模块已经成功建网或是加入ZigBee网络,对网关而言,通常是网络已经建立并生成。
<message timestamp="1517886414.0"> <status type="int">0x3</status> <description type="string">Synchronization with NTP time server successful</description> <severity type="int">0x1</severity> </message>
上面是网关时间服务器的同步消息。
<message timestamp="1517887111.0"> <status type="int">0x105</status> <addr_short type="MAC">18DD</addr_short> <addr_extended type="MAC">00:13:A2:00:41:50:01:28</addr_extended> <description type="string">ZDO_Device_Manager - Received device announce message from known device 00:13:A2:00:41:50:01:28 (NWK: 18DD)</description> <severity type="int">0x1</severity> </message>
上面这条则是标准的ZDO公告消息,表明有网内设备上电并公告自己的存在,尝试入网等。
<message timestamp="1517887196.0"> <status type="int">0x102</status> <addr_extended type="MAC">00:13:A2:00:41:50:01:28</addr_extended> <description type="string">ZDO_Device_Manager - Device 00:13:A2:00:41:50:01:28 detected and marked as active</description> <severity type="int">0x1</severity> </message>
当设备尝试入网后尝试和网关通信时,被标记为活动状态。
以上这些消息也称为伪消息(虚拟消息),是网关报告ZigBee网内活动的一些消息。通常,我们需要的是通过Web Service的API主动发起查询或设置命令,这样网关会返回相应的结果。这类命令,通常在在Digi-SE 的Debug页面左侧RPC_ZCL_Interface和RPC_ZigBee_Interface类目下,下面给出一些用法示例:
HTTP请求:
<get_device_information synchronous="true"> </get_device_information>
HTTP响应:
<get_device_information_response timestamp="1517897763.0">
<record_list type="list">
<item type="ZDODeviceRecord">
<active_endpoints type="list">
<item type="int">0x4A</item>
</active_endpoints>
<power_descriptor type="Power_Desc_rsp">
<status type="int">0x0</status>
<nwk_addr type="MAC">0000</nwk_addr>
<available_power_sources type="int">0x1</available_power_sources>
<current_power_source_level type="int">0xC</current_power_source_level>
<current_power_source type="int">0x1</current_power_source>
<current_power_mode type="int">0x0</current_power_mode>
</power_descriptor>
<node_type type="int">0x0</node_type>
<addr_short type="MAC">0000</addr_short>
<addr_extended type="MAC">00:13:A2:00:41:5B:F9:58</addr_extended>
<node_descriptor type="Node_Desc_rsp">
<status type="int">0x0</status>
<logical_type type="int">0x0</logical_type>
<nwk_addr type="MAC">0000</nwk_addr>
<manufacturer_code type="int">0x101E</manufacturer_code>
<aps_flags type="int">0x0</aps_flags>
<user_desc_avail type="int">0x0</user_desc_avail>
<max_incoming_transfer_size type="int">0x80</max_incoming_transfer_size>
<max_outgoing_transfer_size type="int">0x80</max_outgoing_transfer_size>
<frequency_band type="int">0x8</frequency_band>
<descriptor_capability_field type="int">0x0</descriptor_capability_field>
<complex_desc_avail type="int">0x0</complex_desc_avail>
<max_buffer_size type="int">0x52</max_buffer_size>
<mac_capability_flags type="int">0x8F</mac_capability_flags>
<server_mask type="int">0x0</server_mask>
</node_descriptor>
<active type="bool">TRUE</active>
<manufacturer_id type="int">0x101E</manufacturer_id>
<simple_descriptors type="dict">
<endpoint_0x4A type="Simple_Desc_rsp">
<status type="int">0x0</status>
<nwk_addr type="MAC">0000</nwk_addr>
<profile_id type="int">0xBF0C</profile_id>
<output_cluster_id_list type="list">
<item type="int">0x0</item>
<item type="int">0x3</item>
<item type="int">0xA</item>
<item type="int">0xFC00</item>
<item type="int">0xFC01</item>
<item type="int">0xFC20</item>
</output_cluster_id_list>
<input_cluster_id_list type="list">
<item type="int">0xA</item>
</input_cluster_id_list>
<endpoint_id type="int">0x4A</endpoint_id>
<device_id type="int">0x0</device_id>
<device_version type="int">0x0</device_version>
</endpoint_0x4A>
</simple_descriptors>
</item>
<item type="ZDODeviceRecord">
<active_endpoints type="list">
<item type="int">0x1</item>
</active_endpoints>
<power_descriptor type="Power_Desc_rsp">
<status type="int">0x0</status>
<nwk_addr type="MAC">75E7</nwk_addr>
<available_power_sources type="int">0x1</available_power_sources>
<current_power_source_level type="int">0xC</current_power_source_level>
<current_power_source type="int">0x1</current_power_source>
<current_power_mode type="int">0x0</current_power_mode>
</power_descriptor>
<node_type type="int">0x1</node_type>
<addr_short type="MAC">75E7</addr_short>
<addr_extended type="MAC">00:13:A2:00:41:26:F8:49</addr_extended>
<node_descriptor type="Node_Desc_rsp">
<status type="int">0x0</status>
<logical_type type="int">0x1</logical_type>
<nwk_addr type="MAC">75E7</nwk_addr>
<manufacturer_code type="int">0x101E</manufacturer_code>
<aps_flags type="int">0x0</aps_flags>
<user_desc_avail type="int">0x0</user_desc_avail>
<max_incoming_transfer_size type="int">0xFF</max_incoming_transfer_size>
<max_outgoing_transfer_size type="int">0xFF</max_outgoing_transfer_size>
<frequency_band type="int">0x8</frequency_band>
<descriptor_capability_field type="int">0x0</descriptor_capability_field>
<complex_desc_avail type="int">0x0</complex_desc_avail>
<max_buffer_size type="int">0x52</max_buffer_size>
<mac_capability_flags type="int">0x8E</mac_capability_flags>
<server_mask type="int">0x0</server_mask>
</node_descriptor>
<active type="bool">TRUE</active>
<manufacturer_id type="int">0x101E</manufacturer_id>
<simple_descriptors type="dict">
<endpoint_0x01 type="Simple_Desc_rsp">
<status type="int">0x0</status>
<nwk_addr type="MAC">75E7</nwk_addr>
<profile_id type="int">0xBF0C</profile_id>
<output_cluster_id_list type="list"/>
<input_cluster_id_list type="list">
<item type="int">0x0</item>
<item type="int">0x3</item>
<item type="int">0xFC00</item>
<item type="int">0xFC01</item>
</input_cluster_id_list>
<endpoint_id type="int">0x1</endpoint_id>
<device_id type="int">0x1001</device_id>
<device_version type="int">0x0</device_version>
</endpoint_0x01>
</simple_descriptors>
</item>
<item type="ZDODeviceRecord">
<active_endpoints type="list">
<item type="int">0x1</item>
</active_endpoints>
<power_descriptor type="Power_Desc_rsp">
<status type="int">0x0</status>
<nwk_addr type="MAC">18DD</nwk_addr>
<available_power_sources type="int">0x1</available_power_sources>
<current_power_source_level type="int">0xC</current_power_source_level>
<current_power_source type="int">0x1</current_power_source>
<current_power_mode type="int">0x0</current_power_mode>
</power_descriptor>
<node_type type="int">0x1</node_type>
<addr_short type="MAC">18DD</addr_short>
<addr_extended type="MAC">00:13:A2:00:41:50:01:28</addr_extended>
<node_descriptor type="Node_Desc_rsp">
<status type="int">0x0</status>
<logical_type type="int">0x1</logical_type>
<nwk_addr type="MAC">18DD</nwk_addr>
<manufacturer_code type="int">0x101E</manufacturer_code>
<aps_flags type="int">0x0</aps_flags>
<user_desc_avail type="int">0x0</user_desc_avail>
<max_incoming_transfer_size type="int">0xFF</max_incoming_transfer_size>
<max_outgoing_transfer_size type="int">0xFF</max_outgoing_transfer_size>
<frequency_band type="int">0x8</frequency_band>
<descriptor_capability_field type="int">0x0</descriptor_capability_field>
<complex_desc_avail type="int">0x0</complex_desc_avail>
<max_buffer_size type="int">0x52</max_buffer_size>
<mac_capability_flags type="int">0x8E</mac_capability_flags>
<server_mask type="int">0x0</server_mask>
</node_descriptor>
<active type="bool">TRUE</active>
<manufacturer_id type="int">0x101E</manufacturer_id>
<simple_descriptors type="dict">
<endpoint_0x01 type="Simple_Desc_rsp">
<status type="int">0x0</status>
<nwk_addr type="MAC">18DD</nwk_addr>
<profile_id type="int">0xBF0C</profile_id>
<output_cluster_id_list type="list"/>
<input_cluster_id_list type="list">
<item type="int">0x0</item>
<item type="int">0x3</item>
<item type="int">0xFC00</item>
<item type="int">0xFC01</item>
</input_cluster_id_list>
<endpoint_id type="int">0x1</endpoint_id>
<device_id type="int">0x1001</device_id>
<device_version type="int">0x0</device_version>
</endpoint_0x01>
</simple_descriptors>
</item>
</record_list>
</get_device_information_response>
我们解读一下上面信息,很多是对应程序来说不需要的,每个Item包起来的信息代表一个设备的所有信息,包括它的电源属性,节点描述等标准的ZDO(ZigBee对象设备)信息。比较重要的是Simple_descriptors包起来的信息,其中就包括了活动的endpoit和cluster id,我们可以凭藉这些ID来读取Cluster下面的属性列表和信息。
HTTP请求:
<!-- Discover the attributes on a remote Fryer Cluster --> <discover_attributes synchronous="true"> <cluster_id>0xFC01</cluster_id> <server_or_client>0</server_or_client> <source_endpoint_id>0x4A</source_endpoint_id> <!--- Fryer addressing below here --> <destination_address type="MAC">00:13:A2:00:41:26:F8:49</destination_address> <destination_endpoint_id>0x01</destination_endpoint_id> </discover_attributes>
HTTP响应:
<discover_attributes_response timestamp="1517898036.0">
<source_endpoint_id type="int">0x1</source_endpoint_id>
<server_or_client type="int">0x0</server_or_client>
<record_list type="list">
<item type="AttributeInformationRecord">
<attribute_type type="int">0x10</attribute_type>
<attribute_id type="int">0x0</attribute_id>
</item>
<item type="AttributeInformationRecord">
<attribute_type type="int">0x30</attribute_type>
<attribute_id type="int">0x1</attribute_id>
</item>
<item type="AttributeInformationRecord">
<attribute_type type="int">0x30</attribute_type>
<attribute_id type="int">0x2</attribute_id>
</item>
<item type="AttributeInformationRecord">
<attribute_type type="int">0x21</attribute_type>
<attribute_id type="int">0x3</attribute_id>
</item>
<item type="AttributeInformationRecord">
<attribute_type type="int">0x21</attribute_type>
<attribute_id type="int">0x4</attribute_id>
</item>
<item type="AttributeInformationRecord">
<attribute_type type="int">0xB</attribute_type>
<attribute_id type="int">0x10</attribute_id>
</item>
<item type="AttributeInformationRecord">
<attribute_type type="int">0xB</attribute_type>
<attribute_id type="int">0x11</attribute_id>
</item>
<item type="AttributeInformationRecord">
<attribute_type type="int">0xB</attribute_type>
<attribute_id type="int">0x12</attribute_id>
</item>
<item type="AttributeInformationRecord">
<attribute_type type="int">0xB</attribute_type>
<attribute_id type="int">0x13</attribute_id>
</item>
</record_list>
<profile_id type="int">0xBF0C</profile_id>
<cluster_id type="int">0xFC01</cluster_id>
<destination_endpoint_id type="int">0x4A</destination_endpoint_id>
<source_address type="MAC">00:13:A2:00:41:26:F8:49</source_address>
</discover_attributes_response>
http请求:
<!-- Read a a remote fryer clust attribute -->
<read_attributes synchronous="true">
<cluster_id>0xFC01</cluster_id>
<server_or_client>0</server_or_client>
<source_endpoint_id>0x4A</source_endpoint_id>
<!--- Fryer addressing below here -->
<destination_address type="MAC">00:13:A2:00:41:26:F8:49</destination_address>
<destination_endpoint_id>0x01</destination_endpoint_id>
<record_list type="list">
<item type="ReadAttributeRecord">
<attribute_id>0</attribute_id>
</item>
</record_list>
</read_attributes>
http响应:
<read_attributes_response timestamp="1517898069.0">
<source_endpoint_id type="int">0x1</source_endpoint_id>
<server_or_client type="int">0x0</server_or_client>
<record_list type="list">
<item type="ReadAttributeStatusRecord">
<status type="int">0x0</status>
<attribute_type type="int">0x10</attribute_type>
<attribute_id type="int">0x0</attribute_id>
<value type="int">0x1</value>
</item>
</record_list>
<profile_id type="int">0xBF0C</profile_id>
<cluster_id type="int">0xFC01</cluster_id>
<destination_endpoint_id type="int">0x4A</destination_endpoint_id>
<source_address type="MAC">00:13:A2:00:41:26:F8:49</source_address>
</read_attributes_response>
上面这条响应是对属性0x0000(Split Vat Configuration)的查询结果,其值为0x1(true),在ZCK的规范中代表split vat,也就是双炸锅。
同样地,我们可以主动配置炸锅,这通过写入属性值这一操作来实现
<!-- Write an attribute on remote fryer cluster -->
<!--- This example writes to a read-only attribute and gets a 0x88 READ_ONLY error in the response status -->
<write_attributes synchronous="true">
<cluster_id>0xFC01</cluster_id>
<server_or_client>0</server_or_client>
<source_endpoint_id>0x4A</source_endpoint_id>
<!--- Fryer addressing below here -->
<destination_address type="MAC">00:13:A2:00:41:26:F8:49</destination_address>
<destination_endpoint_id>0x01</destination_endpoint_id>
<record_list type="list">
<item type="WriteAttributeRecord">
<attribute_type>0xB</attribute_type>
<attribute_id>0x10</attribute_id>
<value>0xFF000001</value>
</item>
</record_list>
</write_attributes>
具体的属性值所代表的意义,请参考:ZigBee Commercial Kitchen Application Profile Specification