智能家居小程序softAP配网功能实现

2,199 阅读2分钟

上一个项目一直在做智能家居的小程序和后台管理系统,现在整理一下其中最关键的配网步骤。

softAP的配网原理

配网流程图:

softAP配网原理.png

softAP配网,即利用设备的无线芯片,将设备进入到softAP模式,开启一个无线局域网,手机(或其它移动设备)通过连入设备开启的无线局域网后,向设备发送路由器的ssid及password等信息,让设备在无屏幕的情况下,获取到路由器的ssid信息,达到联网的目的。 上面的流程图简单的画了一下,下面我大概讲一下具体的配网步骤\

配网步骤总共需要4步

  1. 智能家居设备需要长按特定的按键进入配网模式,这个时候设备会启动wifi模块释放wifi(不同的设备进入配网的方式不一样) WechatIMG887.jpeg
  2. 小程序进入配网界面,输入当前家庭连接的wifi密码,记录家庭wifi的名字和密码(可以直接通过小程序的API直接获取到当前手机连接的wifi名字) WechatIMG890.jpeg
  3. 手机进行网络切换,连接设备释放的wifi,然后进行UDP通信,把wifi名字和密码发送给设备端,设备端通过名字密码连接家庭wifi和服务器进行通信(UDP通信发送名字密码可以做自定义的加密处理降低抓包风险) WechatIMG891.jpeg 4.小程序通过调服务器接口查询智能设备是否配网成功(查询参数加密MD5、设备devId、userId)

softAP实现的代码

// 配网
async getDevice() {
    let that = this;
    this.setData({
      isOnload: false
    })
    wx.showToast({
      title: '配网时长在1-2分钟,请耐心等待!',
      icon: 'none',
      duration: 2000
    })
    setTimeout(() => {
      wx.showLoading({
        title: '配网中',
      })
    }, 2000)
    // 开始配网
    let ASCIIStr = `${String.fromCharCode(util.prefixInteger(that.data.SSID.length, 2))}${that.data.SSID}${String.fromCharCode(util.prefixInteger(that.data.password.length, 2))}${that.data.password}`

      let ASCIIStrMi = 0;
      for (var i = ASCIIStr.length - 1; i >= 0; i--) {
        var str = ASCIIStr.charAt(i);
        var code = str.charCodeAt();
        ASCIIStrMi += code;
      }

      that.UDPSocketHandler = wx.createUDPSocket(),
      that.UDPSocketHandler.bind();
      var times = setInterval(() => {
        try {
          that.UDPSocketHandler.send({
            address: "10.10.100.000",
            port: 12414,
            message: `${ASCIIStr}${String.fromCharCode(ASCIIStrMi % 256)}`,
            offset: 0,
            // length: message.byteLength
          })
        } catch (e) { }
      }, 1000); //1000:每1秒轮询一次
      that.UDPSocketHandler.onListening(function (res) {
        console.log(res, '监听中...')
      })
      that.UDPSocketHandler.onMessage(function (res) {
        let str = util.newAb2Str(res.message);
        that.setData({
          udpCode: str.replace("RECVDONE", "")
        });
        console.log('str===' + str)
        if (str.indexOf("RECVDONE") !== -1) {
          clearInterval(times);
          that.UDPSocketHandler.close();
          that.distributionNetwork();
          console.log('RECVDONE !== 1','配网中');
        }
      })
      that.UDPSocketHandler.onError(function (res) {
        console.log(res, 'error');
      })
  },


  getuserDev(index) {
    let that = this;
    if (index > 19) {
      wx.hideLoading();
      wx.showToast({
        title: '配网超时',
        icon: 'none',
        duration: 2000
      });
      return;
    }
    index++;
    let md5Str = md5.md5(`${that.data.SSID}${that.data.password}${that.data.udpCode}`)

    let data = {
      userId: app.globalData.unionId,
      wifiMd5: md5Str,
      devId: that.data.udpCode,
    }
    console.log("配网",data)
    global.api.devNetwork(data).then(res => {
      console.log("res", res);
      if (res.code == 200 && res.rows !== null) {
        clearInterval(that.data._time);
        wx.hideLoading();
        wx.showToast({
          title: '配网成功',
          icon: 'none',
          duration: 2000
        });
        wx.navigateTo({
          url: '/xxxx/xxxx/xxxx/xxxx/xxxxxx/index?data=' + JSON.stringify(res.rows) + '&equipment=' + that.data.equipment + '&ps=' + that.data.ps,
        });
      } else {
        setTimeout(() => {
          that.getuserDev(index);
        }, 5000)
      }
    })
      .catch(err => {
        setTimeout(() => {
          that.getuserDev(index);
        }, 5000)
      })
  },

  distributionNetwork() {
    var that = this;
    wx.showLoading({
      title: '配网中',
    });
    that.getuserDev(0);
  },

上面这部分只是具体的逻辑实现,像调用的小程序获取wifi信息的API就不往上放了。