许多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菜单项下。

网关RPC命令的API用法示例

网关上电后,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类目下,下面给出一些用法示例:

获取ZigBee网络的设备信息

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