1 Z-Wave简介
1.1 什么是Z-Wave技术
Z-Wave是一种新兴的基于射频的、低成本、低功耗、高可靠、适于网络的短距离无线通信技术。工作频带为908.42MHz(美国)~868.42MHz(欧洲),采用FSK(BFSK/GFSK)调制方式,早期的数据传输速率为9.6 kbps(现在40kbps),信号的有效覆盖范围在室内是30m,室外可超过100m,适合于窄带宽应用场合。随着通信距离的增大,设备的复杂度、功耗以及系统成本都在增加,相对于现有的各种无线通信技术,Z-Wave技术将是最低功耗和最低成本的技术,有力地推动着低速率无线个人区域网。
1.2 Z-Wave技术特征
(1) 低成本
(2) 低功耗
(3) 高可靠性
(4) 全网覆盖
(5) 通用性
(6) …..
1.3 Z-Wave技术应用
Z-Wave技术目前主要专注于家庭自动化领域,力求为用户提供一个更加舒适、方便和更具人性化的智能家居环境。Z-Wave网络的安装简单易行,各种符合标准的家庭设备都能方便地“安装”到家庭网络中,也能方便地从家庭网络“ 卸载”。
Z-Wave在其家庭网络中定义了三种类型的设备:控制器(controller)、路由从设备(routing slave)和从设备(slave)。当需要安装新的节点设备时,首先激活网络中的控制器和其他所有节点,激活可以同步也可以不同步。控制器被第一次激活后,通过广播查询新节点的请求,如果收到新节点的回应,控制器会向这个节点分配一个ID,通过这个ID来规定自己的属主关系。新节点需要向控制器报告它周围的邻居表(即在射频范围之内的所有节点),使得控制器有一个全面的网络拓扑信息,从而建立了一个无缝的网状结构通信网络。
Z-Wave在家庭中的应用主要包括照明控制、读取仪表(水、电、气)、家用电器功能控制、身份识别、通路(出入口)管制、能量管理系统、预警火灾等。
另外,Z-Wave还可以和传感器网络结合在一起使用,通过在家电和家具中部署基于Z-Wave的传感器节点,并使它们与Internet连接,用户就可以采用远程监控系统实现对家电的远程遥控。例如可以在回家之前半小时打开空调,这样回家的时候就可以直接享受适合的室温,也可以遥控电饭锅、微波炉、电冰箱、电话机、电视机、录像机、电脑等家电,按照自己的意愿完成相应的煮饭、烧菜、查收电话留言、选择录制电视和电台节目以及下载网上资料到电脑中等操作,也可以通过图像传感设备随时监控家庭安全情况。
1.4 Z-wave协议栈
相对于其他无线通信标准而言,Z-Wave协议栈显得更为紧凑和简单。Z-Wave协议栈包括四层:媒介访问控制(MAC)层、传输层、路由层和应用层,Z-Wave协议栈模型如图1所示,其各层的主要功能如下:
1.MAC层主要用于控制射频媒介,数据流采用曼彻斯特编码。
2. 传输层主要用于提供节点之间可靠的、透明的数据传输,主要功能包括重新传输、帧校验和帧确认等。
3. 路由层的主要功能包括:控制节点间数据帧的路由、确保数据帧在不同节点间能够多次重复传输、扫描网络拓扑和维持路由表(routing table)等。
4.应用层负责Z-Wave网络中的译码和指令的执行,主要功能包括:曼彻斯特译码、指令识别、分配HomeID和NodeID、实现网络中控制器的复制(replication)以及对传送和接收帧的有效载荷(pyload)进行控制。
图1 Z-Wave协议栈模型
2 Z/IP Gateway
2.1 ZIP Gateway定义
在Z-Wave网络中,Z/IP Gateway是一个允许网络客户端连接并且控制节点的应用程序。
Zipgateway需要以太网连接,它可以访问原始以太网帧。在Linux平台上,原始以太网的连接是通过使用linux TAP/TUN驱动程序来实现的,其网络结构图如下所示:
图2 z-wave 网络结构图
2.2 Gateway的主要功能
l 在端口41230/4123接收封装了Z/IP command的数据包
l Z/IP是封装了Z-wave command的UDP/IP包
l 提取z-wave的command指令
l 再将提取的z-wave指令封装在serial帧中,通过serial API发给对应的chip来完成与期望节点的通信。
图3 z-wave 网络模拟
地址与路由
如下图,phone controller想控制编号为2的灯泡,那么他是怎样完成通信的呢?
通过寻址和路由完成,大致的通信过程如下:
图4 z-wave 寻址通信模型
2.3 Gateway
图5 zipgateway 时序图
2.3.1 配置文件读取与解析
首先,需要解析zipgateway的配置文件zipgateway.cfg,这个文件定义了zipgateway的很多基本设置,例如使用的串口端口、IP地址、认证证书文件以及PSK等等。
1. static char* cfgfile = INSTALL_SYSCONFDIR "/" PACKAGE_TARNAME".cfg"
然后通过文件描述符去读取里面的各个参数已经配置的值,并将读取出的值放在一个全局的router_config结构体中。
图6 配置文件
2.3.2 虚拟网卡tap0
TUN/TAP驱动程序实现了虚拟网卡的功能,tun表示虚拟的是点对点设备,tap表示虚拟的是以太网设备,这两种设备针对网络包实施不同的封装。利用tun/tap驱动,可以将tcp/ip协议栈处理好的网络分包传给任何一个使用tun/tap驱动的进程,由进程重新处理后再发到物理链路中。
Zipgateway中的驱动程序是在tapdev-drv.c中完成的,当config文件解析完成后,便会执行驱动程序的初始化:
process_start(&tapdev_process); //启动进程 fd = open(DEVTAP,O_RDWR) ; //打开设备节点 ioctl(fd,TUNSETIFF,(void*)&ifr); //打开虚拟网卡 ioctl(fd,SIOCGIFHWADDR,&ifr); //获取网卡物理地址
设备驱动tap0启动后,通过select调用去轮询读端,一旦有数据产生,意思是从我们的pc controller/pyzip发来数据了,将此数据读取出来,这个数据存放在uip_buf中的,接下来就可以对接收到的数据进行处理了,拿到buf直接抛进contiki的uIP协议栈中了。
图7 tap0 & 桥接
其数据处理方式简化模式如下:
{ uip_len = tapdev_poll(); //tapdev6.c select、read调用返回 if(uip_len> 0) { // 有数据,抛进协议栈里面处理 uip_input(); if(uip_len > 0) { // uip_input返回后,如果buf中有数据,说明要返回各个controller,比如pc,pyzip脚本 tcpip_ipv6_output(); } }
Tap0驱动程序起来后,刚开始时没有数据流过来的,还有很多的初始化工作没有准备好,所以紧接着所做的最最重要的一件事情,就是启动我们zipgateway的主要进程了,它就是zip process。
2.3.3 ZIP process
ZIP process是在ZIP_Router.c里面定义的一个auto start process。
进入Zip process的主代码段,通过判断传入的event事件类型,来进行相应的动作。我们初次传入的是ev=PROCESS_EVENT_INIT,即初始化阶段,如下理出了zip process的初始化流程。
图8 zip process:reset时序
2.3.4 DTLS server
DTLS server给客户端提供安全链接的服务的,即给UDP传输提供端到端的安全通道,目前的版本仅支Pre-Shared-Key(PSK)方式。
OpenSSL API及基本流介绍
SSL通信模型采用标准的C/S结构,因此基于OpenSSL的程序可以被分为两个部分:Client和Server。上图1-1是建立SSL通信的流程简图,说明了基于OpenSSL的程序所要遵循的以下几个重要步骤。
(1)OpenSSL初始化
OpenSSL在使用之前,必须进行相应的初始化工作。完成初始化功能的函数原型为
1. int SSL_library_int(void); //初始化SSL算法库函数( 加载要用到的算法 ),调用SSL函数之前必须调用此函数
2. void SSL_load_error_strings(void); //错误信息的初始化
(2)创建CTX
在OpenSSL中,CTX是指SSL会话环境。建立连接时使用不同的协议,其CTX也不一样。创建CTX的过程中会依次用到以下OpenSSL函数:
3. SSL_CTX_new() //申请SSL会话环境,client,server都会用到
4. //若有验证对方证书的需求,则需调用
5. SSL_CTX_set_verify() //指定证书验证方式
6. SSL_CTX_load_verify_location() //为SSL会话环境加载本应用所信任的CA证书列表
7. //若有加载证书的需求,则需调用
8. SSL_CTX_use_certificate_file() //为SSL会话加载本应用的证书
9. SSL_CTX_use_certificate_chain_file() //为SSL会话加载本应用的证书所属的证书链
10. SSL_CTX_use_PrivateKey_file() //为SSL会话加载本应用的私钥
11. SSL_CTX_check_private_key() //验证所加载的私钥和证书是否相匹配
(3)创建SSL套接字
在此之前要先创建普通的流套接字,完成TCP三次握手,建立普通的TCP连接。然后创建SSL套接字,并将之与流套接字绑定。这一过程中会使用以下几个函数
1. SSL *SSl_new(SSL_CTX *ctx); //创建一个SSL套接字
2. int SSL_set_fd(SSL *ssl,int fd); //以读写模式绑定流套接字
3. int SSL_set_rfd(SSL *ssl,int fd); //以只读模式绑定流套接字
4. int SSL_set_wfd(SSL *ssl,int fd); //以只写模式绑定流套接字
(4)完成SSL握手
在这一步,我们需要在普通TCP连接的基础上,建立SSL连接。与普通流套接字建立连接的过程类似:Client使用函数SSL_connect()(类似于流套接字中用的connect())发起握手,而Server使用函数SSL_accept()(类似于流套接字中用的accept())对握手进行响应,从而完成握手过程。两函数原型如下:
1. int SSL_connect(SSL *ssl);
2. int SSL_accept(SSL *ssl);
握手过程完成之后,Client通常会要求Server发送证书信息,以便对Server进行鉴别。其实现会用到以下几个函数:
1. X509 *SSL_get_peer_certificate(SSL *ssl); //从SSL套接字中获取对方的证书信息
2. X509_NAME *X509_get_subject_name(X509 *a); //得到证书所用者的名字
3. SSL_CTX_use_certificate_file//指定使用的证书文件
4. SSL_CTX_use_PrivateKey_file//指定使用的私钥文件
5. SSL_CTX_set_cipher_list //指定使用的加密算法(123456789012345678901234567890AA)
(5)进行数据传输
经过前面的一系列过程后,就可以进行安全的数据传输了。在数据传输阶段,需要使用SSL_read( )和SSL_write( )来代替普通流套接字所使用的read( )和write( )函数,以此完成对SSL套接字的读写操作,两个新函数的原型分别如下:
1. int SSL_read(SSL *ssl,void *buf,int num); //从SSL套接字读取数据
2. int SSL_write(SSL *ssl,const void *buf,int num); //向SSL套接字写入数据
(6)会话结束
当Client和Server之间的通信过程完成后,就使用以下函数来释放前面过程中申请的SSL资源:
1. int SSL_shutdown(SSL *ssl); //关闭SSL套接字
2. void SSl_free(SSL *ssl); //释放SSL套接字
3. void SSL_CTX_free(SSL_CTX *ctx); //释放SSL会话环境
其流程图如下:
图9 SSL一般流程
DTLS初始化完成后,便进入while true循环等待连接事件了,这里我们主要等待的是有uIP处理后的tcpip_event事件。
2.3.5 Resource directory
Resource directory是一个包含z-wave网络中所有节点信息的database,该模块起来后,就会去探测(probe)网络中节点的信息,包括该节点所支持的Command Class,capability,end point等等信息,并把他们存储起来,探测过程结束后,保存到对应的数据库中,然后通过DHCP为这些网络中未分配ip地址的节点分配ip地址。
RD中有两个很重要的结构体,分别用来保存node和end point节点信息,如下:
当node被添加到网络后,都会存放在一个nat_table中,该结构体保存了每一个节点的信息:
初始化过程:
ResourceDirectory是在ZipRouter reset过程中最后才初始化的。
ZIP_Router_Reset(){ …… ApplicationInitProtocols(){ rd_init() } }
网络中的节点怎样区分?通过HomeID以及NodeID,而且每一个z-wave node都会有ipv4和ipv6地址,HomeID是在网络初始化的时候分配的,nodeID在 一个z-wave网络中也是唯一的,gateway的nodeID则默认被分配为1,而ip地址则通过dhcp模块来动态分配。
图10 resource directory时序
这里会把gateway加入到数据库中,最后通过start_discover方法为其动态分配ip地址,在SerialAPI_GetInitData返回后,会将网络中存在的node信息保存在nodelist中,然后循环将他们加进nat_table中并为新的node配置ip地址。
2.3.6 Comand Class
前面提到tap0端一旦接收到数据,就会往uIP协议栈里面扔,uIP协议栈里面解析头部,处理完数据后,我们会得到它其实是一个udp_input数据,最终走到tcpip_uipcall中,在这里会给DTLS server抛一个tcpip_event,表示客户端数据过来了。
图11 Z/IP Command
下面是整个数据包的格式:
图12 数据包格式
DTLS server读取数据,根据得到的nodeID是否与Controller的MyNodeID进行比较,如果相同,说明数据将发往gateway,调用UDPCommandHandler进行UDP指令数据的处理,解析出各种携带的command class以及对应封装的command。
如果你是一个SUC,或者primary controller,必须支持以下Conmand Class以及对应的command,即下面的CC是我们目前gateway需要支持的Network Manager相关的:
Command Class name |
Command Class identifier |
value |
Supported command identifier |
value |
Network Management Inclusion |
COMMAND_CLASS_NETWORK_MANAGEMENT_INCLUSION |
0x34 |
NODE_ADD |
0x01 |
NODE_REMOVE |
0x02 |
|||
… |
… |
|||
Network Management Basic Node |
COMMAND_CLASS_NETWORK_MANAGEMENT_BASIC |
0x4D |
LEARN_MODE_SET |
0x01 |
NODE_INFORMATION_SEND |
0x05 |
|||
DEFAULT_SET |
0x06 |
|||
Network Management Proxy |
COMMAND_CLASS_NETWORK_MANAGEMENT_PROXY |
0x52 |
NODE_LIST_GET |
0x01 |
NODE_LIST_REPORT |
0x02 |
|||
NODE_INFO_CACHED_GET |
0x03 |
|||
Network Management Primary |
COMMAND_CLASS_NETWORK_MANAGEMENT_PRIMARY |
0x54 |
CONTROLLER_CHANGE |
0x01 |
… |
|
|||
|
|
通过解析UDP数据包中的Conmand Class以及封装的command,接下来就是通过Serial API封装,发送给我们的chip了。
2.3.7 Serial Communication
串口即串行接口,是计算机上一种非常通用设备通信的协议,它可以将接受来自CPU的并行数据字符转换为连续的串行数据流发送出去,同时可将接受的串行数据流转换为并行的数据字符供给CPU的器件。
Zipgateway中使用的Serial API,是一套允许主机与Z-wave芯片通信的API。根据现有的芯片系列,可以通过RS-232或者USB物理接口来进行访问Serial API。
图13 Serial API通信模型
如果使用RS-232实现串口通信,则必须按如下进行设置:
Parameter |
Value |
波特率 |
115200 bits/s |
数据位 |
8 |
数据停止位 |
1 |
即ARM主控制器以波特率115200 bits/s、8 bit数据位、1 bit停止位方式通过异步串行口(UART)与Z-Wave无线模块进行通信(chip)。
如果使用USB连接实现串口通信则必须按照USB通信设备类准则(USB CDC)来实现。
Serial API启动
Zip process启动起来干的第一件事就是启动并初始化Serial API模块。
1. ZipSerialAPIPortName=/dev/ttyS2
2. process_start (&serial_api_process,cfg.serial_port)
初始化完成后,获取serial api的相关信息,然后发送第一个ACK包给到chip,表示我已就绪。接着获取gateway的相关信息。
Init初始化结束时,会重置一些添加节点,学习模式等命令。
ZW_AddNodeToNetwork(ADD_NODE_STOP,0);
ZW_RemoveNodeFromNetwork(REMOVE_NODE_STOP,0);
ZW_SetLearnMode(ZW_SET_LEARN_MODE_DISABLE, 0);
Gateway中通信具体实现
Gateway与zw chip通过简单的协议来进行通信,其通信使用的frametype有如下四种:ACK, NCK,CAN以及DataFrame类型。
ACK frame表示接收端接收到了一个有效的数据帧。
当主机发送了一个数据帧给zw chip后,必须等待chip回一个ACK帧。如果传输出现了错误或其他低概率事件导致传输失败,chip便会回一个其他帧。
主gateway会等待1500ms的timeout时延等待这个ack帧。
ACK帧的结构如下,是一个8bit的数值,定义为0x06:
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
ACK(0x06) |
NCK frame表示接收端收到的数据有错误,收到NCK时需要进行数据重传(retransmit),其结构如下,定义为0x15:
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
NCK(0x15) |
CAN frame表示接收端丢弃了一个有效的数据帧。Chip正在等待gateway给他发一个ACK帧,但是gateway却为其发送了一个data frame,因此,chip此时会回应gateway一个CAN frame,此时就会发生重传。
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
CAN(0x18) |
Date Frame,数据帧里面封装了期望的Serial API指令以及请求指令时一些必要的参数。
每一个Data Frame都必须以一个start of frame (SOF)开头,紧接着的是帧的总长度,类型,然后才是封装的Serial APIcommand ID以及对应的参数,最后以一个校验和checksum结尾,其具体结构如下:
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
SOF(0x01) |
|||||||
Length |
|||||||
Type |
|||||||
Serial API Command ID |
|||||||
Serial API Command Parameter 1 |
|||||||
… |
|||||||
Serial API Command Parameter n |
|||||||
Checksum |
帧类型和含义说明:
类型 |
含义 |
SOF(start of frame) |
主要用来同步,其值为0x01 |
Length |
以字节为单位的帧长度,不包括SOF和checksum |
Type |
该数据帧的类型有如下三种 0x00:REQ,request请求帧 0x01:RES,response 回应帧 0x02…0xFF: 保留位 |
Serial API Command ID |
这个值必须是serial api中支持的ID值(ZW_SerialAPI.h) |
Serial API Command Parameters |
携带的额外必要的参数 |
Checksum |
校验和 |
校验和主要用来检验帧的完整性,其值初始化为0xFF,伴随着帧结构中其他结构的异或结果传送给chip端。
Checksum = 0xFF ⊕ Length ⊕ Type ⊕ Cmd ID ⊕ CmdParm[1] ⊕ …⊕ Cmd Parm[n]
一个基本的发送和接收流程如下,这边的host即我们的zipgateway了,ZW即我们的z-wave chip:
在Serial API模块初始化完成后,既可以开始serial的通信了,在serial API version 4之后的版本中,serial初始化以后,需要初步建立节点的信息帧有必要发送Node Information Command来存储新的Node Information Frame(NIF)。
3 Pyzip & MDNS browser
3.1 Pyzip
PyZIP是一个zipgateway的客户端程序:,他的特点如下:
− 基于python语言编写而成
− 利用pyzip可以对ZWgateway进行基本的测试
− 生成Cert Key用来连接Portal )
主界面:
Z-Wave Portal应用
这里提到的portal是指Z-Wave webserver,利用它我们可以发现网络中的Gateway并且想Gateway以及网络中的节点发送Z-wave Command。
在android phone上的界面如下:
3.2 MDNS Browser
MDNS Browser是一个展示z-wave节点及其存储在Resource Directory中数据的一个应用程序,目前该应用程序还无法与z-wave network通信,仅有展示功能。
主界面:
4 总结
本篇文章主要对Z-Wave技术和核心部分ZIPGateway的流程和核心功能进行了梳理。
随着技术的进一步完善和发展,业界更多的注意力和研发力量将转移到应用的设计和实现、互连互通测试以及市场推广等方面。相信在不远的将来,将会有越来越多的Z-Wave设备进入我们的生活,使我们的生活变得更加便利。