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;
}
util.js
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;
}
绑定成功后跳转