一、AP配网技术原理
1.1 配网模式选择
AP配网(SoftAP模式)是IoT设备配网成功率最高的方案之一
1、其核心原理:
- 设备端:启动AP模式(如SSID格式
YC3000_XXXX
,默认IP192.168.4.1
) - 手机端:直连设备热点后建立TCP/UDP通信,传输目标路由器的SSID/Password
1.2 协议交互流程
sequenceDiagram
小程序->>设备AP: 连接热点(SSID:YC3000_XXXX)
小程序->>设备AP: 建立TCP连接(IP:192.168.4.1:8266)
小程序->>设备AP: 发送AT+CJWAP指令
设备AP-->>小程序: 返回"Data Correct"或"Data Error"
小程序->>设备AP: 发送AT+RST指令重启
设备AP->>路由器: 连接目标WiFi
基础描述(大白话)
WiFi设备进入配网状态,实际是进入AP模式,设备开放一个Wifi热点出来。手机通过连接上设备Wifi模块的热点,将路由器名字和密码直接发送给Wifi设备,设备接收成功后,重启设备。
UDP配网逻辑是一样的,如果需要UDP通信,命令参考UDPSocket | 微信开放文档
二、操作过程
2.1 用户长按按钮,触发WiFi设备进入配网模式。设备在此模式下创建wifi热点(单纯AP模式),开启TCP服务(默认 IP 为192.168.4.1,端口为8266),使指示灯闪烁。
2.2 小程序按照提示依次获取 Wi-Fi 列表,输入目标路由器的 SSID/PSW,再选择设备 softAP 热点的 SSID/PSW。
2.3 手机连接设备 softAP 热点成功后,小程序作为 TCP 客户端会连接 Wi-Fi 设备上面的 TCP 服务。
2.4 小程序给设备 TCP 服务,发送目标 Wi-Fi 路由器的 SSID/PSW 。
2.5 设备接收成功后重启,配网成功
三、UniApp开发实现
3.1 开发环境配置
1.manifest.json声明权限:
"mp-weixin" : {
"appid" : "******",//微信小程序appid
"setting" : {
"urlCheck" : false,
"minified" : true
},
"usingComponents" : true,
"permission" : {//必要,获取WiFi配置必须申请使用位置权限
"scope.userLocation" : {
"desc" : "用户使用小程序关联物联设备时,需要获取用户的所在位置区域"
}
},
"requiredPrivateInfos" : [ "getLocation", "chooseLocation" ],
},
2.设备热点连接(需用户手动操作引导)
uni.connectWifi({
SSID: 'YC3000_XXXX', // 设备热点名称
password: 'z111111',
success: (res) => { console.log("连接成功,开始TCP通信") },
fail: (err) => { console.log("连接失败", err) }
});
3.2 TCP核心通信模块
连接建立
this.tcp = wx.createTCPSocket();
console.log('运行')
this.tcp.connect({
address: '192.168.4.1',//默认 IP 为192.168.4.1
port: 8266,//默认端口为8266
});
指令发送
this.tcp.write('AT+CJWAP="WIFI账户名","WIFI密码"');
重启设备
this.tcp.write('AT+RST');
四、Demo页面源码
<template lang="html">
<view class="sin-home">
<view class="">
设备配网
</view>
<input v-model="form.name" type="text" placeholder="网络1名称" placeholder-class="placeholder" >
<input v-model="form.pwd" type="text" placeholder="密码" placeholder-class="placeholder" >
<view class="">
获取授权
</view>
<button @click="getconfirm()">getconfirm</button>
<view class="">
获取wifi
</view>
<button @click="getWIFI()">getWIFI</button>
<view class="">
测试配网
</view>
<button @click="startWifi()">startWifi</button>
<button @click="connectWifi()">connectWifi</button>
<button @click="connectTCP()">connectTCP</button>
<button @click="sendDataTCP()">sendDataTCP</button>
<button @click="sendRST()">sendRST</button>
<view>
{{tips}}
</view>
{{tips2}}
</view>
</template>
<script>
export default {
name: 'home',
data() {
return {
form: {
name: '',
result: '',
pwd: ''
},
tips:'暂无数据',
tips2:'未连接',
tcp:'',
}
},
computed: {
},
watch: {
},
onLoad() {
},
async onReady() {
},
onShow() {
},
// 下拉刷新
onPullDownRefresh:function(){
},
onPageScroll(e) {
},
methods: {
getconfirm(){
// 获取授权状态
uni.getSetting({
success: (res) => {
const hasLocationAuth = res.authSetting['scope.userLocation']
const hasAgreePrivacy = uni.getStorageSync('hasAgreePrivacy')
// 如果隐私和位置权限都已授权,直接返回
if (hasAgreePrivacy && hasLocationAuth) {
resolve(true)
return
}
// 处理隐私协议
if (!hasAgreePrivacy) {
uni.showModal({
title: '位置信息授权',
content: '获取WiFi列表需要位置权限,是否前往设置?',
confirmText: '去设置',
cancelText: '取消',
success: (modalRes) => {
if (modalRes.confirm) {
// 打开设置页面
uni.openSetting({
success: (settingRes) => {
resolve(!!settingRes.authSetting['scope.userLocation'])
},
fail: () => {
resolve(false)
}
})
} else {
resolve(false)
}
},
fail: () => {
resolve(false)
}
})
}
},
fail: () => {
resolve(false)
}
})
},
getWIFI(){
wx.getWifiList({
success(res) {
this.tips = JSON.stringify(res)
wx.onGetWifiList(function(res) {
console.log("获取wifi列表");
console.log(res.wifiList,102); //在这里提取列表数据
this.tips = JSON.stringify(res.wifiList)
})
},
fail(res) {
console.log(res)
//报错的相关处理
},
})
},
// 开启wifi
startWifi() {
console.log('开始wifi接口');
wx.startWifi({
complete (res) {
console.log(res)
}
})
},
// 链接wifi
connectWifi() {
uni.connectWifi({
SSID: 'YC3000_XXXX', // 设备热点名称
password: '',
success: (res) => { console.log("连接成功,开始TCP通信") },
fail: (err) => { console.log("连接失败", err) }
});
return
},
// 链接TCP
connectTCP() {
this.tcp = wx.createTCPSocket();
console.log('运行')
this.tcp.connect({
address: '192.168.4.1',
port: 8266,
});
},
// 发送命令-账号密码
sendDataTCP() {
this.tcp.write('AT+CJWAP="WIFI账户名","WIFI密码"');
},
// 发送命令-重启
sendRST(){
this.tcp.write('AT+RST');
},
}
}
</script>
<style lang="scss">
.sin-home{
padding: 50px 20px;
}
</style>
demo页面展示
五、注意
1、想要获取WiFi列表,必须授权获取位置信息。
2、开发者工具暂时不支持 调试,必须使用真机进行开发
3、使用手机手动切换连接设备热点会出问题,请使用connectWifi()链接