伴随着物联网的大潮,无数的设备被安装上WiFi模块,接入到互联网上。比如国内的家电巨头海尔、美的、格力、海信等,已经在2014年推出了一系列带WiFi的智能家电产品,包括空调、冰箱、洗衣机、热水器、空气净化器、烤箱、电饭煲等等。等待了这么多年,智能家居终于开始成熟了。

相对于蓝牙和ZigBee等其他无线网络技术,WiFi最大的优势是无需依赖手机或者其他中间设备,通过WiFi路由器,就能够连接到互联网上,直接与云服务器连接或者进行远程控制。而且目前的WiFi模块功耗和价格已经下降得很多,很容易被嵌入到各种物联网设备中,无需过多的担心成本和功耗。

但是,将WiFi模块用在物联网设备中,也有一个麻烦,就是WiFi的初始设置。要让这些设备连接上WiFi路由器,需要首先让它们知道WiFi路由器的名称(SSID)和密码。但是不同于传统的PC或者手机,大多数物联网设备没有按键或者触摸屏这样的输入接口,因此需要其他的方法将路由器的SSID和密码告知物联网设备。因为这些物联网设备大多有与之配套的手机APP,问题也就变成了如何将SSID和密码从手机APP传送给这些设备。从目前已知的方法来看,主要有以下两种。

第一种是基于WiFi模块的SoftAP模式。在WiFi协议中,设备可以工作在AP模式,也可以工作在Station模式。比如WiFi路由器就是典型的AP,而手机和PC就是典型的Station。物联网设备在绝大多数情况下都是工作Station模式,但是为了支持初始配置,许多WiFi模块支持AP模式,当然,不是全功能的AP模式,只是有限的功能,所以称之为SoftAP。利用SoftAP进行WiFi初始配置的流程如下:

  1. 设备启动时,如果发现WiFi没有配置,则启动SoftAP模式,自己变成一个WiFi热点。
  2. 手机连接上SoftAP,打开APP,输入WiFi路由器的SSID和密码,传送给SoftAP。
  3. SoftAP收到SSID和密码后,切换到Station模式,连接指定的WiFi路由器,同时将SSID和密码保存在本地。
  4. 下次设备启动时,因为WiFi已经配置好了,设备之间进入Station模式,连接指定的WiFi路由器。

使用这种方式的智能设备很多,比如小K智能开关,第一次启动后会产生一个OK_SP3的热点,完成配置后就没有了。

在具体APP的实现中,需要考虑Android和iOS的不同。比如WiFi路由器SSID一般是不用用户输入的,APP会提供一个周围热点的SSID列表,用户选择即可。但是iOS是不支持在APP中做WiFi扫描的,因此需要设备端先扫描一个SSID列表发给手机,然后用户在APP里面选择。另外iOS是不支持在APP中切换WiFi连接的,因此用户需要先手工连接到SoftAP,完成配置后,再切换回来。而Android中是可以的。Android的APP中可以先自动连接SoftAP,配置完成后,再自动切换到原来的AP,而用户可能感觉不到这个过程,从而改善了用户体验。

第二种是基于WiFi模块的Sniffer模式。基于SoftAP的方式可以保证配置成功,但是用户体验不太好。因为它要求手机先连接到SoftAP上,无论是手工的(iOS)还是自动的(Android),配置完成后再切换回来。在此期间,手机因为离开了原先的WiFi路由器,因此失去了与互联网的连接。这个是许多用户感觉不爽的地方。而Sniffer模式不同。使用这种配置方式,用户手机不需要断开与当前WiFi路由器的连接,从而可以保持与互联网的连接。这也是这种方式经常被称为智能配置的原因。这种方式要求WiFi模块支持Sniffer模式,也就是杂收模式(Promiscuous)。对无线通信熟悉的人都知道,无线通信本质上是一种广播。理论上,一个WiFi设备可以收到空气中的所有包,只不过正常工作时,底层将不需要的包过滤掉了。打开杂收模式,就是将底层收到的所有包,直接提交给上层处理。这样,虽然WiFi模块与路由器和手机之间没有连接,但是它可以监听手机发出来的包,而手机APP也可以在这些包里面隐含配置信息,从而达到将配置信息传送给WiFi模块的目的。

手机发包时,是连接在WiFi路由器上的。如果WiFi路由器是加密的,比如WEP和WPA,那么WiFi模块收到的包必然也是加密的,模块无法直接获得包里面的信息,那么手机与模块之间怎么传递信息呢?这就要深入理解一下WiFi帧的结构。

物联网设备的WiFi快速配置

​图1,通用的WiFi帧结构

从上图可以看出,WiFi帧包括帧头,帧体和校验和三部分。其中帧头是不加密的,帧体部分根据帧类型的不同,有加密的,也有不加密的,比如管理帧ProbeRequest中的帧体部分就是不加密的。

另外,WiFi帧的长度也是很有用的信息。不管帧怎样加密,对于一定的加密方式(WEP,CCMP,TKIP),加密后的帧长度总是原始数据长度加上一个固定的偏移。这样手机APP就可以通过控制数据包长度的方式来传递有用信息。

总结起来,目前的智能配置一般有下面三种方式:

1, 第一种方式通过WiFi帧的长度传递信息。比如要传递一个字符串”abc”,三个字符a、b、c对应的ASCII分别是97、98、99。手机APP可以生成数据包,控制其长度为97、98、99加上固定的偏移量。这样WiFi模块捕获到包之后,就可以根据包长度提取有用的信息了。目前微信的airkiss就是使用这样的方式。京东的通用智能家居APP也是使用的这样的方式。

2, 第二种方式通过WiFi帧的MAC地址传递信息。WiFi帧头虽然是不加密的,但是它的内容都是底层WiFi驱动填写的,而手机APP处于应用层,是无法控制其中的内容的,但是有一个例外。就是手机APP发送UDP组播包时,组播包的目的IP地址的后23位会映射到WiFi帧目的MAC地址后23位,这样手机APP可以通过修改UDP包的组播地址,达到传递信息的目的。比如传递“abc”,可以发送3个组播包,目的地址分别是229.0.0.97,239.0.0.98,239.0.0.99。这样WiFi模块捕获到包之后,就可以从MAC地址中提取到有用的信息了。比如海尔的U+智能设备就是采用这样的方式。

3, 第三种方式是通过管理帧的帧体部分传递信息,一般使用ProbeRequest,因为它是手机APP可以在应用层控制的。手机APP可以在应用层构造一个目标SSID,启动扫描。比如传递”abc”,可以让手机扫描名为“abc”的目标SSID。WiFi模块捕捉到这样的扫描帧之后,就可以从中提取出有用的信息了。

当然,上面说的只是原理,真正实现的时候,有许多细节需要考虑。比如WiFi模块并不知道手机在哪个WiFi信道上发包,要捕捉到手机发出的包,首先要锁定信道。这就需要一些技巧。另外,安全性也是一个问题。因为手机要把WiFi路由器的密码传送给WiFi模块,如果是明文的,很容易就被截取了,从而给WiFi网络带来极大的安全隐患,这就需要对数据做扰码,这就需要八仙过海、各显神通了。

另外,SoftAP和智能配置也不是完全互斥的。智能配置虽然方便,但是在WiFi环境很复杂的时候,还是有一定的失败概率,而SoftAP是可以保证成功的。所以很多智能设备都是先用智能方式配置,如果失败就切换到SoftAP,比如海尔的U+智能家居设备。