(十七)物联网之 WIFI 一键配网 smartConfig 浅析

一、背景

物联网时代技术开始规模化服务于民众,方便快捷显得尤为重要,WIFI 直连便是一个典型案例。

目前主流的 WIFI 配置模式有以下 2 种:

1、智能硬件处于 AP 模式(类似路由器,组成局域网),手机用于 STA 模式

手机连接到处于 AP 模式的智能硬件后组成局域网,手机发送需要连接路由的 SSID 及密码至智能硬件,智能硬件主动去连接指定路由后,完成配网

2、一键配网(smartConfig)模式

智能硬件处于混杂模式下,监听网络中的所有报文;手机 APP 将 SSID 和密码编码到 UDP 报文中,通过广播包或组播报发送,智能硬件接收到 UDP 报文后解码,得到正确的 SSID 和密码,然后主动连接指定 SSID 的路由完成连接。

AP 模式:

AP 是 (Wireless) Access Point 的缩写,即 (无线) 访问接入点。简单来讲就像是无线路由器一样,设备打开后进入 AP 模式,在手机的网络列表里面,可以搜索到类似 TPLINK_XXX 的名字(SSID)。

连接步骤:

1、智能硬件设备初始化并进入 AP 模式
2、手机扫描 WIFI 列表:扫描到智能硬件设备后(SSID)连接该智能硬件设备,通过 UDP 发送 经过 AES 加密过的 ssid/password/token
3、智能硬件设备通过 UDP 包获取配置信息,切换网络模式连接 WIFI 后配网完成

smartConfig 模式:

这种快速连接方式,相对于 AP 模式连接简化操作,更加贴近于市场

1、手机连上 WiFi,打开智能硬件指定 APP 软件,进入配置界面,输入手机所在 WiFi 密码,请求配网 TOKEN
2、智能硬件开启混杂模式监听所有网络数据包
3、手机通过广播、组播循环发送 ssid/password/token
4、硬件设备通过 UDP 包(长度)获取配置信息捕捉到 ssid/password/token,连接路由器(广播根据 UDP 包长度,组播根据 IP 地址信息)

从原理上讲只要芯片驱动支持开启混杂模式(WiFi Promiscuous),就可以支持一键配网功能

手机编码发送采用有 UDP 组播或广播,不同的发送方式和编码,对应的解码过程也不一样

1、广播:

发送方可通过改变其所需要发送数据包的长度进行控制,因此只要指定出一套利用长度编码的通讯协议,就可利用数据包的 Length 字段进行数据传递

2、 组播:

组播地址是保留的 D 类地址从224.0.0.0-239.255.255.255

IP 地址与 MAC 地址映射关系为:将 MAC 地址的前 25 位设定为 01.00.5e,而 MAC 地址的后 23 位对应 IP 地址位

故发送端可以将数据编码在组播 IP 的后 23bit 中,通过组播包发送接收端进行解码即可

二、smartConfig 原理浅析

在没有和其他设备(支持 smartConfig 技术)建立任何性质的通讯链路的情况下, 配置该设备接入 WIFI 网络

普通权限的应用程序是没有能力完全控制和定义传输层及下层所有协议数据的, 唯一可以完全控制的就是应用层数据

本质上就是将 UDP 包头的数据长度作为 smartConfig 的数据,APP 端和设备端共用一套编码表即可解析数据

TCP/IP 协议栈中的网络层和传输层的数据结构

常用的网络层协议是 IPv4, IPv4 的头部绝大多数情况下都是定长的20字节

传输层协议是 UDP, 因为 UDP 协议头部为定长的 8 字节

明文长度 = 20 + 8 + dataLen

密文长度 = 20 + 8 + dataLen + 算法常量

例子:

如果需要发出一个密文长度为 500 字节的 802.11 帧,只需要在 UDP 中填充任意(500 – 20 – 8 – 算法常亮)个字节数据即可

因此,只需要利用可控的密文长度(dataLen)定义一张编码表即可将数据告诉任何知道这张编码表的设备(IoT硬件设备)

自定义一张编码表,流程如下:

dataLen --> 映射
1234    --> 起始符; 连续的3个起始符, 用于表示数据传输开始
1324    --> 结束符; 连续的3个结束符, 用于表示数据传输结束
110     --> 间隔符; 连续的2个间隔符, 用于表示数据符之间的间隔
1000    --> 数据符; 表示 ASCII 0x00
1001    --> 数据符; 表示 ASCII 0x01

1127    --> 数据符; 表示 ASCII 0x7F

假设我们要把字符串"Jay"告诉摄像头, 整个流程大致如下: (假设算法常亮为 16)

APP 端:
 
打开手机 APP, 在输入框中填入要发送的字符串”Jay”, 点击发送:

1.1、APP 连续发送 3 个 UDP 广播包, 填充数据为 1190 个字节 0x00 数据 ( 1234 – 16 – 20 – 8 = 1190 ), 表示传输开始
1.2、APP 发送     1 个 UDP 广播包, 填充数据为 1030 个字节 0x00 数据 ( 1074 – 16 -20 – 8 = 1030  ), 传输字符 J
1.3、APP 连续发送 2 个 UDP 广播包, 填充数据为 66   个字节 0x00 数据 ( 110 – 16 – 20 – 8 = 66    ), 表示数据间隔
1.4、APP 发送     1 个 UDP 广播包, 填充数据为 1053 个字节 0x00 数据 ( 1097 – 16 -20 – 8 = 1053  ), 传输字符 1097 对应 a
1.5、APP 连续发送 2 个 UDP 广播包, 填充数据为 66   个字节 0x00 数据 ( 110 – 16 – 20 – 8 = 66    ), 表示数据间隔
1.6、APP 发送     1 个 UDP 广播包, 填充数据为 1077 个字节 0x00 数据 ( 1121 – 16 -20 – 8 = 1077  ), 传输字符 1121 对应 y
1.7、APP 连续发送 3 个 UDP 广播包, 填充数据为 1280 个字节 0x00 数据 ( 1324- 16 – 20 – 8 = 1280  ), 表示传输结束

从步骤 1.1 开始循环多次, 直到超时或 IoT 设备成功接入 WIFI

IoT 设备端:

设备上电进入混杂模式,开始监听信号覆盖范围内的所有 WIFI 数据帧

捕获数据帧, 如果连续收到 3 个密文,其数据长度 dataLen 为 1234 字节, 且来自于同一个发射源 channel-A 的数据帧, 则进入下一步, 否则该步骤

捕获发射源 channel-A 的数据帧, 持续捕获密文数据长度为 110 或 1000-1127 之间的数据帧, 直到捕获到连续 3 个密文数据长度为 1324 的数据帧

将上述数据帧按照编码表进行映射, 由于手机 APP 并非是独占网络, 所以捕获到的数据可能有噪音, 比如解码出来的结果可能是(/表示分隔符): mnJ/[email protected]/ymmm

如果没有噪音, 记为候选数据RC, 重复捕获X, 进行二次验证, 通过则表示接收完成, 没通过也重复捕获 channel-A,

将这次所得结果同上一次做交集, 循环如此直到得出唯一结果, 即 RC, 之后再重复 5

由于捕获的数据帧头部信息中已经包含了 WIFI 的 BSSID 信息, 使用 "Jay" 作为密码去尝试连接相应的 WIFI

三、ESP32 配网实例:

手机 APP:

ESP-TOUCH

烧写设备端:

#include "WiFi.h"

void setup() {
  Serial.begin(115200);

  //Init WiFi as Station, start SmartConfig
  WiFi.mode(WIFI_AP_STA);
  WiFi.beginSmartConfig();

  //Wait for SmartConfig packet from mobile
  Serial.println("Waiting for SmartConfig.");
  while (!WiFi.smartConfigDone()) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("SmartConfig received.");

  //Wait for WiFi to connect to AP
  Serial.println("Waiting for WiFi");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("WiFi Connected.");

  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  // put your main code here, to run repeatedly:

}

四、知识扩展

在当前网络通信中有三种通信模式:

单播、广播、组播(又叫多播),其中多播出现的时间最晚,但同时具备单播和广播的优点,最具有发展前景.

通信方式分类:

1.单播:单台主机与单台主机之间的通信;

2.广播:单台主机与网络中所有主机的通信;

3.组播:单台主机与选定的一组主机的通信;

单播:

单播是网络通信中最常见的,网络节点之间的通信 就好像是人们之间的对话一样,如果一个人对另外一个人说话,那么用网络技术的术语来描述就是“单播”,此时信息的接收和传递只在两个节点之间进行。

1. 单播的优点:

(1)服务器以及响应客户端的请求;

(2)服务器能针对每个客户端的不同请求发送不同的响应,容易显示个性化服务;

2. 单播的缺点:

服务器针对每个客户机发送数据流,服务器流量=客户机数量×客户机流量;在客户数量大、每个客户机流量大的流媒体应用中服务器不堪重负;

3. 应用场景:

单播在网络中得到了广泛的应用,网络上绝大部分的数据都是以单播的形式传输的,例如:收发电子邮件、游览网页时,必须与邮件服务器、服务器建立连接,此时使用的就是单播通信方式;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;

// 客户端
public class ClientTest
{
    private static final int MAXRECEIVED = 255;

    public static void main(String[] args) throws IOException
    {
        byte[] msg = new String("connect test successfully!!!").getBytes();

        DatagramSocket client = new DatagramSocket();

        InetAddress inetAddr = InetAddress.getLocalHost();
        SocketAddress socketAddr = new InetSocketAddress(inetAddr, 8888);

        DatagramPacket sendPacket = new DatagramPacket(msg, msg.length,
                socketAddr);

        client.send(sendPacket);

        client.close();
    }
}

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.util.Arrays;

//服务端
public class ServerTest
{
    private static final int MAXREV = 255;

    public static void main(String[] args) throws IOException
    {
        DatagramSocket server = new DatagramSocket(8888);
        DatagramPacket recvPacket = new DatagramPacket(new byte[MAXREV], MAXREV);

        while (true)
        {
            server.receive(recvPacket);

            byte[] receiveMsg = Arrays.copyOfRange(recvPacket.getData(),
                    recvPacket.getOffset(),
                    recvPacket.getOffset() + recvPacket.getLength());

            System.out.println("Handing at client "
                    + recvPacket.getAddress().getHostName() + " ip "
                    + recvPacket.getAddress().getHostAddress());

            System.out.println("Server Receive Data:" + new String(receiveMsg));

            server.send(recvPacket);

        }

    }
}

广播:

广播可以比作为一个人通过广播喇叭对在场的全体说话,换句话说: 广播是一台主机对某一个网络上的所有主机发送数据报包。

这个网络可能是网络,也可能时子网,还有可能是所有子网。

广播有两类:本地广播和定向广播:

定向广播:将数据报包发送到本网络之外的特定网络的所有主机,互联网上的大部分路由器都不转发定向广播消息;

本地广播:将数据报包发送到本地网络的所有主机,IPv4的本地广播地址为“255.255.255.255”,路由器不会转发此广播;

1.广播的优点:

(1)通信的效率高,信息一下子就可以传递到某一个网络上的所有主机。

(2)由于服务器不用向每个客户端单独发送数据,所以服务器流量比较负载低;

2.广播的缺点:

(1)非常占用网络的带宽;

(2)缺乏针对性,也不管主机是否真的需要接收该数据, 就强制的接收数据;

3.应用场景:

有线电视就是典型的广播型网络

UDP 广播:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

//客户端
public class BroadcastSender
{
    public static void main(String[] args) throws IOException
    {
        byte[] msg = new String("connection successfully!!!").getBytes();
        /*
         * 在Java UDP中单播与广播的代码是相同的,要实现具有广播功能的程序只需要使用广播地址即可, 例如:这里使用了本地的广播地址
         */
        InetAddress inetAddr = InetAddress.getByName("255.255.255.255");
        DatagramSocket client = new DatagramSocket();

        DatagramPacket sendPack = new DatagramPacket(msg, msg.length, inetAddr,
                8888);

        client.send(sendPack);
        System.out.println("Client send msg complete");
        client.close();
    }
}

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.util.Arrays;

//服务端
public class BroadcastReceive
{
    public static void main(String[] args) throws IOException
    {

        DatagramPacket receive = new DatagramPacket(new byte[1024], 1024);
        DatagramSocket server = new DatagramSocket(8888);

        System.out.println("---------------------------------");
        System.out.println("Server current start......");
        System.out.println("---------------------------------");

        while (true)
        {
            server.receive(receive);

            byte[] recvByte = Arrays.copyOfRange(receive.getData(), 0,
                    receive.getLength());

            System.out.println("Server receive msg:" + new String(recvByte));
        }

    }
}

组播:

组播可以比作为你对着大街喊:女士免费领优惠券,那么女士就会过来,男士就不会过来(组播:其中所有的女士就是一个组)

换句话说:
     
     组播是一台主机向指定的一组主机发送数据报包,因为如果采用单播方式,逐个节点传输,有多少个目标节点就会有多少次传送过程,这种方式显然效率极低,是不可取的;
     
     如果采用不区分目标、全部发送的广播方式,虽然一次可以传送完数据,但是显然达不到区分特定数据接收对象的目的,又会占用网络带宽。
     
     采用组播方式,既可以实现一次传送所有目标节点的数据,也可以达到只对特定对象传送数据的目的;

IP 网络的组播一般通过组播 IP 地址来实现,组播 IP 地址就是 D 类 IP 地址,即 224.0.0.0 至 239.255.255.255 之间的IP地址。

1.组播的优点:

(1)具备广播所具备的所有优点;

(2)与单播相比,提供了发送数据报包的效率,与广播相比,减少了网络流量;

2.组播的缺点:

与单播协议相比没有纠错机制,发生丢包错包后难以弥补,但可以通过一定的容错机制和QOS加以弥补;

UDP 组播:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;

//客户端
public class MulticastSender
{
    public static void main(String[] args) throws IOException
    {
        int port = 8888;
        byte[] msg = "Connection successfully!!!".getBytes();

        InetAddress inetRemoteAddr = InetAddress.getByName("224.0.0.5");

        /*
         * Java UDP组播应用程序主要通过MulticastSocket实例进行通信,它是DatagramSocket的是一个子类,
         * 其中包含了一些额外的可以控制多播的属性.
         *
         * 注意:
         *
         * 多播数据报包实际上可以通过DatagramSocket发送,只需要简单地指定一个多播地址。
         * 我们这里使用MulticastSocket,是因为它具有DatagramSocket没有的能力
         */
        MulticastSocket client = new MulticastSocket();

        DatagramPacket sendPack = new DatagramPacket(msg, msg.length,
                inetRemoteAddr, port);

        client.send(sendPack);

        System.out.println("Client send msg complete");

        client.close();

    }
}

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.util.Arrays;

//服务端
public class MulticastReceive
{
    public static void main(String[] args) throws IOException
    {
        InetAddress inetRemoteAddr = InetAddress.getByName("224.0.0.5");

        DatagramPacket recvPack = new DatagramPacket(new byte[1024], 1024);

        MulticastSocket server = new MulticastSocket(8888);

        /*
         * 如果是发送数据报包,可以不加入多播组; 如果是接收数据报包,必须加入多播组; 这里是接收数据报包,所以必须加入多播组;
         */
        server.joinGroup(inetRemoteAddr);

        System.out.println("---------------------------------");
        System.out.println("Server current start......");
        System.out.println("---------------------------------");

        while (true)
        {
            server.receive(recvPack);

            byte[] recvByte = Arrays.copyOfRange(recvPack.getData(), 0,
                    recvPack.getLength());

            System.out.println("Server receive msg:" + new String(recvByte));
        }

    }
}

refer:

https://wenku.baidu.com/view/ab6bc08a9b6648d7c0c746ac.html
https://blog.csdn.net/sadshen/article/details/47049129

https://my.oschina.net/u/2396236/blog/1788674
https://blog.csdn.net/li_yangyang_li/article/details/50989220
https://blog.csdn.net/flyingcys/article/details/49283273

https://blog.csdn.net/dabing69221/article/details/17286441#t1

原文地址:https://www.cnblogs.com/zhangshenghui/p/12172893.html

时间: 2024-10-08 03:45:26

(十七)物联网之 WIFI 一键配网 smartConfig 浅析的相关文章

WIFI智能配网 - SmartConfig

要开始IoT项目的第一步是什么?当然不是硬件,而是硬件与硬件的连接!即使有各种各样的通信协议没有好的连接方式绝对不行.那外设上没有的屏幕,没有键盘怎末输入密码怎末选择网络?对,这就是WIFI模块最重要解决的问题. 为了解决这个连接问题乐鑫在其SDK中加入了SmartConfig功能,所谓的smartconfig就是手机APP端发送包含WIFI 用户名 WIFI密码的 UDP 广播包或者组播包,智能终端的WIFI芯片可以接收到该UDP包,只要知道UDP的组织形式,就可以通过接收到的UDP包解密 出

26-ESP8266 SDK开发基础入门篇--编写WIFI模块 SmartConfig/Airkiss 一键配网

https://www.cnblogs.com/yangfengwu/p/11427504.html SmartConfig/Airkiss 配网需要APP/微信公众号,这节大家先使用我做好的APP/微信公众号 APP下载: https://www.cnblogs.com/yangfengwu/p/11249674.html 微信公众号: 扫描这个二维码关注我的公众号      其余的步骤等写完8266的配网程序,在下面演示. 如果想自己实现微信绑定可以看↓ (注:配置过程和源码全部是公开的,大

WiFi-ESP8266入门http(3-4)网页一键配网(1若为普通wifi直连 2若为西电网页认证自动网页post请求连接)+网页按钮灯控+MQTT通信

网页一键配网(1若为普通wifi直连  2若为西电网页认证自动网页post请求连接)+网页按钮灯控+MQTT通信 工程连接:https://github.com/Dongvdong/ESP8266_HTTP_WEB_MQTT/tree/master/MQTT_http 主要目标 网页动态配网 网页认证模式的WIFI也能让ESP8266上网 未来完善: 1 加入网页判断,若为网页认证WIFI需要手动文本框输入 学号和密码(简单) 修改html加入两个文本框和一个判断,用于返回消息 2 现在固定测试

3-(微信小程序篇)WiFi模块配网以后利用小程序绑定,控制设备,一次只能绑定控制一个设备

https://www.cnblogs.com/yangfengwu/p/11623750.html 一,实现的功能描述 STM32通过AT指令控制模块配网(支持SmartConfig和Airkiss),配网以后设备进入绑定状态(60S超时),在设备绑定超时时间内打开小程序即可绑定设备,然后实现控制功能. 二,功能测试 1,由于会不停的更新小程序代码,小程序发布又需要时间审核,我就不发布小程序,所以大家先按照以下方式运行小程序(熟悉一下流程) 1.1 打开小程序工程代码 1.2 选择真机调试,选

10-STM32物联网开发WIFI(ESP8266)+GPRS(Air202)系统方案微信小程序篇(微信配网配置_Airkiss步骤_1)

https://www.cnblogs.com/yangfengwu/p/11066036.html 如果提交失败多提交两次,只要上一节可以,,这一节一定可以的 如果没有设备 咱就测试一下扫描二维码配网,下一节咱再看怎么嵌入到公众号里面,点击按钮实现 修改咱的程序 所有LUA开发的WIFI程序,配网的地方 以升级篇为例: (其它地方都是这样修改) 纯AT指令实现的不需要修改 稍等有点事情 原文地址:https://www.cnblogs.com/yangfengwu/p/11066472.htm

物联网 WIFI 一键配置原理(smartconfig) ESP8266/QCA4004 参考

物联网 WIFI 一键配置原理(smartconfig) ESP8266/QCA4004 物联网WIFI 嵌入式爱好者(小子图) · 2015-09-05 11:07 自从物联网问世以来,如何使得物  能够联网有了很多的方式,目前运用非常广的WIFI,今天就总结下自这个方面,也对于有需要的盆友也希望有抛砖引玉之效果. 来看个知乎上的提问,很有意思! 问题: 买了BroadLink的智能插座,发现有一个很神奇的一键配置功能.简单的说就是:当智能插座还没有连上WiFi的时候,此时通过手机App可以将

7-STM32物联网开发WIFI(ESP8266)+GPRS(Air202)系统方案微信小程序篇(微信配网_申请微信公众号)

https://www.cnblogs.com/yangfengwu/p/11042266.html 老是学习枯燥乏味的东西容易烦躁,所以呢,接着这几节咱实现下微信配网 为了让所有人都可以都可以使用,咱就用微信订阅号实现(里面提供测试版服务号),实质上只有服务号和微信企业号才具有此功能. 咱呢注册登录订阅号 https://mp.weixin.qq.com/ 原文地址:https://www.cnblogs.com/yangfengwu/p/11062034.html

13-STM32物联网开发WIFI(ESP8266)+GPRS(Air202)系统方案微信小程序篇(网页版MQTT)

https://www.cnblogs.com/yangfengwu/p/11148976.html 抱歉哈...最近由于做板子,,教程的进度落下了... 这些天总共做了还几块板子 首先对当前这个教程的这个板子做了修订,调整了下布局,替换换了以前用的Micro USB 接口,开关降压改为MP4462 STM32+Air720H(全网通GPRS)+以太网+422/485+4-20ma采集    https://www.cnblogs.com/yangfengwu/category/1472273.

7-STM32物联网开发WIFI+GPRS基础篇(STM32+Wi-Fi(AT指令)实现MQTT远程通信控制)

https://www.cnblogs.com/yangfengwu/p/10840517.html 新板子终于到了,耽搁时间了,抱歉哈!为了表达歉意,我做了几套代码提供给大家 这节的代码也作为整版测试 看名字就知道了,简单的说 就是  单片机使用AT指令控制模块实现MQTT通信控制 先看这节 STM32+WIFI(AT指令)实现MQTT通信控制: 一,下载STM32程序 1,方式一,串口下载(其他下载方式在最后补充) ①调整拨动开关位置 → 短接BOOT0和3.3V → 复位STM32 ②打开