== 注意:UDP连接只能在局域网才能连接成功 ==
- 设备配网,首先获取当前WIFI
- 页面加载之后自动获取当前手机连接的WiFi名字
- 点击获取更多网络,获取附近可以搜到的WiFi列表
- 选择一个WiFi名字,输入对应密码,点击连接按钮进行配网
- 点击连接按钮,需要切换到设备发出WiFi(设备定死的WiFi名字和密码,不能上网),自动连接,在连接成功的回调里进行后续UDP连接
- 通过固定的设备ip和端口号进行UDP连接
- 连接成功后,将当前环境的WiFi名称和密码加密后发送给设备
- 设备收到后并去连接我们发送的WiFi,如果连接成功会返回当前设备信息
- 设备连接成功就会断开设备WiFi,手机会自动切换到当前环境下的WiFi,将设备信息调取接口存入数据库
问题:有可能网络还没有切换回来之前就调了接口,导致接口没有调成功
方案:收到的设备信息先缓存到本地,延迟10秒调取接口,如果成功接口返回设备id,就清理缓存
小程序每次进来判断本地是否有缓存,如果有去掉接口 - 若长时间收不到设备的反馈信息,就说明配网失败
<view>
<view class="mtb-100 plr-32">
<view class="bold">配网说明</view>
<view class="gray-3 mt-20">连接设备的提供的热点,输入wifi信息,即可进入配网。
设备不支持5G网络。</view>
</view>
<!-- 账号 -->
<view class="pd-60">
<view>
<view class="size-32 bold mb-10">WIFI名称</view>
<view class="flex bb">
<image src="/assets/imgs/net-1.png" mode="widthFix" style="width:48rpx;height:48rpx"></image>
<input disabled class="ptb-10 flex-1 ml-20" type="text" model:value="{{name}}" placeholder="请选择WiFi名称" />
<view bindtap="search" class="green">更多网络</view>
</view>
</view>
<view class="mt-40">
<view class="size-32 bold mb-10">WiFi密码</view>
<view class="flex bb">
<image src="/assets/imgs/net-2.png" mode="widthFix" style="width:48rpx;height:48rpx"></image>
<input wx:if="{{!show}}" class="ptb-10 flex-1 ml-20" type="password" model:value="{{pwd}}"
placeholder="请输入密码" />
<input wx:else class="ptb-10 flex-1 ml-20" type="text" model:value="{{pwd}}" placeholder="请输入密码" />
<view bindtap="showPwd" class="flex_r pr-20 pt-20" style="width:120rpx;height:80rpx">
<image wx:if="{{!show}}" src="/assets/imgs/hide.png" style="width:40rpx;height:40rpx"></image>
<image wx:else src="/assets/imgs/show.png" style="width:40rpx;height:40rpx"></image>
</view>
</view>
</view>
</view>
<!-- 连接按钮 -->
<view class="plr-50 pt-100">
<view bindtap="connect" class="bg-green white center ptb-25 size-32 radius-20">连接</view>
</view>
<!-- wifi列表 -->
<van-action-sheet show="{{ showWifi }}" actions="{{ list }}" bind:close="onClose" bind:select="onSelect"
style="max-height:200rpx" />
</view>
// pages/login/index.js
let CryptoJS = require('./aes.js'); //引用AES源码js
console.log(CryptoJS)
Page({
/**
* 页面的初始数据
*/
data: {
// TODO
name: 'suoan858',
pwd: 'suoan858',
show: false, //显示密码
list: [], //WiFi列表
showWifi: false
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
this.search(1)
},
// 显示隐藏密码
showPwd() {
this.setData({
show: !this.data.show
})
},
search(type) {
let _this = this
wx.getSetting({
success(res) {
if (!res.authSetting['scope.userLocation']) {
wx.authorize({
scope: 'scope.userLocation',
}).then(data => {
_this.getWifi(type)
})
} else {
_this.getWifi(type)
}
}
})
},
getWifi(type) {
let _this = this
wx.showLoading({
title: '搜索WiFi中...'
})
wx.startWifi({
success(res) {
if (type == 1) {
wx.getConnectedWifi({
success: function (e) {
wx.hideLoading()
_this.setData({
name: e.wifi.SSID
})
}
})
} else {
wx.getWifiList({
success(res) {
wx.hideLoading()
wx.onGetWifiList(function (res) {
if (res.wifiList.length == 0) {
wx.showToast({
title: '没有搜索到WiFi信息',
icon: 'error'
})
} else {
res.wifiList.forEach(item => {
item.name = item.SSID
})
_this.setData({
list: res.wifiList,
showWifi: true
})
}
})
},
fail() {
wx.hideLoading()
wx.showToast({
title: '获取WiFi失败',
icon: 'error'
})
}
})
}
},
fail() {
wx.hideLoading()
wx.showToast({
title: '获取WiFi失败',
icon: 'error'
})
}
})
},
onClose() {
this.setData({
showWifi: false
});
},
onSelect(event) {
console.log(event.detail);
this.setData({
name: event.detail.name,
showWifi: false
})
},
// 连接
connect() {
let flag = false
let {
pwd,
name
} = this.data
if (!name) {
wx.showToast({
title: '请选择WiFi名称',
icon: 'none'
})
} else if (!pwd) {
wx.showToast({
title: '请输入密码',
icon: 'none'
})
} else {
let _this = this
// 切换到设备WiFi
// TODO
wx.connectWifi({
SSID: 'ESP8266_JX',
password: 'jixiaoxin',
forceNewApi: true,
success(res) {
console.log('连接设备WIFI成功', res.errMsg)
// AES加密ECB模式
let data = _this.AesEncrypt(JSON.stringify({
wifi: _this.data.name,
password: _this.data.pwd,
host: "121.36.221.107",
port: 1883,
liveTime: "300"
}))
// let data = '11/8jVVMeLxH57dvSJacnmmeRLJhLlShL4Zy1KS/wPyKlnrK6+/DCDevUKzPhYWj7qUK0c'
console.log('加密的传输数据', data)
// udp 连接设备
wx.showLoading({
title: '设备配网中...',
})
const udp = wx.createUDPSocket();
udp.bind();
// TODO
udp.send({
address: '192.168.6.18',
port: 7681,
message: data
});
udp.onMessage((res) => {
flag = true
//bufferArry数据转换为对象
let unit8Arr = new Uint8Array(res.message)
let encodedString = String.fromCharCode.apply(null, unit8Arr)
let message = decodeURIComponent(escape(encodedString))
message = message.substring(0, message.length - 1);
// 对收到的数据进行解密
message = JSON.parse(_this.AesDecrypt(message))
console.log('解密的数据', message)
// 存储设备返回的设备信息
let arr = JSON.parse(wx.getStorageSync('deviceInfo') || "[]")
console.log(222, arr)
arr.push(message)
console.log(333, arr)
wx.setStorageSync('deviceInfo', JSON.stringify(arr))
if (message.code == 0) {
udp.close()
wx.hideLoading()
wx.navigateTo({
url: '../net-result/index?type=1',
})
setTimeout(() => {
wx.http('/equipment/addEquipment', message, "POST").then(data => {
console.log('接口调用成功,设备id', data)
// 接口成功删除该条信息
let arr1 = JSON.parse(wx.getStorageSync('deviceInfo'))
console.log(4444, arr1)
arr1.forEach((item, i) => {
if (item.deviceId == data) {
arr1.splice(i, 1)
console.log(55555, arr1)
wx.setStorageSync('deviceInfo', JSON.stringify(arr1))
}
})
})
}, 5000)
} else {
udp.close()
wx.hideLoading()
wx.navigateTo({
url: '../net-result/index?type=2',
})
}
});
setTimeout(() => {
console.log(flag)
if (!flag) {
udp.close()
wx.hideLoading()
wx.navigateTo({
url: '../net-result/index?type=2',
})
}
}, 20000)
},
fail(err) {
console.log(err)
wx.showToast({
title: '请手动切换到设备WIFI',
icon: 'none'
})
wx.showModal({
title: '温馨提示',
content: '当前机型不支持自动切换设备WiFi,请参照用户手册手动切换,然后重新配网',
success(res) {
if (res.confirm) {} else if (res.cancel) {}
}
})
}
})
}
},
/**
* aes 加密方法
*/
AesEncrypt(data) {
var key = "1234123412341234";
var keyHex = CryptoJS.enc.Utf8.parse(key);
var encrypted = CryptoJS.AES.encrypt(data, keyHex, {
iv: [],
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
var encryptData = encrypted.ciphertext.toString().toUpperCase();
// 转为hex格式,转为Base64的字符串
var oldHexStr = CryptoJS.enc.Hex.parse(encryptData);
// 将密文转为Base64的字符串
var base64Str = CryptoJS.enc.Base64.stringify(oldHexStr);
return base64Str
},
/**
* aes 解密方法
*/
AesDecrypt(decodedData) {
var key = "1234123412341234";
var keyHex = CryptoJS.enc.Utf8.parse(key);
var decrypted = CryptoJS.AES.decrypt({
// ciphertext: CryptoJS.enc.Hex.parse(decodedData) //非base64的数据
ciphertext: CryptoJS.enc.Base64.parse(decodedData) // base64格式的数据
}, keyHex, {
iv: [],
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
var decryptedData = decrypted.toString(CryptoJS.enc.Utf8);
console.log("解密之后的结果:" + decryptedData);
return decryptedData
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
CryptoJS
后来修改后的js代码
// pages/login/index.js
let CryptoJS = require('./aes.js'); //引用AES源码js
console.log(CryptoJS)
Page({
/**
* 页面的初始数据
*/
data: {
// TODO
name: '',
pwd: '',
show: false, //显示密码
list: [], //WiFi列表
showWifi: false,
flag: false, // 配网是否成功
isWifi: false, // 当前连接的wifi名字是否正确
timer: null,
listener: null
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
this.search(1)
},
// 显示隐藏密码
showPwd() {
this.setData({
show: !this.data.show
})
},
search(type) {
let _this = this
wx.getSetting({
success(res) {
if (!res.authSetting['scope.userLocation']) {
wx.authorize({
scope: 'scope.userLocation',
}).then(data => {
_this.getWifi(type)
})
} else {
_this.getWifi(type)
}
}
})
},
getWifi(type) {
let _this = this
wx.showLoading({
title: '搜索WiFi中...'
})
wx.startWifi({
success(res) {
if (type == 1) {
wx.getConnectedWifi({
success: function (e) {
wx.hideLoading()
_this.setData({
name: e.wifi.SSID
})
}
})
} else {
wx.getWifiList({
success(res) {
wx.hideLoading()
wx.onGetWifiList(function (res) {
if (res.wifiList.length == 0) {
wx.showToast({
title: '没有搜索到WiFi信息',
icon: 'error'
})
} else {
res.wifiList.forEach(item => {
item.name = item.SSID
})
_this.setData({
list: res.wifiList,
showWifi: true
})
}
})
},
fail() {
wx.hideLoading()
wx.showToast({
title: '获取WiFi失败',
icon: 'error'
})
}
})
}
},
fail() {
wx.hideLoading()
wx.showToast({
title: '获取WiFi失败',
icon: 'error'
})
}
})
},
onClose() {
this.setData({
showWifi: false
});
},
onSelect(event) {
console.log(event.detail);
this.setData({
name: event.detail.name,
showWifi: false
})
},
// 点击配网
connect() {
this.flag = false
let {
pwd,
name
} = this.data
if (!name) {
wx.showToast({
title: '请选择WiFi名称',
icon: 'none'
})
} else if (!pwd) {
wx.showToast({
title: '请输入密码',
icon: 'none'
})
} else {
// TODO:连接设备WiFi
this.createUDP()
}
},
createUDP() {
const udp = wx.createUDPSocket();
const port = udp.bind()
// AES加密ECB模式
let data = this.AesEncrypt(JSON.stringify({
wifi: this.data.name,
password: this.data.pwd,
host: "121.36.221.107",
port: 1883,
liveTime: "300",
udpPort: port
}))
// 连接设备WIFI
this.connectWifi(udp, data)
// 连接wifi失败重新连接
if (this.data.timer) {
clearInterval(this.data.timer)
this.setData({
timer: null
})
} else {
let timerF = () => {
if (!this.data.isWifi) {
console.log('重新连接', this.data.isWifi)
wx.offWifiConnected(this.data.listener)
this.connectWifi(udp, data)
} else {
this.closeTimer()
}
}
this.setData({
timer: setInterval(timerF, 20000)
})
}
// 2分钟没连上跳转失败
setTimeout(() => {
if (!this.data.flag) {
this.closeTimer()
udp.close()
wx.hideLoading()
wx.offWifiConnected(this.data.listener)
wx.navigateTo({
url: '../net-result/index?type=2',
})
}
}, 120000)
},
closeTimer() {
clearInterval(this.data.timer)
this.setData({
timer: null
})
},
connectWifi(udp, data) {
let _this = this;
wx.connectWifi({
SSID: 'ESP8266_JX',
password: 'jixiaoxin',
forceNewApi: true,
success(res) {
console.log('连接设备WIFI成功', res)
wx.showLoading({
title: '设备配网中...',
})
let listener = (res) => {
console.log('连接上 Wi-Fi 的事件的监听函数' + res.wifi.SSID, res)
if (res.wifi.SSID == 'ESP8266_JX') {
_this.setData({
isWifi: true
})
// TODO
udp.send({
address: '192.168.6.18',
port: 7681,
message: data,
setBroadcast: true
});
}
}
_this.setData({
listener: listener
})
wx.onWifiConnected(_this.data.listener)
udp.onMessage((res) => {
//bufferArry数据转换为对象
let unit8Arr = new Uint8Array(res.message)
let encodedString = String.fromCharCode.apply(null, unit8Arr)
let message = decodeURIComponent(escape(encodedString))
message = message.substring(0, message.length - 1);
// 对收到的数据进行解密
message = JSON.parse(_this.AesDecrypt(message))
console.log('收到解密后的数据', message)
if (message.code == 0) {
// 存储设备返回的设备信息
let arr = JSON.parse(wx.getStorageSync('deviceInfo') || "[]")
arr.push(message)
wx.setStorageSync('deviceInfo', JSON.stringify(arr))
_this.setData({
flag: true,
})
udp.close()
_this.closeTimer()
wx.hideLoading()
wx.offWifiConnected(_this.data.listener)
wx.navigateTo({
url: '../net-result/index?type=1',
})
// setTimeout(() => {
// wx.http('/equipment/addEquipment', message, "POST").then(data => {
// console.log('接口调用成功,设备id', data)
// // 接口成功删除该条信息
// let arr1 = JSON.parse(wx.getStorageSync('deviceInfo'))
// arr1.forEach((item, i) => {
// if (item.deviceId == data) {
// arr1.splice(i, 1)
// wx.setStorageSync('deviceInfo', JSON.stringify(arr1))
// }
// })
// })
// }, 5000)
} else {
udp.close()
_this.closeTimer()
wx.hideLoading()
wx.offWifiConnected(_this.data.listener)
wx.navigateTo({
url: '../net-result/index?type=2',
})
}
});
},
fail(err) {
console.log('连接WIFi失败', err)
wx.showModal({
title: '温馨提示',
content: '当前机型不支持自动切换设备WiFi,请参照用户手册手动切换,然后重新配网',
success(res) {
if (res.confirm) {} else if (res.cancel) {}
}
})
},
})
},
/**
* aes 加密方法
*/
AesEncrypt(data) {
var key = "1234123412341234";
var keyHex = CryptoJS.enc.Utf8.parse(key);
var encrypted = CryptoJS.AES.encrypt(data, keyHex, {
iv: [],
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
var encryptData = encrypted.ciphertext.toString().toUpperCase();
// 转为hex格式,转为Base64的字符串
var oldHexStr = CryptoJS.enc.Hex.parse(encryptData);
// 将密文转为Base64的字符串
var base64Str = CryptoJS.enc.Base64.stringify(oldHexStr);
return base64Str
},
/**
* aes 解密方法
*/
AesDecrypt(decodedData) {
var key = "1234123412341234";
var keyHex = CryptoJS.enc.Utf8.parse(key);
var decrypted = CryptoJS.AES.decrypt({
// ciphertext: CryptoJS.enc.Hex.parse(decodedData) //非base64的数据
ciphertext: CryptoJS.enc.Base64.parse(decodedData) // base64格式的数据
}, keyHex, {
iv: [],
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
var decryptedData = decrypted.toString(CryptoJS.enc.Utf8);
console.log("解密之后的结果:" + decryptedData);
return decryptedData
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})