/**
* Created by SongPeng on 2019-5-31
*/
import { Dialog } from 'vant'
import mqtt from 'mqtt'
// import tools from './tools'
import common from './common'
import store from '@/store/index'
// import router from '@/router/index'
import { getEquiKey } from '@/api/device'
let [loading, vm, timer1] = [{}, {}, null]
const mqttClient = {
ws: {},
pramas: {},
initMqtt (options) {
this.pramas = Object.assign({
port: 8083,
keepalive: 60,
clientId: options.id,
clean: true,
username: '',
password: '',
path: '/mqtt'
}, options)
this.ws = mqtt('mqtt://47.105.162.0', this.pramas)
this.ws.on('connect', (e) => {
// if (Reflect.has(Dialog, 'close'))Dialog.close()
// console.log(`${this.pramas.clientId}连接成功`)
if (!store.state.mqttOnline) store.commit('CHANGEMQTTSTATE', !0)
})
this.ws.on('error', (e) => {
// console.log('error', e)
})
this.ws.on('offline', (e) => {
if (store.state.mqttOnline) store.commit('CHANGEMQTTSTATE', !1)
// Dialog.alert({
// title: '提示',
// message: 'mqtt服务已掉线,请检测网络后等待重连或者刷新后重试',
// showCancelButton: !0
// })
// console.log('offline', e)
})
this.ws.on('disconnect', (e) => {
// console.log('disconnect', e)
})
this.ws.on('close', (e) => {
// console.log('close', e)
})
this.ws.on('message', (topic, payload) => {
console.log('%c收到message,解密前原始数据', 'color:#0088f5', payload)
if (Reflect.has(loading, 'clear')) {
loading.clear()
clearInterval(timer1)
}
if (Reflect.has(Dialog, 'close'))Dialog.close()
// clearTimeout(timer)
let data = common.decryptedData(payload)
// console.log('%c解密完成数据:', 'color:#0088f5;', data)
if (data.index === window.$index) {
window.$index++
vm.onMqttMessage(topic, data)
} else {
// to do something
// console.log('index对应', window.$index + '!==' + data.index)
}
})
},
checkState (success = function () { }) {
this.ws.on('connect', (e) => {
// console.log(`${this.pramas.clientId}连接成功`)
success(e)
})
},
/**
* 自定义mqtt publish (9)
* @param {Object} data 总数据
* @param {Object} data._this vue实例
* @param {String} data.topic topic
* @param {Array} data.encryptedData 加密数据
* @param {Object} data.message 展示信息
* @param {Object} data.showInterval 展示定义器
* @param {Object} data.showFailTip 展示错误提示
* @param {Object} data.DialogOptions Dialog参数
* @param {Object} data.options mqtt publish options
* @param {Object} data.timeOut 超时时间
*/
publish (data) {
return new Promise((resolve, reject) => {
data = Object.assign({
_this: data._this,
topic: '',
encryptedData: [],
message: '连接中',
showInterval: !0,
showFailTip: !0,
DialogOptions: {
title: '提示',
message: '与设备连接超时',
confirmButtonText: '确认'
},
options: {},
timeOut: 10
}, data)
if (data._this === null) console.error('[data._this] can not be null, you should check if send vue[this]?')
if (data.topic === '') console.error('[publish.topic] can not be undefined')
vm = data._this
if (data.showInterval) {
loading = common.showIntervalLoading({
message: `${data.message}10秒`
})
let second = data.timeOut
clearInterval(timer1)
timer1 = setInterval(() => {
second--
if (second) {
loading.message = `${data.message}${second}秒`
} else {
clearInterval(timer1)
loading.clear()
if (data.showFailTip) {
loading.clear()
Dialog.alert(data.DialogOptions)
}
resolve(data.topic)
}
}, 1000)
}
console.log('发送数据:', new Uint8Array(data.encryptedData))
this.ws.publish(data.topic, new Uint8Array(data.encryptedData), Object.assign({ qos: 0 }, data.options), (err) => {
if (err) {
// console.log(err)
loading.clear()
clearInterval(timer1)
Dialog.alert({
title: '提示',
message: '发送信息失败'
})
} else {
console.log('%c数据发送成功', 'color:#ea3800')
}
})
})
},
end () {
this.ws.end()
},
destroy () {
clearInterval(timer1)
loading.clear()
Dialog.close()
},
subscribe (topic, options, callback = function () { }) {
this.ws.subscribe(topic, Object.assign({ qos: 0 }, options), (err) => {
if (err) {
Dialog.alert({
title: '提示',
message: '订阅失败'
})
}
callback(err)
})
},
unsubscribe (topic, options, callback = function () { }) {
this.ws.unsubscribe(topic, Object.assign({ qos: 0 }, options), (err) => {
if (!err) {
callback()
}
})
},
/**
* 自定义mqtt sendMessage (11)
* @param {Object} t 总数据
* @param {Object} t._this vue实例
* @param {Array} t.data 加密前数据
* @param {String} t.equiImei 设备Imei
* @param {Boolean} t.showInterval 展示定时器
* @param {Boolean} t.showFailTip 展示错误提示
* @param {String} t.message 信息提示
* @param {Object} t.subscribePrefix sub前缀
* @param {Object} t.publishPrefix pub前缀
* @param {Object} t.DialogOptions Dialog参数
* @param {Object} t.options mqtt publish options
* @param {Object} t.timeOut 超时时间
*/
sendMessage (t) {
return new Promise((resolve, reject) => {
t = Object.assign({
_this: null,
data: [],
equiImei: '',
showInterval: !0,
showFailTip: !0,
message: '同步中',
subscribePrefix: '2/5',
publishPrefix: '2/3',
DialogOptions: {
title: '提示',
message: '与设备连接超时',
confirmButtonText: '确认'
},
options: {},
timeOut: 10
}, t)
this.subscribe(`${t.subscribePrefix}/${t.equiImei}`, {}, (err) => {
if (!err) {
getEquiKey({
equiImei: t.equiImei
})
.then(res => {
if (res.code === 0) {
this.publish({
_this: t._this,
topic: `${t.publishPrefix}/${t.equiImei}`,
encryptedData: common.getEncryptedData(t.cmdType, [...t.data], res.data),
options: t.options,
showInterval: t.showInterval,
message: t.message,
showFailTip: t.showFailTip,
DialogOptions: t.DialogOptions,
timeOut: t.timeOut
})
.then(res => {
console.log('数据获取失败')
resolve(res)
})
}
})
}
})
})
}
}
export default mqttClient
tools.js
/**
* Created by SongPeng on 2019-5-31
*/
export default {
/**
* 十六进制字符串转字节数组
* 每2个字符串转换
* 100102030405060708 转为 [16, 1, 2, 3, 4, 5, 6, 7, 8]
* @param {String} str 符合16进制字符串
*/
Str2Bytes (str) {
console.log(str)
var pos = 0
var len = str.length
if (len % 2 !== 0) {
return null
}
len /= 2
var hexA = []
for (var i = 0; i < len; i++) {
var s = str.substr(pos, 2)
var v = parseInt(s, 16)
hexA.push(v)
pos += 2
}
return hexA
},
/**
* 字节数组转十六进制字符串
* [16, 1, 2, 3, 4, 5, 6, 7, 8] 转换 100102030405060708
* @param {Array} arr 符合16进制数组
*/
Bytes2Str (arr) {
var str = ''
for (var i = 0; i < arr.length; i++) {
var tmp = arr[i].toString(16)
if (tmp.length === 1) {
tmp = '' + tmp
}
str += tmp
}
return str
},
/**
* 数组进行异或
* @param {Array} arr 数组
*/
BytesDes (arr) {
var des = arr[0]
for (var i = 1; i < arr.length; i++) {
des ^= arr[i]
}
return des
},
/**
* 十六进制数组转十进制数组
* @param {Array} arr 十六进制数组
*/
Array16to10 (arr) {
var list = []
arr.forEach(element => {
list = [
...list,
...this.Str2Bytes(element)
]
})
return list
},
/**
* 十进制数组转十六进制数组
* @param {Array} arr 十进制数组
*/
Array10to16 (arr) {
var list = []
arr.forEach(element => {
list[list.length] = this.toHex(element)
})
return list
},
/**
* 十进制转十六进制
* 15 转 0F
* @param {Number} num 十进制数字
*/
toHex (num) {
if (num <= 255) {
return ('0' + (Number(num).toString(16))).slice(-2).toUpperCase()
} else {
var str = num.toString(16)
if (str.length === 3) {
return '0' + str
} else {
return str
}
}
},
/**
* byte数组 转 int
* @param {Array} arr
*/
byteToInt (arr) {
let [all, int] = ['', 0]
arr.forEach(value => {
value = value.toString(2)
if (value.length < 8) {
for (let i = 0; i < 10; i++) {
value = '0' + value
if (value.length === 8) {
i = 10
}
}
}
all = all + value
})
for (let o = 0; o < all.length; o++) {
int = int + +all[o] * Math.pow(2, all.length - o - 1)
}
return int
},
/**
* int 转 两位byte数组
* @param {Array} arr
*/
intToTwoByte (int) {
let arr = []
if (int <= 255) {
arr = [0, int]
} else {
arr = this.Str2Bytes(this.toHex(int))
}
return arr
}
}