专栏首页知识分享ESA2GJK1DH1K微信小程序篇: 测试微信小程序APUConfig给WI-Fi模块配网并绑定设备,并通过MQTT控制设备

ESA2GJK1DH1K微信小程序篇: 测试微信小程序APUConfig给WI-Fi模块配网并绑定设备,并通过MQTT控制设备

前言

  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;
}

绑定成功后跳转

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • ESP8266 SDK开发: 综合篇-C#上位机串口通信控制ESP8266

    https://www.cnblogs.com/yangfengwu/p/12382103.html   编写C#串口调试助手

    杨奉武
  • STM32远程乒乓升级,升级流程源码详细说明

      2.其实主要的就是把程序文件写入环形队列,然后环形队列取出来数据写入Flash

    杨奉武
  • GPRS(Air202) Lua开发: GPIO输出高低电平

    如果设置GPIO0 - GPIO31管脚,则第一个参数填写 pio.P0_0 - pio.P0_31

    杨奉武
  • JavaScript笔记整理

    整理一篇工作中的JavaScript脚本笔记,不定时更新,笔记来自网上资料或者自己经验归纳。

    用户1208223
  • javascript_时间自动刷新

    =========================================================

    Hongten
  • LintCode 最后一个单词的长度题目分析代码

    给定一个字符串, 包含大小写字母、空格' ' ,请返回其最后一个单词的长度。 如果不存在最后一个单词,请返回 0 。

    desperate633
  • 算法:有效括号

    版权声明: ...

    Fisherman渔夫
  • Spring AOP 注解方式源码解析

    在上篇文章 Spring AOP 功能使用详解 中,知道了 Sprig AOP 的一个详细用法,现在的看看Spring 中是如何实现的。

    Java技术大杂烩
  • libuv之unix域的使用

    之前分析了unix域在libuv的基本原理。今天以一个简单的例子看一下如何使用它。本文涉及到一些网络编程的知识,不过文章不打算讲解这些,如果不了解可以先了解一下...

    theanarkh
  • Spring AOP 源码分析 - 筛选合适的通知器

    从本篇文章开始,我将会对 Spring AOP 部分的源码进行分析。本文是 Spring AOP 源码分析系列文章的第二篇,本文主要分析 Spring AOP ...

    田小波

扫码关注云+社区

领取腾讯云代金券