【微信小程序控制硬件①】 全网首发,借助 emq 消息服务器带你如何搭建微信小程序的mqtt服务器,轻松控制智能硬件!
【微信小程序控制硬件②】 开始微信小程序之旅,导入小程序Mqtt客户端源码,实现简单的验证和通讯于服务器!
【微信小程序控制硬件③】 从软件到硬件搭建一个微信小程序控制esp8266的项目,自定义通讯协议,为面试职位和比赛项目加分!
【微信小程序控制硬件④】 深度剖析微信公众号配网 Airkiss 原理与过程,esp8266如何自定义回调参数给微信,实现绑定设备第一步!
【微信小程序控制硬件⑤ 进阶篇 】理清接下来必须走的架构思想,学习下 JavaScript 的观察者模式,在微信小程序多页面同时接收到设备推送事件!
【微信小程序控制硬件⑥ 进阶篇 】服务器如何集成七牛云存储SDK,把用户自定义设备图片存储在第三方服务器!
【微信小程序控制硬件⑦ 进阶篇 】动起来做一个微信小程序Mqtt协议控制智能硬件的框架,为自己心里全栈工程师梦想浇水!!
文章目录
一、前言;
经过几趟折磨,过年后也就把这个框架弄好了,一直没时间写篇文章分享下!今天有空之余分享下心得!前面说了,要实现一个微信小程序控制自己的硬件(包括esp8266、esp32或者流行的树莓派)都需要一个服务器,而我前面几个分享给大家的是走私有服务器(非微信服务器)!
而前端开发与设备通过Mqtt
协议连接的交互信息,无非是通过订阅和发送不同的主题实现控制。
所以,大多情况下,这种思想是固定的!发送主题,订阅主题!前端拿到设备列表的各个主题去订阅,一个主题就是一个设备!发送的主题就是控制一个设备。所以,我就大胆地设计了这么一个框架,并且分享出来!
二、涉及的技术点;
-
JavaScript
观察者模式:因为各个页面发送和接收设备信息和主链接MQTT
服务器是一个订阅观察的关系!由此我选用了onFire
框架! -
weui
框架使用:因为有些界面毕竟涉及到了美观,所以我就采用了微信开源的ui
框架 -----weui
框架! -
MQTT
协议的了解:这个协议是必须要熟悉的!MQTT
协议已经作为物联网认知的一个协议标准了! - 其他要了解的是微信小程序的基本开发流程,从下载开发工具和后台配置以及对微信小程序工程结构的了解!
三、框架的运行原理;
-
再多的文字解释,也不够一个图片的归纳的好。上面是我归纳的;可以看到主要是分为三个模块:
-
连接服务器主线程:实现与服务器的信息交互!不会直接和各个界面进行联系,只需要和封装库联系!
-
封装库:作为服务器和用户交互的桥梁!内部封装好 主题订阅、发送消息和接收消息的工作。
-
用户交互界面:这是一个很广的总结。交互界面有设备控制界面、设备列表界面或者其他分组界面等。但是还是只需要关心你的当前操作设备的订阅主题和发送主题,或者这个设备的图片和设备类型。
四、框架代码流程;
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.1 特性
- 支持断线重连!重新订阅主题!
- 拓展性强,与具体的通讯协议没有任何耦合!开发者可以根据自己业务来做协议!
5.2 如何修改信息;
-
修改连接域名等连接信息!
-
修改模拟的设备列表数据,小伙伴也可以从自己的服务器获取(修改格式时候要对应在
index.js
做适配): -
工程框架结构:
六、下载;
-
工程的读懂需要一定的微信小程序开发基础,请自备!
-
框架下载(个人整理,收点小费):http://www.demodashi.com/demo/15147.html