【微信小程序控制硬件⑦ 进阶篇】动起来作一个微信小程序Mqtt协议控制智能硬件的框架,为内心全栈工程师梦想浇水!

微信小程序控制硬件第1篇 】 全网首发,借助 emq 消息服务器带你如何搭建微信小程序的mqtt服务器,轻松控制智能硬件!
微信小程序控制硬件第2篇 】 开始微信小程序之旅,导入小程序Mqtt客户端源码,实现简单的验证和通信于服务器!
微信小程序控制硬件第3篇 】 从软件到硬件搭建一个微信小程序控制esp8266的项目,自定义通信协议,为面试职位和比赛项目加分!
微信小程序控制硬件第4篇 】 深度剖析微信公众号配网 Airkiss 原理与过程,esp8266如何自定义回调参数给微信,实现绑定设备第一步!
微信小程序控制硬件第5篇 】理清接下来必须走的架构思想,学习下 JavaScript 的观察者模式,在微信小程序多页面同时接收到设备推送事件!
微信小程序控制硬件第6篇 】服务器如何集成七牛云存储SDK,把用户自定义设备图片存储在第三方服务器!
微信小程序控制硬件第7篇 】动起来作一个微信小程序Mqtt协议控制智能硬件的框架,为本身内心全栈工程师梦想浇水!!
微信小程序控制硬件第8篇 】微信小程序以 websocket 链接阿里云IOT物联网平台mqtt服务器,封装起来使用就是这么简单!
微信小程序控制硬件第9篇 】巧借阿里云物联网平台的免费链接,从微信小程序颜色采集控制 esp8266 输出七彩灯效果,中秋节来个直播如何?!
微信公众号控制硬件 第10篇 】如何在微信公众号网页实现链接mqtt服务器教程!!
微信小程序控制硬件 第11篇 】全网首发,微信小程序ble蓝牙控制esp32,实现无需网络也能够控制亮度开关。
微信小程序控制硬件 第12篇 】微信小程序蓝牙控制硬件应如何开发?为您全面解析微信小程序蓝牙API的使用。
微信小程序控制硬件 第13篇 】安信可B站直播学习总结,微信小程序MQTT远程控制ESP8266 NodeMCU,谈谈微信生态那些事。html



1、前言;


           通过几趟折磨,过年后也就把这个框架弄好了,一直没时间写篇文章分享下!今天有空之余分享下心得!前面说了,要实现一个微信小程序控制本身的硬件(包括esp826六、esp32或者流行的树莓派)都须要一个服务器,而我前面几个分享给你们的是走私有服务器(非微信服务器)前端

           而前端开发与设备经过Mqtt协议链接的交互信息,无非是经过订阅和发送不一样的主题实现控制。
           因此,大多状况下,这种思想是固定的!发送主题,订阅主题!前端拿到设备列表的各个主题去订阅,一个主题就是一个设备!发送的主题就是控制一个设备。因此,我就大胆地设计了这么一个框架,而且分享出来!git


在这里插入图片描述


2、涉及的技术点;


  1. JavaScript观察者模式:由于各个页面发送和接收设备信息和主连接MQTT服务器是一个订阅观察的关系!由此我选用了onFire框架!
  2. weui框架使用:由于有些界面毕竟涉及到了美观,因此我就采用了微信开源的ui框架 ----- weui框架!
  3. MQTT协议的了解:这个协议是必需要熟悉的!MQTT协议已经做为物联网认知的一个协议标准了!
  4. 其余要了解的是微信小程序的基本开发流程,从下载开发工具和后台配置以及对微信小程序工程结构的了解!

在这里插入图片描述


3、框架的运行原理;


在这里插入图片描述

  • 再多的文字解释,也不够一个图片的概括的好。上面是我概括的;能够看到主要是分为三个模块:github

  • 链接服务器主线程:实现与服务器的信息交互!不会直接和各个界面进行联系,只须要和封装库联系!web

  • 封装库:做为服务器和用户交互的桥梁!内部封装好 主题订阅、发送消息和接收消息的工做。面试

  • 用户交互界面:这是一个很广的总结。交互界面有设备控制界面、设备列表界面或者其余分组界面等。可是仍是只须要关心你的当前操做设备的订阅主题和发送主题,或者这个设备的图片和设备类型。json


4、框架代码流程;


4.1 主线程;


            主线程是与mqtt服务器的链接,这个操做无非确定是在app.js经行的!
            doConnect()函数涉及了链接、订阅主题以及和本地的封装库的逻辑!小程序


doConnect: function() {
    var that = this;
    if (that.data.client && that.data.client.isConnected()) {
      console.log('不要重复链接');
      return
    }
    var client = new Client(this.globalData.server_domain, this.globalData.clientId());
    client.connect({
      userName: this.globalData.userName,
      password: this.globalData.password,
      useSSL: true,
      reconnect: true, //设置断线重连,默认是断线不重连
      cleanSession: true,
      keepAliveInterval: this.globalData.keepAliveInterval,
      onFailure: function(errorCode) {
        mDeviceClouds.notifyConnectEvent(false)
        //console.log("connect failed code:" + errorCode.errorCode)
        //console.log("connect failed message:" + errorCode.errorMessage)
      },
      onSuccess: function() {
        that.data.client = client
        client.onMessageArrived = function(msg) {
          if (typeof that.data.onMessageArrived === 'function') {
            return that.data.onMessageArrived(msg)
          }
          //  console.log("onMessageArrived topic:" + msg.destinationName)
          //  console.log("onMessageArrived payload:" + msg.payloadString)
          mDeviceClouds.notifyDeviceStatusEvent(msg.destinationName, msg.payloadString)
        }
        client.onConnectionLost = function(responseObject) {
          if (typeof that.data.onConnectionLost === 'function') {
            return that.data.onConnectionLost(responseObject)
          }
          if (responseObject.errorCode !== 0) {
            //console.log("onConnectionLost:" + responseObject.errorMessage);
          }
        }
        //console.log("connect success..")
        //链接成功mqtt服务器回调
        mDeviceClouds.notifyConnectEvent(true)
      }
    });
  },
  onLaunch: function() {

    //延迟连接,以防后面的收不到连接成功回调
    var that = this
    setTimeout(function() {
      that.doConnect();
    }, 800)

    // 订阅某个设备推送状态函数:参数 device对象
    mDeviceClouds.listenSubDeviceTopicEvent(true, function(device) {
      var client = that.data.client;
      if (client && client.isConnected()) {
        //console.log('订阅成功');
        return client.subscribe(device, {
          qos: 1
        });
      }
      //console.log('订阅失败');
    })
    // 发送消息给设备
    mDeviceClouds.listenWriteDeviceEvent(true, function(device, message, qos = 1, retained = false) {
      var client = that.data.client;
      if (client && client.isConnected()) {
        var message = new Message(message);
        message.destinationName = device;
        message.qos = qos;
        message.retained = retained;
        console.log('发送ok');
        return client.send(message);
      }
    })
  },

4.2 获取设备列表显示设备,以及订阅在线的设备;


            问题来了,从哪里获取设备列表,这个能够从本身的服务器,可是个人框架给出的是本地模拟的数据;这个能够根据小伙伴的业务来定了!能够看到下面,个人是很详细的,有设备名字、设备类型、设备图片、已经设备的订阅主题和发送主题!微信小程序

//模拟数据
var localData = [{
  'alias': '书房灯',
  'type': 'light',
  'img': 'http://qiniu.xuhongv.com/device_list_light.png',
  'online': true,
  'deviceSubTopic': 'light/29e90c3d0/Sub',
  'devicePubTopic': 'light/29e90c3d0/Pub',
}, {
  'alias': '抽风机插座',
  'type': 'outlet',
  'img': 'http://qiniu.xuhongv.com/device_list_outlet.png',
  'online': true,
  'deviceSubTopic': 'outlet/59e90c3d6/Sub',
  'devicePubTopic': 'outlet/59e90c3d6/Pub',
}, {
  'alias': '卧室灯',
  'type': 'outlet',
  'img': 'http://qiniu.xuhongv.com/device_list_light.png',
  'online': false,
  'deviceSubTopic': 'light/m9e90c396/Sub',
  'devicePubTopic': 'outlet/m9e90c396/Pub',
}, ]

            拿到设备列表以后,本身作一个设备列表把!下面是个人设备列表页面代码!七牛云存储

            根据设备列表数据的是否在线而显示不一样的颜色!加载不同的文字显示!

<view class="page">
  <view wx:for="{{cloudsDevices}}" wx:key="this" data-index='{{index}}' wx:for-item='itemObj' 
   bindtap='jumpDeviceControl'>
    <view class='item-deviceList'>

      <!--设备图片-->
      <image src='{{itemObj.img}}' class='deviceIcon'></image>

      <!--若是设备在线设备名字颜色蓝色,不然就灰色-->
      <text wx:if='{{itemObj.online}}' class='deviceName'>{{itemObj.alias}}</text>
      <text wx:else class='deviceName' style='color:#a1afc9'>{{itemObj.alias}}</text>

      <!--若是设备离线则加载不同的显示状态-->
      <text wx:if='{{itemObj.online}}' class="deviceStatusLine">在线</text>
      <text wx:else class="deviceStatusLine" style='color:#a1afc9'>离线</text>

      <!--若是设备离线则不显示箭头-->
      <image wx:if='{{itemObj.online}}' class='deviceInto' />

    </view>
    <view class='line'></view>
  </view>
  <view class="weui-footer weui-footer_fixed-bottom">
    <view class="weui-footer__links">
      <navigator url="https://github.com/xuhongv" class="weui-footer__link">WeUI+Mqtt+onfire</navigator>
    </view>
    <view class="weui-footer__text">Copyright ©半颗心脏 https://github.com/xuhongv</view>
  </view>

</view>

  • 效果以下:
    在这里插入图片描述

4.3 点击某设备如何实现携带此设备信息到控制界面;


            这个问题其实原理很简答的!点击某个设备,获取其索引!而后根据这个索引来从设备列表的中查找到这个设备,而后就能够把这个设备的某些信息去跳转到下一个设备了,好比设备的名字和类型,最主要的是设备的订阅主题,由于设备一直在接收此主题的消息。下面是点击一项设备时候触发的方法:

jumpDeviceControl: function(e) {
    //拿到当前点击设备的设备对象
    var device = this.data.devicesCloudsDatas["listData"][e.currentTarget.dataset.index];
    //设备是否在线?若是在线则能够跳转
    if (device.online)
      //判断设备类型
      switch (device.type) {
        case 'light':
         //携带设备订阅主题和名字跳转给下一个界面
          wx.navigateTo({
            url: "../deviceLight/deviceLight?devicePubTopic=" + device.devicePubTopic + "&deviceSubTopic=" + device.deviceSubTopic + "&alias=" + device.alias
          })
          break;
        case 'outlet':
           //携带设备订阅主题和名字跳转给下一个界面
          wx.navigateTo({
            url: "../deviceSocket/deviceSocket?devicePubTopic=" + device.devicePubTopic + "&deviceSubTopic=" + device.deviceSubTopic + "&alias=" + device.alias
          })
          break;
        default:
          break;
      }
  }

4.4 控制界面如何获取上个界面传过来的信息;


            首先你得明白,onLoad()方法里面的参数就是上个界面传来的!所以,咱们拿到了参数以后,要向咱们的本地的订阅中心订阅发来全部信息,判断是否当前设备的发来的;以下代码:

callBackDeviceStatus: function (topic, payload) {
    //此处判断服务器的下发主题和此设备的主题是否一致!
    if (this.data.devicePubTopic === topic) {
      console.log("设备状态回调:" + payload);
      //这里处理同步ui工做的代码逻辑处理
    }
  },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {

    console.log("拿到上个界面传来的设备信息:" + options.devicePubTopic);

    //根据设备名字,设置标题
    wx.setNavigationBarTitle({
      title: options.alias
    })
    this.setData({
      devicePubTopic: options.devicePubTopic,
      deviceSubTopic: options.deviceSubTopic
    })

    //设置监听函数
    mDeviceClouds.listenDeviceStatusEvent(true, this.callBackDeviceStatus);

    //控制设备,此函数任意地方调用!第一个参数是topic,第二个是payload
    //mDeviceClouds.notifyWriteDeviceEvent(options.deviceSubTopic, "hello world , i am from wechat");
  },

            既然咱们拿到了设备的订阅主题,那么咱们就能够作本身协议来控制了,好比点击开关灯以及控制亮度灯!看我下面的一个按键回调如何把定协议发送给设备:

//按键触发
  onSwitch: function (e) {
    console.log("onSwitch success :" + e.detail.value);
    //同步数据
    if (e.detail.value)
      this.setData({
        lightValue: 100,
        valuePic: this.data.pathLightOpen
      })
    else this.setData({
      lightValue: 0,
      valuePic: this.data.pathLightOff
    })
    //开始构造json数据
    var jsonObj = new Object();
    jsonObj.change = "power";
    jsonObj.value = "" + e.detail.value + "";
    //开始发布消息
    //mDeviceClouds.notifyWriteDeviceEvent(this.data.deviceSubTopic, JSON.stringify(jsonObj));
  }

5、其余;


5.1 特性

  • 支持断线重连!从新订阅主题!
  • 拓展性强,与具体的通信协议没有任何耦合!开发者能够根据本身业务来作协议!

5.2 如何修改信息;


  • 修改链接域名等链接信息!
    在这里插入图片描述

  • 修改模拟的设备列表数据,小伙伴也能够从本身的服务器获取(修改格式时候要对应在index.js作适配):
    在这里插入图片描述

  • 工程框架结构:
    在这里插入图片描述


6、下载;


  • 工程的读懂须要必定的微信小程序开发基础,请自备!

  • 框架下载(我的整理,收点小费):http://www.demodashi.com/demo/15147.html