前言
1.有多少人一直在期盼着小程序可以实现SmartConfig或者Airkiss的功能? 来吧!我的这种方式包您满意.
注:APUConfig 是我自己取的名字(哈哈谁让这种方式,我是第一个在微信小程序上实现的),代表着 AP UDP Config
绑定流程详细说明:
实现功能概要
小程序使用APUConfig给Wi-Fi模块配网,并获取设备MAC等信息,然后通过MQTT控制绑定的Wi-Fi设备.
测试准备工作
一,下载单片机程序(请自行下载)
二,打开微信小程序软件,导入本节工程
三,把小程序安装到手机运行
四,调整波动开关位置,STM32和Wi-Fi 串口 通信
五,短接STM32的PB2和Wi-Fi模块的RST引脚(内部程序使用该引脚硬件复位Wi-Fi)
开始测试
一,点击小程序下方的添加设备按钮
二,选择添加Wi-Fi设备
三,输入路由器密码(注:Wi-Fi名称自动获取,也可自己填写)
四.长按PB5大约4S,等待指示灯快闪,松开PB5,Wi-Fi模块进入配网状态
五.点击小程序上的 "绑定设备"按钮,开始搜索设备,绑定成功,将自动跳转到主页面,显示绑定的Wi-Fi设备
5.1 正在尝试连接Wi-Fi模块的热点
5.2 连接上热点,正在和模块通信
5.3 成功绑定设备
六.点击设备,进入控制页面,控制设备
6.1 点击设备
6.2 控制继电器吸合
6.2 控制继电器断开
结语
希望能够为用小程序做物联网开发的大家解决当前最大的烦心事!
小程序端APUConfig源码:
.js
// pages/BindWiFiDevice/BindWiFiDevice.js var util = require("../../utils/util.js"); var APUConfigStart = false;//是否在配网 var APUConfigconnectAPCount = 0;//连接热点的次数 var APUConfigSendUDPDataIntervalNumber = 0;//发送UDP数据的定时器编号 var APUConfigSendUDPDataCount = 0;//发送UDP数据的次数 var udp; Page({ /** * 页面的初始数据 */ data: { ssid: ‘‘, password: ‘‘ }, // 获取路由器名称 ssidInput: function (e) { this.data.ssid = e.detail.value; }, // 获取输入密码 passwordInput: function (e) { this.data.password = e.detail.value; }, /** * 成功连接热点 */ connectWifiSuccess: function(res) { var _this = this; udp = wx.createUDPSocket()//启用UDP udp.bind() wx.hideLoading(); wx.showLoading({ title: ‘正在绑定‘ }) udp.onListening(function (res) { console.log(‘监听中...‘) console.log(res) }) //定时1S发送一次UDP数据 try { clearInterval(APUConfigSendUDPDataIntervalNumber); } catch (e) { } APUConfigSendUDPDataIntervalNumber = setInterval( function () { udp.send ({ address: ‘192.168.4.1‘, port: 5556, message: "{\"ssid\":" + "\"" + _this.data.ssid + "\"" + "\"pwd\":" + "\"" + _this.data.password + "\"" + "}" }) APUConfigSendUDPDataCount = APUConfigSendUDPDataCount + 1; console.log(‘发送数据: ‘ + "{\"ssid\":" + "\"" + _this.data.ssid + "\"" + "\"pwd\":" + "\"" + _this.data.password + "\"" + "}"); if (APUConfigSendUDPDataCount>20)//发送了20次,还没绑定上 { APUConfigSendUDPDataCount = 0; APUConfigconnectAPCount = 0; APUConfigStart = false;// udp.close(); wx.hideLoading(); wx.showModal({//弹出对话框 title: ‘绑定失败‘, content: ‘请重新尝试‘ }) } }, 1000, "null");//启动定时器 //UDP接收到消息 udp.onMessage(function (res) { console.log(res) let str = util.newAb2Str(res.message);//接收消息 console.log(‘str===‘ + str) //{ "mac": "dc:4f:22:10:b0:ce", "ip": "192.168.0.101" } try { clearInterval(APUConfigSendUDPDataIntervalNumber); } catch (e) { } try { udp.close(); } catch (e) { }//关闭UDP APUConfigSendUDPDataCount = 0; APUConfigconnectAPCount = 0; APUConfigStart = false;//复位所有变量 wx.hideLoading();//关闭提示框 if (str!=null) { let json = JSON.parse(str);//解析JSON数据 if (json != null) { let mac = json.mac; let ip = json.ip; if (mac != null) { wx.reLaunch({ url: ‘../index/index?ClientID=‘ + mac + "&" + "IP=" + ip }) } } } }) }, /** * 连接无线失败 */ connectWifiFail: function (res) { var _this = this; if (APUConfigconnectAPCount<6)//尝试连接热点的次数 { APUConfigconnectAPCount = APUConfigconnectAPCount + 1; console.log(‘连接Wi-Fi: wifi_8266_bind‘); wx.connectWifi//控制连接Wi-Fi无线信号 ({ SSID: "wifi_8266_bind", password: "11223344", success: _this.connectWifiSuccess, fail: _this.connectWifiFail }) } else { APUConfigconnectAPCount = 0; APUConfigStart = false;// wx.hideLoading(); wx.showModal({//弹出对话框 title: ‘绑定失败‘, content: ‘请重新尝试‘ }) } }, //点击绑定按钮 BindClick: function () { var _this = this; if (_this.data.ssid.length == 0 || _this.data.password.length == 0) { wx.showModal({//弹出对话框 title: ‘提示‘, content: ‘Wi-Fi名称和密码不能为空‘ }) } else { APUConfigStart = true;//开始配网 //控制连接Wi-Fi无线信号 wx.connectWifi ({ SSID: "wifi_8266_qqqqq_binding", password: "11223344", success: _this.connectWifiSuccess, fail: _this.connectWifiFail }) } }, /** * 生命周期函数--监听页面加载 */ onLoad: function (options) { var _this = this; _this.GetWiFiSSID();//显示当前连接的Wi-Fi名称 //启动网络状态监听 wx.onNetworkStatusChange(function (res) { console.log("绑定设备:网络改变" + res.isConnected + " " + res.networkType); if (res.networkType == "wifi")//当前连接的网络类型是WIFI { console.log("绑定设备:当前连接的网络类型是WIFI"); if (!APUConfigStart)//没在配网状态 { _this.GetWiFiSSID(); } } else//其它网络 { if (!APUConfigStart)//没在配网状态 { _this.setData({//清空显示的wifi名称 ssidValue: "" }) } } }) }, /** * 获取链接的WIFI名称 */ GetWiFiSSID: function () { var _this = this; wx.startWifi({//启用WIFI功能 success(res) { wx.getConnectedWifi//获取链接的Wi-Fi信息 ({ success(res) //获取到信息 { _this.data.ssid = res.wifi.SSID; console.log("绑定设备:连接的Wi-Fi名称 " + _this.data.ssid); _this.setData({ ssidValue: _this.data.ssid }) }, fail(res) { } }) } }) }, /** * 生命周期函数--监听页面显示 */ onShow: function () { this.GetWiFiSSID();//显示当前连接的Wi-Fi名称 }, /** * 生命周期函数--监听页面卸载 */ onUnload: function () { try { clearInterval(APUConfigSendUDPDataIntervalNumber); } catch (e) { } try { udp.close(); } catch (e) { } APUConfigSendUDPDataCount = 0; APUConfigconnectAPCount = 0; APUConfigStart = false;// wx.hideLoading(); }, /** * 生命周期函数--监听页面隐藏 */ onHide: function () { }, /** * 页面相关事件处理函数--监听用户下拉动作 */ onPullDownRefresh: function () { }, /** * 页面上拉触底事件的处理函数 */ onReachBottom: function () { }, /** * 用户点击右上角分享 */ onShareAppMessage: function () { } })
.json
{ "usingComponents": {} }
.wxml
<!--pages/BindWiFiDevice/BindWiFiDevice.wxml--> <view class="container"> <!--提示--> <view class="hint"> <text style="color: #545454; font-size:35rpx;">绑定设备前请确定完成以下步骤</text> <view> <text style="color:#09bb07; font-size:35rpx;">①</text> <text style="font-size:35rpx;" space=‘nbsp‘> 请先连接自家路由器热点</text> </view> <view> <text style="color:#09bb07; font-size:35rpx;">②</text> <text style="font-size:35rpx;" space=‘nbsp‘> 给设备上电</text> </view> <view> <text style="color:#09bb07; font-size:35rpx;">③</text> <text style="font-size:35rpx;" space=‘nbsp‘> 长按"配置按键"大约3S,直至指示灯快闪</text> </view> <view> <text style="color:#09bb07; font-size:35rpx;">④</text> <text style="font-size:35rpx;" space=‘nbsp‘> 输入路由器密码,点击“添加设备”按钮</text> </view> <view> <text style="color:#09bb07; font-size:35rpx;" >⑥</text> <text style="font-size:35rpx;" space=‘nbsp‘> 绑定成功后,软件自动跳转到设备页面</text> </view> </view> <view class="login-from"> <!--WiFi名称--> <view class="inputView"> <label class="loginLab">WiFi名称:</label> <input class="inputText" placeholder="请输入路由器热点" bindinput="ssidInput" value="{{ssidValue}}"/> </view> <view class="line"></view> <!--WiFi密码--> <view class="inputView"> <label class="loginLab">WiFi密码:</label> <input class="inputText" placeholder="请输入密码" bindinput="passwordInput"/> </view> <!--按钮--> <view class="BindClickView"> <button class="BindClick" type="primary" bindtap="BindClick">绑定设备</button> </view> </view> </view>
.WXSS
/* pages/BindWiFiDevice/BindWiFiDevice.wxss */ page{ height: 100%; } .container { height: 100%; display: flex; flex-direction: column; padding: 0; box-sizing: border-box; background-color: #f2f2f2 } /*提示信息*/ .hint { display: flex; flex-direction: column; margin-top: 10rpx } /*表单内容*/ .login-from { margin-top: 50px; width: 90%; flex: auto; height:100%; } .inputView { display: flex; flex-direction: row; background-color: #fff; } /*Wi-Fi名称和密码两个字*/ .loginLab { margin-left: 10px; margin-top: 15px; margin-bottom: 15px; color: #545454; font-size: 16px } .inputText { margin-left: 10px; text-align: left; margin-top: 15px; color: black; font-size: 16px } .line { width: 100%; height: 1px; background-color: #cccccc; margin-top: 1px; } /*按钮*/ .BindClickView { width: 100%; height: auto; background-color: #f2f2f2; margin-top: 0px; margin-bottom: 0px; padding-bottom: 0px; } .BindClick { width: 95%; margin-top: 35px; }
const formatTime = date => { const year = date.getFullYear() const month = date.getMonth() + 1 const day = date.getDate() const hour = date.getHours() const minute = date.getMinutes() const second = date.getSeconds() return [year, month, day].map(formatNumber).join(‘/‘) + ‘ ‘ + [hour, minute, second].map(formatNumber).join(‘:‘) } const formatNumber = n => { n = n.toString() return n[1] ? n : ‘0‘ + n } // util.newAb2Str代码 var newAb2Str = function newAb2Str(arrayBuffer) { let unit8Arr = new Uint8Array(arrayBuffer); let encodedString = String.fromCharCode.apply(null, unit8Arr), decodedString = decodeURIComponent(escape((encodedString)));//没有这一步中文会乱码 return decodedString; } module.exports = { formatTime: formatTime, newAb2Str: newAb2Str }
单片机端APUConfig,Wi-Fi配置流程
/** ****************************************************************************** * @author yang feng wu * @version V1.0.0 * @date 2019/10/12 * @brief 配置8266 ****************************************************************************** 一,使用说明:指示灯(PC13) 1,把以下程序放在1ms定时器中断中 SmartConfigCnt++; if(SmartConfigFlage)//配网状态,指示灯闪耀 { Config8266LedDelay++; if(Config8266LedDelay>100) { Config8266LedDelay=0; SmartConfigPinOut = ~SmartConfigPinOut; } } else { Config8266LedDelay=0; } 2,调用使用,建议使用一个按钮控制 if(SmartConfig())//配网成功 { //执行操作 } ****************************************************************************** APUConfig配网绑定流程 设备端 1.获取设备MAC XX:XX:XX:XX:XX:XX 2.控制WIFI发出固定无线网 名称:wifi_8266_bind 密码:11223344 3.UDP 监听固定端口5556 4.等待接收客户端的消息. 消息格式{"ssid":"qqqqq","pwd":"11223344"} 5.提取路由器名称和密码,连接路由器 6.获取链接路由器后分的的IP. 假设是192.168.10.2 以防后期实现局域网通信备用 7.UDP发送数据,{"mac":"XX:XX:XX:XX:XX:XX","ip":"192.168.10.2"} APP/小程序/上位机 1.提示用户连接自己的路由器,长按设备按钮使得设备进入UDP监听状态,提示用户输入路由器密码 2.用户点击绑定设备 , 控制手机尝试连接 名称为 wifi_8266_bind 的无线 (内部控制) 3.成功连接无线,往192.168.4.1:5556 UDP发送路由器信息,1S 1次 4.接收到 {"mac":"XX:XX:XX:XX:XX:XX","ip":"192.168.10.2"} 5.绑定成功 8.完 */ #define CONFIG8266_C_ #include "include.h" char SmartConfigFlage = 0;//是不是在配网 u32 SmartConfigCnt = 0;//配网连接路由器延时使用 char SmartConfigSuccess = 0;//是否配网成功 u32 Config8266Delay=0;//执行Config8266函数内部所需延时 u32 Config8266LedDelay=0;//配置8266指示灯闪耀 char ThisSSID[32]="";//记录路由器名称 char ThisPWD[64]="";//记录密码 char ThisMAC[18]="";//记录设备MAC char ThisIP[21]="";//记录设备连接路由器分得的IP /** * @brief 启用APUConfig 给WIFI配网 * @ warn None * @param None * @param None * @param None * @param None * @retval 1:成功 * @example **/ char APUConfig(void) { u32 delay=0,Flage=0; SmartConfigPinOut = 1; SmartConfigSuccess = 0; Rst8266(); if(ConfigModuleBlock("+++","+++",NULL))//退出透传 { if(ConfigModuleBlock("AT+RESTORE\r\n","ready",NULL))//恢复出厂设置 { if(ConfigModuleBlock("AT+CWMODE_DEF=3\r\n","OK",NULL))//模式3 { if(ConfigModuleBlock("AT+CIPSTAMAC_CUR?\r\n","MAC_CUR",NULL))//MAC { MainString = StrBetwString(Usart1ReadBuff,"MAC_CUR:\"","\"");//得到MAC if(strlen(MainString) ==17) { memset(ThisMAC,0,sizeof(ThisMAC)); memcpy(ThisMAC,MainString,17); } else {goto end;} cStringRestore(); if(ConfigModuleBlock("AT+CWSAP_DEF=\"wifi_8266_bind\",\"11223344\",11,4,4\r\n","OK",NULL))//配置发出的无线 { if(ConfigModuleBlock("AT+CIPSTART=\"UDP\",\"192.168.4.2\",5555,5556,2\r\n","OK",NULL))//配置UDP { SmartConfigCnt = 0; while(1) { //{"ssid":"qqqqq","pwd":"11223344"} //{"mac":"XX:XX:XX:XX:XX:XX","ip":"192.168.10.2"} //*StrBetwString(char *Str,char *StrBegin,char *StrEnd) IWDG_Feed();//喂狗 if(Usart1ReadFlage==1) { Usart1ReadFlage=0; MainString = StrBetwString(Usart1ReadBuff,"\"ssid\":\"","\"");//获取ssid if(MainString!=NULL) { memset(ThisSSID,0,sizeof(ThisSSID)); sprintf(ThisSSID,"%s",MainString); cStringRestore(); MainString = StrBetwString(Usart1ReadBuff,"\"pwd\":\"","\"");//获取pwd if(MainString!=NULL) { memset(ThisPWD,0,sizeof(ThisPWD)); sprintf(ThisPWD,"%s",MainString); cStringRestore(); break; } else {goto end;} } else {goto end;} } if(SmartConfigCnt>60000) {goto end;}//60S超时 } if(ConfigModuleBlock("AT+CWAUTOCONN=1\r\n","OK",NULL))//自动连接路由器 { memset(MainBuffer,0,sizeof(MainBuffer)); sprintf(MainBuffer,"AT+CWJAP_DEF=\"%s\",\"%s\"\r\n",ThisSSID,ThisPWD); if(ConfigModuleBlock(MainBuffer,"WIFI GOT IP",NULL))//设置连接的路由器 { Flage = 1;//配网成功 SmartConfigSuccess=1; if(ConfigModuleBlock("AT+CIPSTA_CUR?\r\n","CIPSTA_CUR:ip",NULL))//获取路由器分得的IP { MainString = StrBetwString(Usart1ReadBuff,"CUR:ip:\"","\"");//得到路由器分得的IP if(MainString != NULL) { memset(ThisIP,0,sizeof(ThisIP)); memcpy(ThisIP,MainString,strlen(MainString)); split(MainString,".",NULL,&MainLen);//XXX.XXX.XXX.XXX if(MainLen == 4) { MainLen = sprintf(MainBuffer,"{\"mac\":\"%s\",\"ip\":\"%s\"}",ThisMAC,ThisIP); MainLen = sprintf(MainBuffer,"AT+CIPSEND=%d\r\n",MainLen); if(ConfigModuleBlock(MainBuffer,">",NULL))//准备向UDP客户端发送消息 { memset(MainBuffer,0,sizeof(MainBuffer)); MainLen = sprintf(MainBuffer,"{\"mac\":\"%s\",\"ip\":\"%s\"}",ThisMAC,ThisIP); printf("%s",MainBuffer); SmartConfigCnt = 0; while(SmartConfigCnt<3000) { IWDG_Feed();//喂狗 } }else {goto end;} }else {goto end;} }else {goto end;} cStringRestore(); } } } } } } } } } end: if(ConfigModuleBlock("AT+CWMODE_DEF=1\r\n","OK",NULL))//模式1 {} Rst8266();//复位 SmartConfigFlage = 0; return Flage; }
绑定成功后跳转
知识在于灵活的运用!!!!!
ESA2GJK1DH1K微信小程序篇: 测试微信小程序APUConfig给WI-Fi模块配网并绑定设备,并通过MQTT控制设备