微信小程序udp通信连接硬件设备配网

== 注意:UDP连接只能在局域网才能连接成功 ==

  1. 设备配网,首先获取当前WIFI
    1. 页面加载之后自动获取当前手机连接的WiFi名字
    2. 点击获取更多网络,获取附近可以搜到的WiFi列表
    3. 选择一个WiFi名字,输入对应密码,点击连接按钮进行配网
  2. 点击连接按钮,需要切换到设备发出WiFi(设备定死的WiFi名字和密码,不能上网),自动连接,在连接成功的回调里进行后续UDP连接
  3. 通过固定的设备ip和端口号进行UDP连接
  4. 连接成功后,将当前环境的WiFi名称和密码加密后发送给设备
  5. 设备收到后并去连接我们发送的WiFi,如果连接成功会返回当前设备信息
  6. 设备连接成功就会断开设备WiFi,手机会自动切换到当前环境下的WiFi,将设备信息调取接口存入数据库
    问题:有可能网络还没有切换回来之前就调了接口,导致接口没有调成功
    方案:收到的设备信息先缓存到本地,延迟10秒调取接口,如果成功接口返回设备id,就清理缓存
    小程序每次进来判断本地是否有缓存,如果有去掉接口
  7. 若长时间收不到设备的反馈信息,就说明配网失败
    在这里插入图片描述
<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 () {

  }
})
  • 0
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小曲曲

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值