Commit 59719230 by 王榕

Initial commit

parents
//app.js
App({
onLaunch: function () {
},
globalData: {
userInfo: null
}
})
\ No newline at end of file
{
"pages": [
"pages/index/index"
],
"window": {
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#fff",
"navigationBarTitleText": "WeChat",
"navigationBarTextStyle": "black"
},
"sitemapLocation": "sitemap.json"
}
\ No newline at end of file
//index.js
//获取应用实例
const app = getApp()
import Jsbuffer from '../../utils/jsbuffer.min.js';
import {
Api,
confirmTip,
alertTip
} from '../../utils/util.js';
let jsbufer = new Jsbuffer();
function ab2str(buf) {
return String.fromCharCode.apply(null, new Uint8Array(buf));
}
const serverUUID = 'E7810BB2-73AE-499D-8C15-FAA9AEF0C3F2'
const writeUUID = 'BEF8E801-9C21-4C9E-B632-BD58C1009F9F'
const readUUID = 'BEF8E800-9C21-4C9E-B632-BD58C1009F9F'
const deviceSet = new Set()
const event = {
writeValue() {},
readValue() {}
}
let cacheHexs = []
let timeOutFlag = false
let timer = null
function writeHex(hex, deviceId) {
timeOutFlag = false
clearTimeout(timer)
return new Promise((resolve, reject) => {
let resHex = jsbufer.from(hex, 'hex')
wx.writeBLECharacteristicValue({
deviceId: deviceId,
serviceId: serverUUID,
characteristicId: writeUUID,
value: resHex.buffer,
success: function(res) {
// console.log('成功:', hex)
timer = setTimeout(() => {
timeOutFlag = true
wx.hideLoading()
alertTip(`升级失败,超时未回复`)
}, 3000)
resolve()
},
fail: function(err) {
// console.log('失败:', hex, err)
timeOutFlag = true
reject('失败:' + hex)
},
complete() {
}
})
})
}
Page({
data: {
deviceList: [],
blueOpen: false,
blueConnect: false,
linkDevice: '',
deviceId: '',
inputDeviceId: '',
deviceListShow: false,
discovery: false,
hex: '',
hexStr: ''
},
//事件处理函数
bindViewTap: function() {
},
onLoad: function() {
// 初始化蓝牙
this.initBlueTooth()
this.getUpdateStr()
},
getUpdateStr() {
Api.get('http://yadi-upgrade.zhuzhux.com/download/getFileHex?typeHex=3')
.then(res => {
this.setData({
hexStr: res
})
})
.catch(err => {
console.log('升级数据:', err)
confirmTip('获取升级数据失败,是否重试', () => {
this.getUpdateStr()
})
})
},
// 蓝牙开始
initBlueTooth: function() {
let that = this
wx.openBluetoothAdapter({ // 初始化蓝牙模块
fail(err) {
console.log('蓝牙初始化失败', err)
},
complete: function(co) {
console.log('蓝牙模块初始化公共段', co)
if (co.errMsg == 'openBluetoothAdapter:ok') {
console.log('蓝牙已打开')
// 把状态改为有关闭蓝牙提醒
that.setData({
blueOpen: true
})
} else {
console.log('蓝牙已关闭')
// 把状态改为有打开蓝牙提醒
that.setData({
blueOpen: false
})
}
// 开始监听蓝牙变化
wx.onBluetoothAdapterStateChange(function(res) {
console.log('监听蓝牙状态改变', res)
if (res.available) {
// // console.log('蓝牙已打开')
// 把状态改为有关闭蓝牙提醒
that.setData({
blueOpen: true
})
} else {
console.log('蓝牙已关闭')
// 把状态改为有打开蓝牙提醒
that.setData({
blueOpen: false
})
}
})
}
})
},
// 关闭蓝牙
closeBlueTooth() {
let that = this
wx.closeBLEConnection({
deviceId: that.data.deviceId,
success: function(res) {
that.setData({
blueConnect: false
})
wx.closeBluetoothAdapter({
success: function(res) {
that.setData({
blueOpen: false
})
// // console.log('closeBluetoothAdapter22', res)
}
})
},
complete: function() {
wx.closeBluetoothAdapter({
success: function(res) {
that.setData({
blueOpen: false
})
// // console.log('closeBluetoothAdapter23', res)
}
})
}
})
},
searchStart(e) {
let blueAddress = this.data.linkDevice.slice(-12)
let that = this
// 监听寻找到新设备的事件
deviceSet.clear()
wx.onBluetoothDeviceFound(function(res) {
let devices = res.devices // 设备列表
console.log('onBluetoothDeviceFound获取到设备', res.devices)
res.devices.forEach(elt => {
if (/^c1/gi.test(elt.deviceId)) {
deviceSet.add(elt)
}
})
that.setData({
deviceList: [...deviceSet]
})
if (e) {
return
}
if (devices.length > 0) {
for (let i in devices) {
let mac = ab2str(devices[i].advertisData).toLowerCase()
let deviceId = devices[i].deviceId
let mac2 = deviceId.split(':').join('').toLowerCase()
// // console.log('解析苹果上的advertisData', mac, 'devicesId', deviceId)
if (mac.indexOf(blueAddress.toLowerCase()) != -1) {
// // console.log('找到对应的车辆', mac)
if (deviceId) {
if (!that.data.blueConnect) {
that.connectBlue(deviceId)
}
}
}
}
}
})
wx.startBluetoothDevicesDiscovery({
allowDuplicatesKey: false,
success: function(res) {
// // console.log('startBluetoothDevicesDiscovery发现蓝牙设备', res)
},
fail: function(res) {
that.setData({
bluetooth: false
})
}
})
},
searchEnd() {
let that = this
wx.showLoading({
title: '关闭中',
mask: true
})
wx.stopBluetoothDevicesDiscovery({
success: function(res) {
// console.log('stopBluetoothDevicesDiscovery', res)
wx.hideLoading()
that.setData({
bluetooth: false
})
},
fail: function(res) {
wx.hideLoading()
wx.showToast({
title: '关闭搜索失败',
})
// console.log('errstopBluetoothDevicesDiscovery', res)
}
})
},
connectBlue(deviceId) {
// 低功耗连接蓝牙设备
wx.showLoading({
title: '连接中',
mask: true
})
let that = this
that.setData({
deviceId: deviceId,
})
wx.createBLEConnection({
deviceId,
success: function(res) {
wx.hideLoading()
that.setData({
blueConnect: true,
deviceId,
})
that.getServers(deviceId)
that.readBLECharacteristicValue(deviceId)
wx.showLoading()
setTimeout(() => {
that.sendMsg2()
}, 1200)
},
fail: function() {
that.setData({
blueConnect: false
})
wx.hideLoading()
wx.showToast({
title: '连接失败',
})
}
})
},
// 蓝牙结束
openDeviceList: function() {
this.setData({
})
},
bindHexInput: function(e) {
this.setData({
hex: e.detail.value.toUpperCase()
})
},
bindDeviceIdInput: function(e) {
this.setData({
inputDeviceId: e.detail.value
})
},
sendBlueValue: function(hex, serviceId, characteristicId) {
if (!hex) {
wx.showToast({
title: '请输入要发送的信息',
})
return
}
let {
deviceId
} = this.data
let resHex = jsbufer.from(hex, 'hex')
// // console.log('发送的数据:', resHex)
wx.writeBLECharacteristicValue({
deviceId: deviceId,
serviceId: serviceId,
characteristicId: characteristicId,
value: resHex.buffer,
success: function(res) {
wx.showToast({
title: '写入成功',
})
},
fail: function(res) {
wx.showToast({
title: '写入数据失败,请重试',
})
}
})
},
handleHexstrToArray(hexStr) {
function toFix(val) {
return val[1] ? val : '0' + val
}
function toFixType(val) {
let str = '0'.repeat(4 - val.length) + val
return str.slice(2) + str.slice(0, 2)
}
function xor(hex) {
let newValue = ''
let arr = []
for (let i = 0; i < hex.length / 2; i++) {
let item = hex.slice(i * 2, (i + 1) * 2)
arr.push(Number('0x' + item))
}
let start = arr.shift(1)
let checkNum = toFix((arr.reduce((sum, val) => {
return sum ^ val
}, start)).toString(16))
return hex.slice(0, 2) + checkNum + hex.slice(2)
}
let num = hexStr.length % 32
hexStr += 'F'.repeat(32 - num)
// hexStr = 'FF'.repeat(16) + hexStr + 'FF'.repeat(16)
let newArr = []
newArr.push(xor('5200FF' + 'FF'.repeat(16)))
for (let i = 0; i < hexStr.length / 32; i++) {
let item = '52' + toFixType(i.toString(16)) + hexStr.slice(i * 32, (i + 1) * 32)
newArr.push(xor(item))
}
newArr.push(xor('5201FF' + 'FF'.repeat(16)))
return newArr
},
// 读蓝牙返回
readBLECharacteristicValue(deviceId) {
wx.readBLECharacteristicValue({
deviceId,
serviceId: serverUUID,
characteristicId: readUUID,
})
wx.notifyBLECharacteristicValueChange({
deviceId,
serviceId: serverUUID,
characteristicId: readUUID,
state: true,
})
wx.onBLECharacteristicValueChange((characteristic) => {
if (characteristic.characteristicId == readUUID) {
let hexData = new Jsbuffer();
this.getBlueValueBack(hexData.read(characteristic.value))
}
})
},
getBlueValueBack(hex) {
let {
deviceId
} = this.data
// console.log('收到回复', hex)
let wHex = cacheHexs.shift()
wx.showLoading({
title: `升级中。。还剩${cacheHexs.length}个包`,
})
if (/^5250584b0000/gi.test(hex.hex) && !timeOutFlag) {
if (wHex) {
writeHex(wHex, deviceId)
.catch(err => {
wx.hideLoading()
clearTimeout(timer)
alertTip(`升级失败:写入数据${wHex}失败`)
})
} else {
wx.hideLoading()
clearTimeout(timer)
alertTip('升级成功')
}
} else {
clearTimeout(timer)
alertTip(`升级失败,回复${hex.hex}`)
}
},
sendBlueListValue: function(hexArray, serviceId, characteristicId) {
let {
deviceId
} = this.data
cacheHexs = [...hexArray]
let hex = cacheHexs.shift()
writeHex(hex, deviceId)
.catch(err => {
wx.hideLoading()
console.log(err)
alertTip(`升级失败:写入数据${hex}失败`)
})
// let promiseAll = hexArray.map(hex => writeHex(hex))
// Promise.all(promiseAll)
// .then(res => {
// wx.hideLoading()
// wx.showToast({
// title: '写入数据结束',
// })
// })
// .catch(err => {
// wx.hideLoading()
// wx.showToast({
// title: '写入数据失败,请重试',
// })
// })
},
getServers(deviceId) {
wx.getBLEDeviceServices({
// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
deviceId,
success(res) {
console.log('服务ids:', res.services)
wx.getBLEDeviceCharacteristics({
// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
deviceId,
// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
serviceId: serverUUID,
success(res) {
console.log('设备特征值:', res.characteristics)
}
})
}
})
},
hexFocus: function() {
this.setData({
hex: '',
})
},
connectByHand() {
let deviceId = this.data.inputDeviceId
this.connectBlue(deviceId)
},
connectByList(e) {
let item = e.currentTarget.dataset.item
this.connectBlue(item.deviceId)
},
scanDevice: function() {
let that = this
wx.scanCode({
success: function(res) {
// console.log(res)
that.setData({
linkDevice: res.result
})
that.searchStart()
},
fail: function(res) {
wx.showToast({
title: '调用扫码失败',
})
}
})
},
openLock: function() {
this.sendBlueValue('2401ff00', '0000FFE5-0000-1000-8000-00805F9B34FB', '0000FFE9-0000-1000-8000-00805F9B34FB')
},
closeLock: function() {
this.sendBlueValue('2402ff00', '0000FFE5-0000-1000-8000-00805F9B34FB', '0000FFE9-0000-1000-8000-00805F9B34FB')
},
sendMsg: function() {
let hex = this.data.hex
this.sendBlueValue(hex, '0000FFE5-0000-1000-8000-00805F9B34FB', '0000FFE9-0000-1000-8000-00805F9B34FB')
},
sendMsg2: function() {
if (!this.data.hexStr) {
alertTip('未获取到升级数据')
return
}
wx.showLoading({
title: '升级中。。。',
})
let a = this.data.hexStr
let arr = this.handleHexstrToArray(a)
this.sendBlueListValue(arr, serverUUID, writeUUID)
},
})
\ No newline at end of file
{
"usingComponents": {}
}
\ No newline at end of file
<!--index.wxml-->
<view class="panel">
<view class="panel-title">状态</view>
<view class="panel-body">
<view class="body-item">
<text>手机蓝牙:</text>
<text wx:if="{{blueOpen}}" style='color:green'>已开启</text>
<text wx:else style='color:red'>已关闭</text>
</view>
<view class="body-item">
<text>设备:</text>
<text wx:if="{{blueConnect}}" style='color:green'>已连接,设备编号{{linkDevice||deviceId}}</text>
<text wx:else style='color:red'>已断开</text>
</view>
</view>
</view>
<view class="panel">
<view class="panel-title">操作</view>
<view class="panel-body">
<view wx:if="{{blueOpen}}">
<button bindtap='searchStart' type='primary' wx:if="{{!discovery}}">搜索蓝牙设备</button>
<button bindtap='searchEnd' wx:else>停止搜索</button>
</view>
<button bindtap='scanDevice' wx:if="{{blueOpen}}" type='primary'>扫码连接</button>
<!-- <input bindinput="bindDeviceIdInput" value='{{inputDeviceId}}' wx:if="{{blueOpen}}" placeholder="请输入设备deviceId" />
<button bindtap='connectByHand' wx:if="{{blueOpen}}" type='primary'>直接连接</button> -->
<view wx:if="{{blueConnect}}">
<button bindtap='sendMsg2' type='primary'>重试升级</button>
</view>
<button bindtap='closeBlueTooth' wx:if="{{blueOpen}}" type='warn'>关闭蓝牙</button>
<button bindtap='initBlueTooth' wx:else type='primary'>开启蓝牙</button>
<button bindtap='getUpdateStr' type='info'>重新获取升级文件</button>
</view>
</view>
<view class="panel">
<view class="panel-title">设备列表</view>
<view class="panel-body">
<view class='device-list' wx:if='deviceList.length!=0'>
<view wx:for="{{deviceList}}" class="device-item" wx:key="{{index}}" data-item='{{item}}' bindtap='connectByList'>
<view class="device-name">
<text>{{item.name}}</text>
<text>{{item.deviceId}}</text>
</view>
<view class="btn" style='color:green;'>连接并升级</view>
</view>
</view>
</view>
</view>
<!-- <view wx:if="{{blueConnect}}">
<view class="section">
<view class="label">自定义发送的值:</view>
<view class='hex-input'>
<input bindinput="bindHexInput" value='{{hex}}' placeholder="请输入hex可以小写" bindfocus="hexFocus" />
<button bindtap='sendMsg' plain>发送</button>
</view>
</view>
<view class='btn'>
<button bindtap='openLock' type='primary'>开锁</button>
<button bindtap='closeLock' type='warn'>关锁</button>
</view>
<view class='btn'>
<button bindtap='sendMsg2' type='primary'>重试升级</button>
<button bindtap='closeLock' type='warn'>关锁</button>
</view>
</view> -->
\ No newline at end of file
page {
background: #e5e5e5;
min-height: 100vh;
}
.panel {
}
.panel .panel-title {
font-size: 16px;
font-weight: bolder;
padding: 20rpx 30rpx;
}
.panel-body {
background-color: #fff;
padding: 30rpx;
font-size: 14px;
}
.panel-body .body-item {
display: flex;
padding-bottom: 10rpx;
}
.panel-body .body-item:last-child {
padding-bottom: 0;
}
.panel-body .body-item text:nth-of-type(1) {
width: 200rpx;
}
.panel-body .body-item text:nth-of-type(2) {
flex: 1;
}
.hex-input {
display: flex;
align-items: center;
padding: 10px;
}
.hex-input input {
border: 1px solid #ccc;
flex: 1;
margin-right: 8px;
height: 100rpx;
}
button {
margin: 5px;
}
.device-list{
}
.device-item{
padding: 20rpx 16rpx;
border: 1rpx solid #e5e5e5;
border-radius:6rpx;
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20rpx;
}
.device-item .device-name{
font-size: 12px;
display: flex;
flex-direction: column;
line-height: 18px;
width: 500rpx;
}
.device-item .btn{
padding: 10rpx 15rpx;
font-size: 12px;
border: 1rpx solid #000;
border-radius: 3px;
}
\ No newline at end of file
{
"description": "项目配置文件",
"packOptions": {
"ignore": []
},
"setting": {
"urlCheck": false,
"es6": true,
"postcss": true,
"minified": true,
"newFeature": true,
"coverView": true,
"autoAudits": false,
"checkInvalidKey": true,
"checkSiteMap": true,
"uploadWithSourceMap": true,
"babelSetting": {
"ignore": [],
"disablePlugins": [],
"outputPath": ""
}
},
"compileType": "miniprogram",
"libVersion": "2.7.2",
"appid": "wx918b041f12491a2b",
"projectname": "%E8%93%9D%E7%89%99%E5%BC%80%E9%94%81%E5%B7%A5%E5%85%B7",
"debugOptions": {
"hidedInDevtools": []
},
"isGameTourist": false,
"simulatorType": "wechat",
"simulatorPluginLibVersion": {},
"condition": {
"search": {
"current": -1,
"list": []
},
"conversation": {
"current": -1,
"list": []
},
"game": {
"currentL": -1,
"list": []
},
"miniprogram": {
"current": -1,
"list": []
}
}
}
\ No newline at end of file
{
"desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
"rules": [{
"action": "allow",
"page": "*"
}]
}
\ No newline at end of file
/**
*create by wr
**/
"use strict";var _createClass=function(){function n(t,r){for(var e=0;e<r.length;e++){var n=r[e];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(t,r,e){return r&&n(t.prototype,r),e&&n(t,e),t}}();function _classCallCheck(t,r){if(!(t instanceof r))throw new TypeError("Cannot call a class as a function")}var jsbuffer=function(){function t(){return _classCallCheck(this,t),this.buffer=null,this.hex=null,this.uint8array=null,this}return _createClass(t,[{key:"from",value:function(t,r){var n=this;if(r&&"hex"==r)this.hex=t,this.buffer=new ArrayBuffer(t.length/2),this.uint8array=new Uint8Array(this.buffer),t.match(/.{2}/g).forEach(function(t,r){n.uint8array[r]=Number("0x"+t)});else{var e=t.split("");this.buffer=new ArrayBuffer(e.length),this.uint8array=new Uint8Array(this.buffer),this.hex="",e.forEach(function(t,r){var e=t.charCodeAt(0);e=1==e.toString(16).length?"0"+e.toString(16):e.toString(16),n.hex+=e,n.uint8array[r]=Number("0x"+e)})}return this}},{key:"read",value:function(t){return this.buffer=t,this.uint8array=new Uint8Array(this.buffer),this.setHex(),this}},{key:"set",value:function(t,r){return this.uint8array[t]=r,this.setHex(),this}},{key:"get",value:function(t,r){var e=this.uint8array[t];return r&&/hex/i.test(r)?1==e.toString(16).length?"0"+e.toString(16):e.toString(16):e}},{key:"setHex",value:function(){var r=this;this.hex="",this.uint8array.forEach(function(t){r.hex+=1==t.toString(16).length?"0"+t.toString(16):t.toString(16)})}}]),t}();module.exports=jsbuffer;
\ No newline at end of file
const formatTime = date => {
const year = date.getFullYear()
const month = date.getMonth() + 1
const day = date.getDate()
const hour = date.getHours()
const minute = date.getMinutes()
const second = date.getSeconds()
return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':')
}
const formatNumber = n => {
n = n.toString()
return n[1] ? n : '0' + n
}
const Api = {
get: (url, query, notShowLoad) => {
if (!notShowLoad) {
wx.showLoading({
mask: true,
})
}
return new Promise((resolve, reject) => {
wx.request({
url: url,
// data: Object.assign({}, { userId: wx.getStorageSync('user') ? wx.getStorageSync('user').userId : '' }, query),
data: query,
method: 'GET',
success(res) {
console.log(res)
if (res.statusCode == 200) {
resolve(res.data)
return
} else {
reject(res.data, '请求失败')
}
},
fail(res) {
console.error('1', res)
reject(res.data, '请求失败')
},
complete() {
if (!notShowLoad) {
wx.hideLoading()
}
}
})
})
}
}
module.exports = {
formatTime: formatTime,
Api,
confirmTip: (msg, cb) => {
msg = msg ? msg.toString() : 'timeout'
wx.showModal({
title: '提示',
content: msg,
success(res) {
if (res.confirm) {
cb && cb()
}
}
})
},
alertTip: (msg, cb) => {
wx.showModal({
title: '提示',
content: msg,
showCancel: false,
success() {
cb && cb()
}
})
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment