@ -0,0 +1,33 @@ | |||||
// app.js | |||||
import { globalData } from "./utils/global"; | |||||
const EventEmitter2 = require("./miniprogram_npm/eventemitter2/index").EventEmitter2; | |||||
const emitter = new EventEmitter2(); | |||||
App({ | |||||
onLaunch() { | |||||
// 展示本地存储能力 | |||||
const logs = wx.getStorageSync('logs') || [] | |||||
logs.unshift(Date.now()) | |||||
wx.setStorageSync('logs', logs) | |||||
// 登录 | |||||
wx.login({ | |||||
success: res => { | |||||
// 发送 res.code 到后台换取 openId, sessionKey, unionId | |||||
} | |||||
}) | |||||
}, | |||||
globalData: Object.assign( | |||||
{ | |||||
ble: "",//全局蓝牙实例 | |||||
emitter: emitter, //全局订阅函数 | |||||
blueStatus: false, | |||||
userInfo: null | |||||
}, | |||||
globalData | |||||
), | |||||
}) |
@ -0,0 +1,16 @@ | |||||
{ | |||||
"pages":[ | |||||
"pages/asyntest/asyntest", | |||||
"pages/lanyatest/lanyatest", | |||||
"pages/index/index", | |||||
"pages/logs/logs" | |||||
], | |||||
"window":{ | |||||
"backgroundTextStyle":"light", | |||||
"navigationBarBackgroundColor": "#fff", | |||||
"navigationBarTitleText": "Weixin", | |||||
"navigationBarTextStyle":"black" | |||||
}, | |||||
"style": "v2", | |||||
"sitemapLocation": "sitemap.json" | |||||
} |
@ -0,0 +1,10 @@ | |||||
/**app.wxss**/ | |||||
.container { | |||||
height: 100%; | |||||
display: flex; | |||||
flex-direction: column; | |||||
align-items: center; | |||||
justify-content: space-between; | |||||
padding: 200rpx 0; | |||||
box-sizing: border-box; | |||||
} |
@ -0,0 +1,800 @@ | |||||
module.exports = (function() { | |||||
var __MODS__ = {}; | |||||
var __DEFINE__ = function(modId, func, req) { var m = { exports: {} }; __MODS__[modId] = { status: 0, func: func, req: req, m: m }; }; | |||||
var __REQUIRE__ = function(modId, source) { if(!__MODS__[modId]) return require(source); if(!__MODS__[modId].status) { var m = { exports: {} }; __MODS__[modId].status = 1; __MODS__[modId].func(__MODS__[modId].req, m, m.exports); if(typeof m.exports === "object") { __MODS__[modId].m.exports.__proto__ = m.exports.__proto__; Object.keys(m.exports).forEach(function(k) { __MODS__[modId].m.exports[k] = m.exports[k]; var desp = Object.getOwnPropertyDescriptor(m.exports, k); if(desp && desp.configurable) Object.defineProperty(m.exports, k, { set: function(val) { __MODS__[modId].m.exports[k] = val; }, get: function() { return __MODS__[modId].m.exports[k]; } }); }); if(m.exports.__esModule) Object.defineProperty(__MODS__[modId].m.exports, "__esModule", { value: true }); } else { __MODS__[modId].m.exports = m.exports; } } return __MODS__[modId].m.exports; }; | |||||
var __REQUIRE_WILDCARD__ = function(obj) { if(obj && obj.__esModule) { return obj; } else { var newObj = {}; if(obj != null) { for(var k in obj) { if (Object.prototype.hasOwnProperty.call(obj, k)) newObj[k] = obj[k]; } } newObj.default = obj; return newObj; } }; | |||||
var __REQUIRE_DEFAULT__ = function(obj) { return obj && obj.__esModule ? obj.default : obj; }; | |||||
__DEFINE__(1585827830357, function(require, module, exports) { | |||||
/*! | |||||
* EventEmitter2 | |||||
* https://github.com/hij1nx/EventEmitter2 | |||||
* | |||||
* Copyright (c) 2013 hij1nx | |||||
* Licensed under the MIT license. | |||||
*/ | |||||
;!function(undefined) { | |||||
var isArray = Array.isArray ? Array.isArray : function _isArray(obj) { | |||||
return Object.prototype.toString.call(obj) === "[object Array]"; | |||||
}; | |||||
var defaultMaxListeners = 10; | |||||
function init() { | |||||
this._events = {}; | |||||
if (this._conf) { | |||||
configure.call(this, this._conf); | |||||
} | |||||
} | |||||
function configure(conf) { | |||||
if (conf) { | |||||
this._conf = conf; | |||||
conf.delimiter && (this.delimiter = conf.delimiter); | |||||
this._maxListeners = conf.maxListeners !== undefined ? conf.maxListeners : defaultMaxListeners; | |||||
conf.wildcard && (this.wildcard = conf.wildcard); | |||||
conf.newListener && (this._newListener = conf.newListener); | |||||
conf.removeListener && (this._removeListener = conf.removeListener); | |||||
conf.verboseMemoryLeak && (this.verboseMemoryLeak = conf.verboseMemoryLeak); | |||||
if (this.wildcard) { | |||||
this.listenerTree = {}; | |||||
} | |||||
} else { | |||||
this._maxListeners = defaultMaxListeners; | |||||
} | |||||
} | |||||
function logPossibleMemoryLeak(count, eventName) { | |||||
var errorMsg = '(node) warning: possible EventEmitter memory ' + | |||||
'leak detected. ' + count + ' listeners added. ' + | |||||
'Use emitter.setMaxListeners() to increase limit.'; | |||||
if(this.verboseMemoryLeak){ | |||||
errorMsg += ' Event name: ' + eventName + '.'; | |||||
} | |||||
if(typeof process !== 'undefined' && process.emitWarning){ | |||||
var e = new Error(errorMsg); | |||||
e.name = 'MaxListenersExceededWarning'; | |||||
e.emitter = this; | |||||
e.count = count; | |||||
process.emitWarning(e); | |||||
} else { | |||||
console.error(errorMsg); | |||||
if (console.trace){ | |||||
console.trace(); | |||||
} | |||||
} | |||||
} | |||||
function EventEmitter(conf) { | |||||
this._events = {}; | |||||
this._newListener = false; | |||||
this._removeListener = false; | |||||
this.verboseMemoryLeak = false; | |||||
configure.call(this, conf); | |||||
} | |||||
EventEmitter.EventEmitter2 = EventEmitter; // backwards compatibility for exporting EventEmitter property | |||||
// | |||||
// Attention, function return type now is array, always ! | |||||
// It has zero elements if no any matches found and one or more | |||||
// elements (leafs) if there are matches | |||||
// | |||||
function searchListenerTree(handlers, type, tree, i) { | |||||
if (!tree) { | |||||
return []; | |||||
} | |||||
var listeners=[], leaf, len, branch, xTree, xxTree, isolatedBranch, endReached, | |||||
typeLength = type.length, currentType = type[i], nextType = type[i+1]; | |||||
if (i === typeLength && tree._listeners) { | |||||
// | |||||
// If at the end of the event(s) list and the tree has listeners | |||||
// invoke those listeners. | |||||
// | |||||
if (typeof tree._listeners === 'function') { | |||||
handlers && handlers.push(tree._listeners); | |||||
return [tree]; | |||||
} else { | |||||
for (leaf = 0, len = tree._listeners.length; leaf < len; leaf++) { | |||||
handlers && handlers.push(tree._listeners[leaf]); | |||||
} | |||||
return [tree]; | |||||
} | |||||
} | |||||
if ((currentType === '*' || currentType === '**') || tree[currentType]) { | |||||
// | |||||
// If the event emitted is '*' at this part | |||||
// or there is a concrete match at this patch | |||||
// | |||||
if (currentType === '*') { | |||||
for (branch in tree) { | |||||
if (branch !== '_listeners' && tree.hasOwnProperty(branch)) { | |||||
listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i+1)); | |||||
} | |||||
} | |||||
return listeners; | |||||
} else if(currentType === '**') { | |||||
endReached = (i+1 === typeLength || (i+2 === typeLength && nextType === '*')); | |||||
if(endReached && tree._listeners) { | |||||
// The next element has a _listeners, add it to the handlers. | |||||
listeners = listeners.concat(searchListenerTree(handlers, type, tree, typeLength)); | |||||
} | |||||
for (branch in tree) { | |||||
if (branch !== '_listeners' && tree.hasOwnProperty(branch)) { | |||||
if(branch === '*' || branch === '**') { | |||||
if(tree[branch]._listeners && !endReached) { | |||||
listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], typeLength)); | |||||
} | |||||
listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i)); | |||||
} else if(branch === nextType) { | |||||
listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i+2)); | |||||
} else { | |||||
// No match on this one, shift into the tree but not in the type array. | |||||
listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i)); | |||||
} | |||||
} | |||||
} | |||||
return listeners; | |||||
} | |||||
listeners = listeners.concat(searchListenerTree(handlers, type, tree[currentType], i+1)); | |||||
} | |||||
xTree = tree['*']; | |||||
if (xTree) { | |||||
// | |||||
// If the listener tree will allow any match for this part, | |||||
// then recursively explore all branches of the tree | |||||
// | |||||
searchListenerTree(handlers, type, xTree, i+1); | |||||
} | |||||
xxTree = tree['**']; | |||||
if(xxTree) { | |||||
if(i < typeLength) { | |||||
if(xxTree._listeners) { | |||||
// If we have a listener on a '**', it will catch all, so add its handler. | |||||
searchListenerTree(handlers, type, xxTree, typeLength); | |||||
} | |||||
// Build arrays of matching next branches and others. | |||||
for(branch in xxTree) { | |||||
if(branch !== '_listeners' && xxTree.hasOwnProperty(branch)) { | |||||
if(branch === nextType) { | |||||
// We know the next element will match, so jump twice. | |||||
searchListenerTree(handlers, type, xxTree[branch], i+2); | |||||
} else if(branch === currentType) { | |||||
// Current node matches, move into the tree. | |||||
searchListenerTree(handlers, type, xxTree[branch], i+1); | |||||
} else { | |||||
isolatedBranch = {}; | |||||
isolatedBranch[branch] = xxTree[branch]; | |||||
searchListenerTree(handlers, type, { '**': isolatedBranch }, i+1); | |||||
} | |||||
} | |||||
} | |||||
} else if(xxTree._listeners) { | |||||
// We have reached the end and still on a '**' | |||||
searchListenerTree(handlers, type, xxTree, typeLength); | |||||
} else if(xxTree['*'] && xxTree['*']._listeners) { | |||||
searchListenerTree(handlers, type, xxTree['*'], typeLength); | |||||
} | |||||
} | |||||
return listeners; | |||||
} | |||||
function growListenerTree(type, listener) { | |||||
type = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); | |||||
// | |||||
// Looks for two consecutive '**', if so, don't add the event at all. | |||||
// | |||||
for(var i = 0, len = type.length; i+1 < len; i++) { | |||||
if(type[i] === '**' && type[i+1] === '**') { | |||||
return; | |||||
} | |||||
} | |||||
var tree = this.listenerTree; | |||||
var name = type.shift(); | |||||
while (name !== undefined) { | |||||
if (!tree[name]) { | |||||
tree[name] = {}; | |||||
} | |||||
tree = tree[name]; | |||||
if (type.length === 0) { | |||||
if (!tree._listeners) { | |||||
tree._listeners = listener; | |||||
} | |||||
else { | |||||
if (typeof tree._listeners === 'function') { | |||||
tree._listeners = [tree._listeners]; | |||||
} | |||||
tree._listeners.push(listener); | |||||
if ( | |||||
!tree._listeners.warned && | |||||
this._maxListeners > 0 && | |||||
tree._listeners.length > this._maxListeners | |||||
) { | |||||
tree._listeners.warned = true; | |||||
logPossibleMemoryLeak.call(this, tree._listeners.length, name); | |||||
} | |||||
} | |||||
return true; | |||||
} | |||||
name = type.shift(); | |||||
} | |||||
return true; | |||||
} | |||||
// By default EventEmitters will print a warning if more than | |||||
// 10 listeners are added to it. This is a useful default which | |||||
// helps finding memory leaks. | |||||
// | |||||
// Obviously not all Emitters should be limited to 10. This function allows | |||||
// that to be increased. Set to zero for unlimited. | |||||
EventEmitter.prototype.delimiter = '.'; | |||||
EventEmitter.prototype.setMaxListeners = function(n) { | |||||
if (n !== undefined) { | |||||
this._maxListeners = n; | |||||
if (!this._conf) this._conf = {}; | |||||
this._conf.maxListeners = n; | |||||
} | |||||
}; | |||||
EventEmitter.prototype.event = ''; | |||||
EventEmitter.prototype.once = function(event, fn) { | |||||
return this._once(event, fn, false); | |||||
}; | |||||
EventEmitter.prototype.prependOnceListener = function(event, fn) { | |||||
return this._once(event, fn, true); | |||||
}; | |||||
EventEmitter.prototype._once = function(event, fn, prepend) { | |||||
this._many(event, 1, fn, prepend); | |||||
return this; | |||||
}; | |||||
EventEmitter.prototype.many = function(event, ttl, fn) { | |||||
return this._many(event, ttl, fn, false); | |||||
} | |||||
EventEmitter.prototype.prependMany = function(event, ttl, fn) { | |||||
return this._many(event, ttl, fn, true); | |||||
} | |||||
EventEmitter.prototype._many = function(event, ttl, fn, prepend) { | |||||
var self = this; | |||||
if (typeof fn !== 'function') { | |||||
throw new Error('many only accepts instances of Function'); | |||||
} | |||||
function listener() { | |||||
if (--ttl === 0) { | |||||
self.off(event, listener); | |||||
} | |||||
return fn.apply(this, arguments); | |||||
} | |||||
listener._origin = fn; | |||||
this._on(event, listener, prepend); | |||||
return self; | |||||
}; | |||||
EventEmitter.prototype.emit = function() { | |||||
if (!this._events && !this._all) { | |||||
return false; | |||||
} | |||||
this._events || init.call(this); | |||||
var type = arguments[0]; | |||||
if (type === 'newListener' && !this._newListener) { | |||||
if (!this._events.newListener) { | |||||
return false; | |||||
} | |||||
} | |||||
var al = arguments.length; | |||||
var args,l,i,j; | |||||
var handler; | |||||
if (this._all && this._all.length) { | |||||
handler = this._all.slice(); | |||||
if (al > 3) { | |||||
args = new Array(al); | |||||
for (j = 0; j < al; j++) args[j] = arguments[j]; | |||||
} | |||||
for (i = 0, l = handler.length; i < l; i++) { | |||||
this.event = type; | |||||
switch (al) { | |||||
case 1: | |||||
handler[i].call(this, type); | |||||
break; | |||||
case 2: | |||||
handler[i].call(this, type, arguments[1]); | |||||
break; | |||||
case 3: | |||||
handler[i].call(this, type, arguments[1], arguments[2]); | |||||
break; | |||||
default: | |||||
handler[i].apply(this, args); | |||||
} | |||||
} | |||||
} | |||||
if (this.wildcard) { | |||||
handler = []; | |||||
var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); | |||||
searchListenerTree.call(this, handler, ns, this.listenerTree, 0); | |||||
} else { | |||||
handler = this._events[type]; | |||||
if (typeof handler === 'function') { | |||||
this.event = type; | |||||
switch (al) { | |||||
case 1: | |||||
handler.call(this); | |||||
break; | |||||
case 2: | |||||
handler.call(this, arguments[1]); | |||||
break; | |||||
case 3: | |||||
handler.call(this, arguments[1], arguments[2]); | |||||
break; | |||||
default: | |||||
args = new Array(al - 1); | |||||
for (j = 1; j < al; j++) args[j - 1] = arguments[j]; | |||||
handler.apply(this, args); | |||||
} | |||||
return true; | |||||
} else if (handler) { | |||||
// need to make copy of handlers because list can change in the middle | |||||
// of emit call | |||||
handler = handler.slice(); | |||||
} | |||||
} | |||||
if (handler && handler.length) { | |||||
if (al > 3) { | |||||
args = new Array(al - 1); | |||||
for (j = 1; j < al; j++) args[j - 1] = arguments[j]; | |||||
} | |||||
for (i = 0, l = handler.length; i < l; i++) { | |||||
this.event = type; | |||||
switch (al) { | |||||
case 1: | |||||
handler[i].call(this); | |||||
break; | |||||
case 2: | |||||
handler[i].call(this, arguments[1]); | |||||
break; | |||||
case 3: | |||||
handler[i].call(this, arguments[1], arguments[2]); | |||||
break; | |||||
default: | |||||
handler[i].apply(this, args); | |||||
} | |||||
} | |||||
return true; | |||||
} else if (!this._all && type === 'error') { | |||||
if (arguments[1] instanceof Error) { | |||||
throw arguments[1]; // Unhandled 'error' event | |||||
} else { | |||||
throw new Error("Uncaught, unspecified 'error' event."); | |||||
} | |||||
return false; | |||||
} | |||||
return !!this._all; | |||||
}; | |||||
EventEmitter.prototype.emitAsync = function() { | |||||
if (!this._events && !this._all) { | |||||
return false; | |||||
} | |||||
this._events || init.call(this); | |||||
var type = arguments[0]; | |||||
if (type === 'newListener' && !this._newListener) { | |||||
if (!this._events.newListener) { return Promise.resolve([false]); } | |||||
} | |||||
var promises= []; | |||||
var al = arguments.length; | |||||
var args,l,i,j; | |||||
var handler; | |||||
if (this._all) { | |||||
if (al > 3) { | |||||
args = new Array(al); | |||||
for (j = 1; j < al; j++) args[j] = arguments[j]; | |||||
} | |||||
for (i = 0, l = this._all.length; i < l; i++) { | |||||
this.event = type; | |||||
switch (al) { | |||||
case 1: | |||||
promises.push(this._all[i].call(this, type)); | |||||
break; | |||||
case 2: | |||||
promises.push(this._all[i].call(this, type, arguments[1])); | |||||
break; | |||||
case 3: | |||||
promises.push(this._all[i].call(this, type, arguments[1], arguments[2])); | |||||
break; | |||||
default: | |||||
promises.push(this._all[i].apply(this, args)); | |||||
} | |||||
} | |||||
} | |||||
if (this.wildcard) { | |||||
handler = []; | |||||
var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); | |||||
searchListenerTree.call(this, handler, ns, this.listenerTree, 0); | |||||
} else { | |||||
handler = this._events[type]; | |||||
} | |||||
if (typeof handler === 'function') { | |||||
this.event = type; | |||||
switch (al) { | |||||
case 1: | |||||
promises.push(handler.call(this)); | |||||
break; | |||||
case 2: | |||||
promises.push(handler.call(this, arguments[1])); | |||||
break; | |||||
case 3: | |||||
promises.push(handler.call(this, arguments[1], arguments[2])); | |||||
break; | |||||
default: | |||||
args = new Array(al - 1); | |||||
for (j = 1; j < al; j++) args[j - 1] = arguments[j]; | |||||
promises.push(handler.apply(this, args)); | |||||
} | |||||
} else if (handler && handler.length) { | |||||
handler = handler.slice(); | |||||
if (al > 3) { | |||||
args = new Array(al - 1); | |||||
for (j = 1; j < al; j++) args[j - 1] = arguments[j]; | |||||
} | |||||
for (i = 0, l = handler.length; i < l; i++) { | |||||
this.event = type; | |||||
switch (al) { | |||||
case 1: | |||||
promises.push(handler[i].call(this)); | |||||
break; | |||||
case 2: | |||||
promises.push(handler[i].call(this, arguments[1])); | |||||
break; | |||||
case 3: | |||||
promises.push(handler[i].call(this, arguments[1], arguments[2])); | |||||
break; | |||||
default: | |||||
promises.push(handler[i].apply(this, args)); | |||||
} | |||||
} | |||||
} else if (!this._all && type === 'error') { | |||||
if (arguments[1] instanceof Error) { | |||||
return Promise.reject(arguments[1]); // Unhandled 'error' event | |||||
} else { | |||||
return Promise.reject("Uncaught, unspecified 'error' event."); | |||||
} | |||||
} | |||||
return Promise.all(promises); | |||||
}; | |||||
EventEmitter.prototype.on = function(type, listener) { | |||||
return this._on(type, listener, false); | |||||
}; | |||||
EventEmitter.prototype.prependListener = function(type, listener) { | |||||
return this._on(type, listener, true); | |||||
}; | |||||
EventEmitter.prototype.onAny = function(fn) { | |||||
return this._onAny(fn, false); | |||||
}; | |||||
EventEmitter.prototype.prependAny = function(fn) { | |||||
return this._onAny(fn, true); | |||||
}; | |||||
EventEmitter.prototype.addListener = EventEmitter.prototype.on; | |||||
EventEmitter.prototype._onAny = function(fn, prepend){ | |||||
if (typeof fn !== 'function') { | |||||
throw new Error('onAny only accepts instances of Function'); | |||||
} | |||||
if (!this._all) { | |||||
this._all = []; | |||||
} | |||||
// Add the function to the event listener collection. | |||||
if(prepend){ | |||||
this._all.unshift(fn); | |||||
}else{ | |||||
this._all.push(fn); | |||||
} | |||||
return this; | |||||
} | |||||
EventEmitter.prototype._on = function(type, listener, prepend) { | |||||
if (typeof type === 'function') { | |||||
this._onAny(type, listener); | |||||
return this; | |||||
} | |||||
if (typeof listener !== 'function') { | |||||
throw new Error('on only accepts instances of Function'); | |||||
} | |||||
this._events || init.call(this); | |||||
// To avoid recursion in the case that type == "newListeners"! Before | |||||
// adding it to the listeners, first emit "newListeners". | |||||
if (this._newListener) | |||||
this.emit('newListener', type, listener); | |||||
if (this.wildcard) { | |||||
growListenerTree.call(this, type, listener); | |||||
return this; | |||||
} | |||||
if (!this._events[type]) { | |||||
// Optimize the case of one listener. Don't need the extra array object. | |||||
this._events[type] = listener; | |||||
} | |||||
else { | |||||
if (typeof this._events[type] === 'function') { | |||||
// Change to array. | |||||
this._events[type] = [this._events[type]]; | |||||
} | |||||
// If we've already got an array, just add | |||||
if(prepend){ | |||||
this._events[type].unshift(listener); | |||||
}else{ | |||||
this._events[type].push(listener); | |||||
} | |||||
// Check for listener leak | |||||
if ( | |||||
!this._events[type].warned && | |||||
this._maxListeners > 0 && | |||||
this._events[type].length > this._maxListeners | |||||
) { | |||||
this._events[type].warned = true; | |||||
logPossibleMemoryLeak.call(this, this._events[type].length, type); | |||||
} | |||||
} | |||||
return this; | |||||
} | |||||
EventEmitter.prototype.off = function(type, listener) { | |||||
if (typeof listener !== 'function') { | |||||
throw new Error('removeListener only takes instances of Function'); | |||||
} | |||||
var handlers,leafs=[]; | |||||
if(this.wildcard) { | |||||
var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); | |||||
leafs = searchListenerTree.call(this, null, ns, this.listenerTree, 0); | |||||
} | |||||
else { | |||||
// does not use listeners(), so no side effect of creating _events[type] | |||||
if (!this._events[type]) return this; | |||||
handlers = this._events[type]; | |||||
leafs.push({_listeners:handlers}); | |||||
} | |||||
for (var iLeaf=0; iLeaf<leafs.length; iLeaf++) { | |||||
var leaf = leafs[iLeaf]; | |||||
handlers = leaf._listeners; | |||||
if (isArray(handlers)) { | |||||
var position = -1; | |||||
for (var i = 0, length = handlers.length; i < length; i++) { | |||||
if (handlers[i] === listener || | |||||
(handlers[i].listener && handlers[i].listener === listener) || | |||||
(handlers[i]._origin && handlers[i]._origin === listener)) { | |||||
position = i; | |||||
break; | |||||
} | |||||
} | |||||
if (position < 0) { | |||||
continue; | |||||
} | |||||
if(this.wildcard) { | |||||
leaf._listeners.splice(position, 1); | |||||
} | |||||
else { | |||||
this._events[type].splice(position, 1); | |||||
} | |||||
if (handlers.length === 0) { | |||||
if(this.wildcard) { | |||||
delete leaf._listeners; | |||||
} | |||||
else { | |||||
delete this._events[type]; | |||||
} | |||||
} | |||||
if (this._removeListener) | |||||
this.emit("removeListener", type, listener); | |||||
return this; | |||||
} | |||||
else if (handlers === listener || | |||||
(handlers.listener && handlers.listener === listener) || | |||||
(handlers._origin && handlers._origin === listener)) { | |||||
if(this.wildcard) { | |||||
delete leaf._listeners; | |||||
} | |||||
else { | |||||
delete this._events[type]; | |||||
} | |||||
if (this._removeListener) | |||||
this.emit("removeListener", type, listener); | |||||
} | |||||
} | |||||
function recursivelyGarbageCollect(root) { | |||||
if (root === undefined) { | |||||
return; | |||||
} | |||||
var keys = Object.keys(root); | |||||
for (var i in keys) { | |||||
var key = keys[i]; | |||||
var obj = root[key]; | |||||
if ((obj instanceof Function) || (typeof obj !== "object") || (obj === null)) | |||||
continue; | |||||
if (Object.keys(obj).length > 0) { | |||||
recursivelyGarbageCollect(root[key]); | |||||
} | |||||
if (Object.keys(obj).length === 0) { | |||||
delete root[key]; | |||||
} | |||||
} | |||||
} | |||||
recursivelyGarbageCollect(this.listenerTree); | |||||
return this; | |||||
}; | |||||
EventEmitter.prototype.offAny = function(fn) { | |||||
var i = 0, l = 0, fns; | |||||
if (fn && this._all && this._all.length > 0) { | |||||
fns = this._all; | |||||
for(i = 0, l = fns.length; i < l; i++) { | |||||
if(fn === fns[i]) { | |||||
fns.splice(i, 1); | |||||
if (this._removeListener) | |||||
this.emit("removeListenerAny", fn); | |||||
return this; | |||||
} | |||||
} | |||||
} else { | |||||
fns = this._all; | |||||
if (this._removeListener) { | |||||
for(i = 0, l = fns.length; i < l; i++) | |||||
this.emit("removeListenerAny", fns[i]); | |||||
} | |||||
this._all = []; | |||||
} | |||||
return this; | |||||
}; | |||||
EventEmitter.prototype.removeListener = EventEmitter.prototype.off; | |||||
EventEmitter.prototype.removeAllListeners = function(type) { | |||||
if (type === undefined) { | |||||
!this._events || init.call(this); | |||||
return this; | |||||
} | |||||
if (this.wildcard) { | |||||
var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); | |||||
var leafs = searchListenerTree.call(this, null, ns, this.listenerTree, 0); | |||||
for (var iLeaf=0; iLeaf<leafs.length; iLeaf++) { | |||||
var leaf = leafs[iLeaf]; | |||||
leaf._listeners = null; | |||||
} | |||||
} | |||||
else if (this._events) { | |||||
this._events[type] = null; | |||||
} | |||||
return this; | |||||
}; | |||||
EventEmitter.prototype.listeners = function(type) { | |||||
if (this.wildcard) { | |||||
var handlers = []; | |||||
var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); | |||||
searchListenerTree.call(this, handlers, ns, this.listenerTree, 0); | |||||
return handlers; | |||||
} | |||||
this._events || init.call(this); | |||||
if (!this._events[type]) this._events[type] = []; | |||||
if (!isArray(this._events[type])) { | |||||
this._events[type] = [this._events[type]]; | |||||
} | |||||
return this._events[type]; | |||||
}; | |||||
EventEmitter.prototype.eventNames = function(){ | |||||
return Object.keys(this._events); | |||||
} | |||||
EventEmitter.prototype.listenerCount = function(type) { | |||||
return this.listeners(type).length; | |||||
}; | |||||
EventEmitter.prototype.listenersAny = function() { | |||||
if(this._all) { | |||||
return this._all; | |||||
} | |||||
else { | |||||
return []; | |||||
} | |||||
}; | |||||
if (typeof define === 'function' && define.amd) { | |||||
// AMD. Register as an anonymous module. | |||||
define(function() { | |||||
return EventEmitter; | |||||
}); | |||||
} else if (typeof exports === 'object') { | |||||
// CommonJS | |||||
module.exports = EventEmitter; | |||||
} | |||||
else { | |||||
// Browser global. | |||||
window.EventEmitter2 = EventEmitter; | |||||
} | |||||
}(); | |||||
}, function(modId) {var map = {}; return __REQUIRE__(map[modId], modId); }) | |||||
return __REQUIRE__(1585827830357); | |||||
})() | |||||
//# sourceMappingURL=index.js.map |
@ -0,0 +1,191 @@ | |||||
const app = getApp(); | |||||
var longUtil = require('./../../utils/long'); | |||||
var util = require('../../utils/util'); | |||||
import { BLE } from "./../../utils/btls/ble"; | |||||
const emitter = app.globalData.emitter | |||||
Page({ | |||||
/** | |||||
* 页面的初始数据 | |||||
*/ | |||||
data: { | |||||
baseUrlImg: app.globalData.baseUrlImg, | |||||
bleStatus: false, | |||||
respond: [], | |||||
blueyes: false, //是否重发同步指令 | |||||
connectStatus: "", | |||||
info:"未初始化蓝牙适配器", | |||||
}, | |||||
btntest1(event){ | |||||
var that = this; | |||||
this.startconnect() | |||||
}, | |||||
btntest2(event){ | |||||
var that = this | |||||
let userTelephone = "13028878230" | |||||
let userPassword = "130288" | |||||
let pwd = "12344321" | |||||
let openLockType = 2 | |||||
this.openLock(userTelephone, userPassword, pwd, openLockType) | |||||
}, | |||||
//获取输入框的数据 | |||||
getmsg(event){ | |||||
this.setData({ | |||||
sendmsg:event.detail.value | |||||
}) | |||||
}, | |||||
btntest3(event){ | |||||
var that = this; | |||||
this.closeblue() | |||||
}, | |||||
startconnect() { | |||||
//if(checkWechatVersion()) | |||||
{ | |||||
const ble = new BLE("yxwl01680000004895", emitter) | |||||
app.globalData.ble = ble | |||||
this.watchBLE() | |||||
app.globalData.ble.init() | |||||
} | |||||
}, | |||||
watchBLE() { | |||||
if (app.globalData.ble) { | |||||
app.globalData.ble.listen(res => { | |||||
if (res.type == 'connect') { | |||||
if (res.data == "未打开适配器") { | |||||
wx.showModal({ | |||||
title: "提示", | |||||
content: "请检查手机蓝牙和定位功能是否打开?", | |||||
showCancel: false, | |||||
confirmText: "确定", | |||||
}); | |||||
} else { | |||||
this.setData({ | |||||
info: res.data | |||||
}) | |||||
app.globalData.bleStatus = res.data | |||||
} | |||||
} | |||||
}) | |||||
} | |||||
}, | |||||
closeblue() { | |||||
wx.showLoading({ | |||||
title: "正在停止...", | |||||
}); | |||||
app.globalData.ble.close() | |||||
setTimeout(() => { | |||||
wx.hideLoading() | |||||
}, 1000); | |||||
app.globalData.bleStatus = false | |||||
this.setData({ | |||||
bleStatus: false, | |||||
respond: [] | |||||
}) | |||||
}, | |||||
openLock(userTelephone, userPassword, pwd, openLockType) { | |||||
wx.showLoading({ | |||||
title: "正在发送...", | |||||
}); | |||||
setTimeout(() => { | |||||
wx.hideLoading() | |||||
}, 1000); | |||||
let cmd = 0x41 | |||||
let ut = util.stringToUint8Array(userTelephone) | |||||
let up = util.stringToUint8Array(userPassword) | |||||
let p = util.hexStringToBytesWithPadding(pwd, 10, 0xff) | |||||
let length = 1+11+6+10+1 | |||||
let b = new Uint8Array(length) | |||||
b[0] = cmd | |||||
b.set(ut, 1) | |||||
b.set(up, 12) | |||||
b.set(p, 18) | |||||
b[28] = openLockType | |||||
console.log(b) | |||||
app.globalData.ble.send(cmd, b, length) | |||||
}, | |||||
}) | |||||
/** | |||||
* 版本比较 | |||||
*/ | |||||
function versionCompare (ver1, ver2) { //版本比较 | |||||
// console.log("ver1" + ver1 + 'ver2' + ver2); | |||||
var version1pre = parseFloat(ver1) | |||||
var version2pre = parseFloat(ver2) | |||||
var version1next = parseInt(ver1.replace(version1pre + ".", "")) | |||||
var version2next = parseInt(ver2.replace(version2pre + ".", "")) | |||||
if (version1pre > version2pre) | |||||
return true | |||||
else if (version1pre < version2pre) | |||||
return false | |||||
else { | |||||
if (version1next > version2next) | |||||
return true | |||||
else | |||||
return false | |||||
} | |||||
} | |||||
/** | |||||
* 微信版本检测 | |||||
* Android从微信 6.5.7 开始支持,iOS从微信 6.5.6 开始支持 | |||||
*/ | |||||
function checkWechatVersion() { | |||||
wx.getSystemInfo({ | |||||
success: function (res) { | |||||
let si = res; | |||||
if (si.platform == 'android' && versionCompare('6.5.7', si.version)) { | |||||
console.log("当前安卓微信版本过低,请更新至最新版本体验"); | |||||
wx.showModal({ | |||||
title: '提示', | |||||
content: '当前微信版本过低,请更新至最新版本体验', | |||||
showCancel: false | |||||
}) | |||||
return false; | |||||
}else if (si.platform == 'ios' && versionCompare('6.5.6', si.version)) { | |||||
console.log("当前苹果微信版本过低,请更新至最新版本体验"); | |||||
wx.showModal({ | |||||
title: '提示', | |||||
content: '当前微信版本过低,请更新至最新版本体验', | |||||
showCancel: false | |||||
}) | |||||
return false; | |||||
} | |||||
return true; | |||||
} | |||||
}) | |||||
} | |||||
@ -0,0 +1,3 @@ | |||||
{ | |||||
"usingComponents": {} | |||||
} |
@ -0,0 +1,18 @@ | |||||
<!--pages/asyntest/asyntest.wxml--> | |||||
<view class="contentview"> | |||||
<view class='myview' > | |||||
{{info}} | |||||
</view> | |||||
<button type="primary" class="button" bindtap="btntest1">初始化蓝牙</button> | |||||
<view class="section"> | |||||
<input placeholder='请输入要发送的信息' bindinput='getmsg'/> | |||||
</view> | |||||
<button type="primary" class="button" bindtap="btntest2">微信发送消息</button> | |||||
<button type="primary" class="button" bindtap="btntest3">断开蓝牙设备</button> | |||||
</view> |
@ -0,0 +1,28 @@ | |||||
/* pages/asyntest/asyntest.wxss */ | |||||
.vertical{ | |||||
display: flex; | |||||
flex-direction: column; | |||||
} | |||||
/**index.wxss**/ | |||||
.horizontal{ | |||||
display: flex; | |||||
flex-direction: row; | |||||
} | |||||
.btinfo{ | |||||
height:100px; | |||||
} | |||||
.contentview { | |||||
margin: 0 10px; | |||||
} | |||||
.button { | |||||
margin: 5px; | |||||
} | |||||
.myview{ | |||||
height:200px; | |||||
word-break:break-all;/* 自动换行 */ | |||||
} |
@ -0,0 +1,212 @@ | |||||
const app = getApp() | |||||
function inArray(arr, key, val) { | |||||
for (let i = 0; i < arr.length; i++) { | |||||
if (arr[i][key] === val) { | |||||
return i; | |||||
} | |||||
} | |||||
return -1; | |||||
} | |||||
// ArrayBuffer转16进度字符串示例 | |||||
function ab2hex(buffer) { | |||||
var hexArr = Array.prototype.map.call( | |||||
new Uint8Array(buffer), | |||||
function (bit) { | |||||
return ('00' + bit.toString(16)).slice(-2) | |||||
} | |||||
) | |||||
return hexArr.join(''); | |||||
} | |||||
Page({ | |||||
data: { | |||||
devices: [], | |||||
connected: false, | |||||
chs: [], | |||||
}, | |||||
openBluetoothAdapter() { | |||||
wx.openBluetoothAdapter({ | |||||
success: (res) => { | |||||
console.log('openBluetoothAdapter success', res) | |||||
this.startBluetoothDevicesDiscovery() | |||||
}, | |||||
fail: (res) => { | |||||
if (res.errCode === 10001) { | |||||
wx.onBluetoothAdapterStateChange(function (res) { | |||||
console.log('onBluetoothAdapterStateChange', res) | |||||
if (res.available) { | |||||
this.startBluetoothDevicesDiscovery() | |||||
} | |||||
}) | |||||
} | |||||
} | |||||
}) | |||||
}, | |||||
getBluetoothAdapterState() { | |||||
wx.getBluetoothAdapterState({ | |||||
success: (res) => { | |||||
console.log('getBluetoothAdapterState', res) | |||||
if (res.discovering) { | |||||
this.onBluetoothDeviceFound() | |||||
} else if (res.available) { | |||||
this.startBluetoothDevicesDiscovery() | |||||
} | |||||
} | |||||
}) | |||||
}, | |||||
startBluetoothDevicesDiscovery() { | |||||
if (this._discoveryStarted) { | |||||
return | |||||
} | |||||
this._discoveryStarted = true | |||||
wx.startBluetoothDevicesDiscovery({ | |||||
allowDuplicatesKey: true, | |||||
success: (res) => { | |||||
console.log('startBluetoothDevicesDiscovery success', res) | |||||
this.onBluetoothDeviceFound() | |||||
}, | |||||
}) | |||||
}, | |||||
stopBluetoothDevicesDiscovery() { | |||||
wx.stopBluetoothDevicesDiscovery() | |||||
}, | |||||
onBluetoothDeviceFound() { | |||||
wx.onBluetoothDeviceFound((res) => { | |||||
res.devices.forEach(device => { | |||||
if (!device.name && !device.localName) { | |||||
return | |||||
} | |||||
const foundDevices = this.data.devices | |||||
const idx = inArray(foundDevices, 'deviceId', device.deviceId) | |||||
const data = {} | |||||
if (idx === -1) { | |||||
data[`devices[${foundDevices.length}]`] = device | |||||
} else { | |||||
data[`devices[${idx}]`] = device | |||||
} | |||||
this.setData(data) | |||||
}) | |||||
}) | |||||
}, | |||||
createBLEConnection(e) { | |||||
const ds = e.currentTarget.dataset | |||||
const deviceId = ds.deviceId | |||||
const name = ds.name | |||||
wx.createBLEConnection({ | |||||
deviceId, | |||||
success: (res) => { | |||||
this.setData({ | |||||
connected: true, | |||||
name, | |||||
deviceId, | |||||
}) | |||||
this.getBLEDeviceServices(deviceId) | |||||
} | |||||
}) | |||||
this.stopBluetoothDevicesDiscovery() | |||||
}, | |||||
closeBLEConnection() { | |||||
wx.closeBLEConnection({ | |||||
deviceId: this.data.deviceId | |||||
}) | |||||
this.setData({ | |||||
connected: false, | |||||
chs: [], | |||||
canWrite: false, | |||||
}) | |||||
}, | |||||
getBLEDeviceServices(deviceId) { | |||||
wx.getBLEDeviceServices({ | |||||
deviceId, | |||||
success: (res) => { | |||||
for (let i = 0; i < res.services.length; i++) { | |||||
if (res.services[i].isPrimary) { | |||||
this.getBLEDeviceCharacteristics(deviceId, res.services[i].uuid) | |||||
return | |||||
} | |||||
} | |||||
} | |||||
}) | |||||
}, | |||||
getBLEDeviceCharacteristics(deviceId, serviceId) { | |||||
wx.getBLEDeviceCharacteristics({ | |||||
deviceId, | |||||
serviceId, | |||||
success: (res) => { | |||||
console.log('getBLEDeviceCharacteristics success', res.characteristics) | |||||
for (let i = 0; i < res.characteristics.length; i++) { | |||||
let item = res.characteristics[i] | |||||
if (item.properties.read) { | |||||
wx.readBLECharacteristicValue({ | |||||
deviceId, | |||||
serviceId, | |||||
characteristicId: item.uuid, | |||||
}) | |||||
} | |||||
if (item.properties.write) { | |||||
this.setData({ | |||||
canWrite: true | |||||
}) | |||||
this._deviceId = deviceId | |||||
this._serviceId = serviceId | |||||
this._characteristicId = item.uuid | |||||
this.writeBLECharacteristicValue() | |||||
} | |||||
if (item.properties.notify || item.properties.indicate) { | |||||
wx.notifyBLECharacteristicValueChange({ | |||||
deviceId, | |||||
serviceId, | |||||
characteristicId: item.uuid, | |||||
state: true, | |||||
}) | |||||
} | |||||
} | |||||
}, | |||||
fail(res) { | |||||
console.error('getBLEDeviceCharacteristics', res) | |||||
} | |||||
}) | |||||
// 操作之前先监听,保证第一时间获取数据 | |||||
wx.onBLECharacteristicValueChange((characteristic) => { | |||||
const idx = inArray(this.data.chs, 'uuid', characteristic.characteristicId) | |||||
const data = {} | |||||
if (idx === -1) { | |||||
data[`chs[${this.data.chs.length}]`] = { | |||||
uuid: characteristic.characteristicId, | |||||
value: ab2hex(characteristic.value) | |||||
} | |||||
} else { | |||||
data[`chs[${idx}]`] = { | |||||
uuid: characteristic.characteristicId, | |||||
value: ab2hex(characteristic.value) | |||||
} | |||||
} | |||||
// data[`chs[${this.data.chs.length}]`] = { | |||||
// uuid: characteristic.characteristicId, | |||||
// value: ab2hex(characteristic.value) | |||||
// } | |||||
this.setData(data) | |||||
}) | |||||
}, | |||||
writeBLECharacteristicValue() { | |||||
// 向蓝牙设备发送一个0x00的16进制数据 | |||||
let buffer = new ArrayBuffer(1) | |||||
let dataView = new DataView(buffer) | |||||
dataView.setUint8(0, Math.random() * 255 | 0) | |||||
wx.writeBLECharacteristicValue({ | |||||
deviceId: this._deviceId, | |||||
serviceId: this._deviceId, | |||||
characteristicId: this._characteristicId, | |||||
value: buffer, | |||||
}) | |||||
}, | |||||
closeBluetoothAdapter() { | |||||
wx.closeBluetoothAdapter() | |||||
this._discoveryStarted = false | |||||
}, | |||||
}) |
@ -0,0 +1,3 @@ | |||||
{ | |||||
"usingComponents": {} | |||||
} |
@ -0,0 +1,41 @@ | |||||
<wxs module="utils"> | |||||
module.exports.max = function(n1, n2) { | |||||
return Math.max(n1, n2) | |||||
} | |||||
module.exports.len = function(arr) { | |||||
arr = arr || [] | |||||
return arr.length | |||||
} | |||||
</wxs> | |||||
<button bindtap="openBluetoothAdapter">开始扫描</button> | |||||
<button bindtap="stopBluetoothDevicesDiscovery">停止扫描</button> | |||||
<button bindtap="closeBluetoothAdapter">结束流程</button> | |||||
<view class="devices_summary">已发现 {{devices.length}} 个外围设备:</view> | |||||
<scroll-view class="device_list" scroll-y scroll-with-animation> | |||||
<view wx:for="{{devices}}" wx:key="index" | |||||
data-device-id="{{item.deviceId}}" | |||||
data-name="{{item.name || item.localName}}" | |||||
bindtap="createBLEConnection" | |||||
class="device_item" | |||||
hover-class="device_item_hover"> | |||||
<view style="font-size: 16px; color: #333;">{{item.name}}</view> | |||||
<view style="font-size: 10px">信号强度: {{item.RSSI}}dBm ({{utils.max(0, item.RSSI + 100)}}%)</view> | |||||
<view style="font-size: 10px">UUID: {{item.deviceId}}</view> | |||||
<view style="font-size: 10px">Service数量: {{utils.len(item.advertisServiceUUIDs)}}</view> | |||||
</view> | |||||
</scroll-view> | |||||
<view class="connected_info" wx:if="{{connected}}"> | |||||
<view> | |||||
<text>已连接到 {{name}}</text> | |||||
<view class="operation"> | |||||
<button wx:if="{{canWrite}}" size="mini" bindtap="writeBLECharacteristicValue">写数据</button> | |||||
<button size="mini" bindtap="closeBLEConnection">断开连接</button> | |||||
</view> | |||||
</view> | |||||
<view wx:for="{{chs}}" wx:key="index" style="font-size: 12px; margin-top: 10px;"> | |||||
<view>特性UUID: {{item.uuid}}</view> | |||||
<view>特性值: {{item.value}}</view> | |||||
</view> | |||||
</view> |
@ -0,0 +1,41 @@ | |||||
page { | |||||
color: #333; | |||||
} | |||||
.devices_summary { | |||||
margin-top: 30px; | |||||
padding: 10px; | |||||
font-size: 16px; | |||||
} | |||||
.device_list { | |||||
height: 300px; | |||||
margin: 50px 5px; | |||||
margin-top: 0; | |||||
border: 1px solid #EEE; | |||||
border-radius: 5px; | |||||
width: auto; | |||||
} | |||||
.device_item { | |||||
border-bottom: 1px solid #EEE; | |||||
padding: 10px; | |||||
color: #666; | |||||
} | |||||
.device_item_hover { | |||||
background-color: rgba(0, 0, 0, .1); | |||||
} | |||||
.connected_info { | |||||
position: fixed; | |||||
bottom: 0; | |||||
width: 100%; | |||||
background-color: #F0F0F0; | |||||
padding: 10px; | |||||
padding-bottom: 20px; | |||||
margin-bottom: env(safe-area-inset-bottom); | |||||
font-size: 14px; | |||||
min-height: 100px; | |||||
box-shadow: 0px 0px 3px 0px; | |||||
} | |||||
.connected_info .operation { | |||||
position: absolute; | |||||
display: inline-block; | |||||
right: 30px; | |||||
} |
@ -0,0 +1,637 @@ | |||||
// pages/lanyatest/lanyatest.js | |||||
var longUtil = require('./../../utils/long.js'); | |||||
Page({ | |||||
/** | |||||
* 页面的初始数据 | |||||
*/ | |||||
data: { | |||||
info:"未初始化蓝牙适配器", | |||||
deviceName:"yxwl01680000004895", | |||||
connectedDeviceId:"", | |||||
deviceId:"", | |||||
services:"", | |||||
mtuSize:512, | |||||
servicesUUID:"000018f0-0000-1000-8000-00805f9b34fb", | |||||
notifyUUID:"00002af0-0000-1000-8000-00805f9b34fb", | |||||
writeUUID:"00002af1-0000-1000-8000-00805f9b34fb", | |||||
serviceId:"", | |||||
notifyCharacteristicsId:"", | |||||
writeCharacteristicsId: "", | |||||
userTelephone:"13028878230", | |||||
userPassword:"130288", | |||||
pwd:"12344321", | |||||
openLockType:2, | |||||
sendmsg:"8989415B017BC796C6F8001DA0B0AAB7AFABB1B6B9B1BAB7B0BE8989A9AB8BABBE80EEEEE2E2E6E6EFE4", | |||||
systemInfo:{}, | |||||
}, | |||||
lanyatest1(event){ | |||||
var that = this; | |||||
wx.getSystemInfo({ | |||||
success: function (res) { | |||||
console.log(res.model) | |||||
console.log(res.pixelRatio) | |||||
console.log(res.windowWidth) | |||||
console.log(res.windowHeight) | |||||
console.log(res.language) | |||||
console.log(res.version) | |||||
console.log(res.platform) | |||||
console.log(res.environment) | |||||
that.setData({ | |||||
systemInfo:res | |||||
}); | |||||
} | |||||
}) | |||||
checkWechatVersion(that.data.systemInfo) | |||||
wx.openBluetoothAdapter({ | |||||
success: function (res) { | |||||
console.log('初始化蓝牙适配器成功') | |||||
//页面日志显示 | |||||
that.setData({ | |||||
info: '初始化蓝牙适配器成功' | |||||
}) | |||||
}, | |||||
fail: function (res) { | |||||
console.log('请打开蓝牙和定位功能') | |||||
that.setData({ | |||||
info: '请打开蓝牙和定位功能' | |||||
}) | |||||
} | |||||
}) | |||||
}, | |||||
lanyatest2(event){ | |||||
var that = this; | |||||
wx.getBluetoothAdapterState({ | |||||
success: function (res) { | |||||
//打印相关信息 | |||||
console.log(JSON.stringify(res.errMsg) + "\n蓝牙是否可用:" + res.available); | |||||
that.setData({ | |||||
info: JSON.stringify(res.errMsg) +"\n蓝牙是否可用:" + res.available | |||||
}) | |||||
}, | |||||
fail: function (res) { | |||||
//打印相关信息 | |||||
console.log(JSON.stringify(res.errMsg) + "\n蓝牙是否可用:" + res.available); | |||||
that.setData({ | |||||
info: JSON.stringify(res.errMsg) + "\n蓝牙是否可用:" + res.available | |||||
}) | |||||
} | |||||
}) | |||||
}, | |||||
lanyatest3(event){ | |||||
var that = this; | |||||
wx.startBluetoothDevicesDiscovery({ | |||||
services: [that.data.servicesUUID], //如果填写了此UUID,那么只会搜索出含有这个UUID的设备 | |||||
success: function (res) { | |||||
that.setData({ | |||||
info: "搜索设备" + JSON.stringify(res), | |||||
}) | |||||
console.log('搜索设备返回' + JSON.stringify(res)) | |||||
} | |||||
}) | |||||
}, | |||||
lanyatest4(event){ | |||||
var that = this; | |||||
var pos; | |||||
wx.getBluetoothDevices({ | |||||
success: function (res) { | |||||
for (var i = 0; i < res.devices.length; i++) { | |||||
pos = that.data.deviceName.indexOf(res.devices[i].name); | |||||
if(pos != -1) | |||||
{ | |||||
that.setData({ | |||||
connectedDeviceId: res.devices[i].deviceId | |||||
}) | |||||
console.log('设备号:' + res.devices[i].name + " Mac地址: " + that.data.connectedDeviceId + " pos: " + pos + "\n") | |||||
break; | |||||
} | |||||
} | |||||
that.setData({ | |||||
info: "设备列表\n" + JSON.stringify(res.devices), | |||||
devices: res.devices | |||||
}) | |||||
console.log('搜设备数目:' + res.devices.length) | |||||
console.log('设备信息:\n' + JSON.stringify(res.devices)+"\n") | |||||
} | |||||
}) | |||||
}, | |||||
lanyaconnect(event){ | |||||
var that = this; | |||||
wx.createBLEConnection({ | |||||
deviceId: that.data.connectedDeviceId, | |||||
success: function (res) { | |||||
console.log('调试信息:' + res.errMsg); | |||||
that.setData({ | |||||
info: "MAC地址:" + event.currentTarget.id + ' 调试信息:' + res.errMsg, | |||||
}) | |||||
if (that.data.systemInfo.platform == 'android') | |||||
{ | |||||
wx.setBLEMTU({ | |||||
deviceId: that.data.connectedDeviceId, | |||||
mtu:that.data.mtuSize, | |||||
success:(res)=>{ | |||||
console.log("setBLEMTU success >> " + JSON.stringify(res)) | |||||
}, | |||||
fail:(res)=>{ | |||||
console.log("setBLEMTU fail >> " + JSON.stringify(res)) | |||||
} | |||||
}) | |||||
} | |||||
}, | |||||
fail: function () { | |||||
console.log("连接失败"); | |||||
}, | |||||
}) | |||||
}, | |||||
lanyatest6(event){ | |||||
var that = this; | |||||
wx.stopBluetoothDevicesDiscovery({ | |||||
success: function (res) { | |||||
console.log("停止搜索" + JSON.stringify(res.errMsg)); | |||||
that.setData({ | |||||
info: "停止搜索" + JSON.stringify(res.errMsg), | |||||
}) | |||||
} | |||||
}) | |||||
}, | |||||
lanyatest7(event){ | |||||
var that = this; | |||||
wx.getBLEDeviceServices({ | |||||
// 这里的 deviceId 需要在上面的 getBluetoothDevices 或 onBluetoothDeviceFound 接口中获取 | |||||
deviceId: that.data.connectedDeviceId, | |||||
success: function (res) { | |||||
console.log('services UUID:\n', JSON.stringify(res.services)); | |||||
for (var i = 0; i < res.services.length; i++) { | |||||
console.log("第"+(i+1) + "个UUID:" + res.services[i].uuid+"\n") | |||||
} | |||||
that.setData({ | |||||
services: res.services, | |||||
info: JSON.stringify(res.services), | |||||
}) | |||||
} | |||||
}) | |||||
}, | |||||
lanyatest8(event){ | |||||
var that = this; | |||||
var myUUID = toPlatformString(that.data.systemInfo, that.data.servicesUUID);//具有写、通知属性的服务uuid | |||||
console.log(' UUID: ' + myUUID + " mac: " + that.data.connectedDeviceId) | |||||
wx.getBLEDeviceCharacteristics({ | |||||
// 这里的 deviceId 需要在上面的接口中获取 | |||||
deviceId: that.data.connectedDeviceId, | |||||
// 这里的 serviceId 需要在上面的 接口中获取 | |||||
serviceId: myUUID, | |||||
success: function (res) { | |||||
console.log("%c getBLEDeviceCharacteristics", "color:red;"); | |||||
for (var i = 0; i < res.characteristics.length; i++) { | |||||
console.log('特征值:' + res.characteristics[i].uuid) | |||||
if (res.characteristics[i].properties.notify) { | |||||
console.log("notifyServicweId:", myUUID); | |||||
console.log("notifyCharacteristicsId:", res.characteristics[i].uuid); | |||||
that.setData({ | |||||
notifyServicweId: myUUID, | |||||
notifyCharacteristicsId: that.data.notifyUUID,//手动设置notifyCharacteristicsId为这个UUID,为了方便写死在这里 | |||||
}) | |||||
} | |||||
if (res.characteristics[i].properties.write) { | |||||
console.log("writeServicweId:", myUUID); | |||||
console.log("writeCharacteristicsId:", res.characteristics[i].uuid); | |||||
that.setData({ | |||||
writeServicweId: myUUID, | |||||
//writeCharacteristicsId: res.characteristics[i].uuid, | |||||
writeCharacteristicsId: that.data.writeUUID,//手动设置writeCharacteristicsId为这个UUID,为了方便写死在这里 | |||||
}) | |||||
} | |||||
} | |||||
console.log('device getBLEDeviceCharacteristics:', res.characteristics); | |||||
that.setData({ | |||||
msg: JSON.stringify(res.characteristics), | |||||
}) | |||||
}, | |||||
fail: function () { | |||||
console.log("fail"); | |||||
}, | |||||
}) | |||||
}, | |||||
lanyatest9(event){ | |||||
var that = this; | |||||
var notifyServicweId = toPlatformString(that.data.systemInfo, that.data.servicesUUID); //具有写、通知属性的服务uuid | |||||
var notifyCharacteristicsId = toPlatformString(that.data.systemInfo, that.data.notifyCharacteristicsId); | |||||
console.log("启用notify的serviceId", notifyServicweId); | |||||
console.log("启用notify的notifyCharacteristicsId", notifyCharacteristicsId); | |||||
wx.notifyBLECharacteristicValueChange({ | |||||
state: true, // 启用 notify 功能 | |||||
deviceId: that.data.connectedDeviceId, | |||||
// 这里的 serviceId 就是that.data.servicesUUID | |||||
serviceId: notifyServicweId, | |||||
characteristicId: notifyCharacteristicsId, | |||||
success: function (res) { | |||||
console.log('notifyBLECharacteristicValueChange success', res.errMsg) | |||||
var msg = '启动notify:' + res.errMsg | |||||
that.setData({ | |||||
info: msg | |||||
}) | |||||
}, | |||||
fail: function () { | |||||
console.log('启动notify:' + res.errMsg); | |||||
}, | |||||
}) | |||||
}, | |||||
lanyatest10(event){ | |||||
var that = this; | |||||
console.log("开始接收数据"); | |||||
wx.onBLECharacteristicValueChange(function (res) { | |||||
console.log("characteristicId:" + res.characteristicId) | |||||
console.log("serviceId: " + res.serviceId) | |||||
console.log("deviceId: " + res.deviceId) | |||||
console.log("Length: " + res.value.byteLength) | |||||
console.log("hex value: " + ab2hex(res.value)) | |||||
that.setData({ | |||||
info: that.data.info + ab2hex(res.value) | |||||
}) | |||||
}) | |||||
}, | |||||
lanyatest11(event){ | |||||
var that = this | |||||
//var hex = that.data.sendmsg //要发送的信息 | |||||
var myUUID = toPlatformString(that.data.systemInfo, that.data.servicesUUID); //具有写、通知属性的服务uuid | |||||
var writeCharId = toPlatformString(that.data.systemInfo, that.data.writeCharacteristicsId); | |||||
//console.log('要发送的信息是:'+hex) | |||||
//var typedArray1 = new Uint8Array(hex.match(/[\da-f]{2}/gi).map(function (h) { | |||||
// return parseInt(h, 16) | |||||
//})) | |||||
//console.log(typedArray1) | |||||
var typedArray = packData(that.data.userTelephone, that.data.userPassword, that.data.pwd, that.data.openLockType) | |||||
console.log(typedArray) | |||||
wx.writeBLECharacteristicValue({ | |||||
deviceId: that.data.connectedDeviceId, | |||||
serviceId: myUUID, | |||||
characteristicId: writeCharId, | |||||
// 这里的value是ArrayBuffer类型 | |||||
value: typedArray.buffer, | |||||
success: function (res) { | |||||
console.log('写入成功', res.errMsg) | |||||
}, | |||||
fail(res){ | |||||
console.log('写入失败', res.errMsg) | |||||
} | |||||
}) | |||||
}, | |||||
//获取输入框的数据 | |||||
getmsg(event){ | |||||
this.setData({ | |||||
sendmsg:event.detail.value | |||||
}) | |||||
}, | |||||
lanyatest12(event){ | |||||
var that = this; | |||||
wx.closeBLEConnection({ | |||||
deviceId: that.data.connectedDeviceId, | |||||
success: function (res) { | |||||
that.setData({ | |||||
connectedDeviceId: "", | |||||
}) | |||||
console.log('断开蓝牙设备成功:' + res.errMsg) | |||||
}, | |||||
fail:function(res){ | |||||
console.log('断开蓝牙设备失败:' + res.errMsg) | |||||
} | |||||
}) | |||||
}, | |||||
}) | |||||
function toPlatformString(systemInfo, str) | |||||
{ | |||||
if (systemInfo.platform == 'android') | |||||
return str.toLowerCase(); | |||||
else if (systemInfo.platform == 'ios') | |||||
return str.toUpperCase(); | |||||
else | |||||
return str; | |||||
} | |||||
/** | |||||
* 版本比较 | |||||
*/ | |||||
function versionCompare (ver1, ver2) { //版本比较 | |||||
// console.log("ver1" + ver1 + 'ver2' + ver2); | |||||
var version1pre = parseFloat(ver1) | |||||
var version2pre = parseFloat(ver2) | |||||
var version1next = parseInt(ver1.replace(version1pre + ".", "")) | |||||
var version2next = parseInt(ver2.replace(version2pre + ".", "")) | |||||
if (version1pre > version2pre) | |||||
return true | |||||
else if (version1pre < version2pre) | |||||
return false | |||||
else { | |||||
if (version1next > version2next) | |||||
return true | |||||
else | |||||
return false | |||||
} | |||||
} | |||||
/** | |||||
* 微信版本检测 | |||||
* Android从微信 6.5.7 开始支持,iOS从微信 6.5.6 开始支持 | |||||
*/ | |||||
function checkWechatVersion(systemInfo) { | |||||
if (systemInfo.platform == 'android' && versionCompare('6.5.7', systemInfo.version)) { | |||||
wx.showModal({ | |||||
title: '提示', | |||||
content: '当前微信版本过低,请更新至最新版本体验', | |||||
showCancel: false | |||||
}) | |||||
}else if (systemInfo.platform == 'ios' && versionCompare('6.5.6', systemInfo.version)) { | |||||
wx.showModal({ | |||||
title: '提示', | |||||
content: '当前微信版本过低,请更新至最新版本体验', | |||||
showCancel: false | |||||
}) | |||||
} | |||||
} | |||||
function Uint8ArrayToString(fileData){ | |||||
var dataString = ""; | |||||
for (var i = 0; i < fileData.length; i++) { | |||||
dataString += String.fromCharCode(fileData[i]); | |||||
} | |||||
return dataString | |||||
} | |||||
// 微信官方给的ArrayBuffer转十六进制示例 | |||||
function ab2hex(buffer) { | |||||
var hexArr = Array.prototype.map.call( | |||||
new Uint8Array(buffer), | |||||
function (bit) { | |||||
return ('00' + bit.toString(16)).slice(-2) | |||||
} | |||||
) | |||||
return hexArr.join(','); | |||||
} | |||||
//转成可展会的文字 | |||||
function hexCharCodeToStr(hexCharCodeStr) { | |||||
var trimedStr = hexCharCodeStr.trim(); | |||||
var rawStr = trimedStr.substr(0, 2).toLowerCase() === '0x' ? trimedStr.substr(2) : trimedStr; | |||||
var len = rawStr.length; | |||||
var curCharCode; | |||||
var resultStr = []; | |||||
for (var i = 0; i < len; i = i + 2) { | |||||
curCharCode = parseInt(rawStr.substr(i, 2), 16); | |||||
resultStr.push(String.fromCharCode(curCharCode)); | |||||
} | |||||
return resultStr.join(''); | |||||
} | |||||
//转换成需要的格式 | |||||
function buf2string(buffer) { | |||||
var arr = Array.prototype.map.call(new Uint8Array(buffer), x => x) | |||||
return arr.map((char, i) => { | |||||
return String.fromCharCode(char); | |||||
}).join(''); | |||||
} | |||||
function stringToUint8Array(str){ | |||||
let arr = []; | |||||
for (let i = 0, j = str.length; i < j; ++i) { | |||||
arr.push(str.charCodeAt(i)); | |||||
} | |||||
let tmpUint8Array = new Uint8Array(arr); | |||||
return tmpUint8Array | |||||
} | |||||
function decodeHexNibble(c) { | |||||
if (c >= 48 && c <= 57) { | |||||
return c - 48; | |||||
} else if (c >= 65 && c <= 70) { | |||||
return c - 65 + 10; | |||||
} else { | |||||
return c >= 97 && c <= 102 ? c - 97 + 10 : -1; | |||||
} | |||||
} | |||||
function decodeHexByte(s, pos) { | |||||
let hi = decodeHexNibble(s.charCodeAt(pos)); | |||||
let lo = decodeHexNibble(s.charCodeAt(pos + 1)); | |||||
return ((hi << 4) + lo); | |||||
} | |||||
function hexStringToBytesWithPadding(str, byteLen, padding) { | |||||
let len = str.length | |||||
let length = 2 * byteLen | |||||
if (length >= len && (length & 1) == 0) { | |||||
if (length == 0) { | |||||
return [0]; | |||||
} else { | |||||
//let buffer = new ArrayBuffer(length >>> 1); | |||||
//let bytes = new Uint8Array(buffer); | |||||
let bytes = new Uint8Array(length >>> 1); | |||||
for(let i = 0; i < len; i += 2) { | |||||
bytes[i >>> 1] = decodeHexByte(str, i); | |||||
} | |||||
for(let i = 0; i < byteLen-len/2; i++) | |||||
bytes[len/2+i] = padding; | |||||
return bytes; | |||||
} | |||||
} | |||||
else | |||||
return [0]; | |||||
} | |||||
function hexStringToBytes(str) { | |||||
let s = str; | |||||
if(s.length < 12) | |||||
{ | |||||
let tmp = 12-s.length | |||||
for(let i = 0; i< tmp; i++) | |||||
s = "0" + s; | |||||
} | |||||
else | |||||
s = str.substr(s.length-12, s.length); | |||||
let start = 0 | |||||
let length = s.length | |||||
if (length >= 0 && (length & 1) == 0) { | |||||
if (length == 0) { | |||||
return new byte[0]; | |||||
} else { | |||||
let bytes = new Uint8Array(length >>> 1); | |||||
for(let i = 0; i < length; i += 2) { | |||||
bytes[i >>> 1] = decodeHexByte(s, start + i); | |||||
} | |||||
return bytes; | |||||
} | |||||
} | |||||
else | |||||
return [0]; | |||||
} | |||||
function packData(userTelephone, userPassword, pwd, openLockType) | |||||
{ | |||||
let cmd = 0x41 | |||||
let ut = stringToUint8Array(userTelephone) | |||||
let up = stringToUint8Array(userPassword) | |||||
let p = hexStringToBytesWithPadding(pwd, 10, 0xff) | |||||
let length = 1+11+6+10+1 | |||||
let b = new Uint8Array(length) | |||||
b[0] = cmd | |||||
b.set(ut, 1) | |||||
b.set(up, 12) | |||||
b.set(p, 18) | |||||
b[28] = openLockType | |||||
console.log(b) | |||||
return packMsg(0x41, b, length) | |||||
} | |||||
function packMsg(cmd, data, payloadLength) | |||||
{ | |||||
let length = 13 + payloadLength | |||||
//let buffer = new ArrayBuffer(length); | |||||
let b = new Uint8Array(length); | |||||
b[0] = 0x89; | |||||
b[1] = 0x89; | |||||
b[2] = cmd; | |||||
let timestamp = new Date().getTime(); | |||||
let ts = timestamp.toString(16) | |||||
let t = hexStringToBytes(ts) | |||||
b.set(t, 4) | |||||
b[3] = b[9]; | |||||
b[10] = (payloadLength>>8)&0xff; | |||||
b[11] = payloadLength & 0xff; | |||||
let key = b[3]; | |||||
for (let i=0; i<payloadLength; i++) { | |||||
data[i] -= (payloadLength - i) ^ key; | |||||
data[i] = (data[i] ^ (key ^ i)); | |||||
} | |||||
b.set(data, 12) | |||||
let xor = b[0]; | |||||
for (let i=1; i<length-1; i++) | |||||
xor ^= b[i]; | |||||
b[length-1] = xor; | |||||
return b; | |||||
} | |||||
@ -0,0 +1,3 @@ | |||||
{ | |||||
"usingComponents": {} | |||||
} |
@ -0,0 +1,29 @@ | |||||
<!--pages/lanyatest/lanyatest.wxml--> | |||||
<view class="contentview"> | |||||
<view class='myview' > | |||||
{{info}} | |||||
</view> | |||||
<button type="primary" class="button" bindtap="lanyatest1">1初始化蓝牙</button> | |||||
<button type="primary" class="button" bindtap="lanyatest2">2获取蓝牙状态</button> | |||||
<button type="primary" class="button" bindtap="lanyatest3">3搜索周边设备</button> | |||||
<button type="primary" class="button" bindtap="lanyatest4">4获取所有设备</button> | |||||
<block wx:for="{{devices}}" wx:key="{{test}}"> | |||||
<button type="primary" class="button" id="{{item.deviceId}}" style='background-color:red' bindtap="lanyaconnect">5连接{{item.name}} </button> | |||||
</block> | |||||
<button type="primary" class="button" bindtap="lanyatest6">6停止搜索周边蓝牙设备</button> | |||||
<button type="primary" class="button" bindtap="lanyatest7">7获取所有service</button> | |||||
<button type="primary" class="button" bindtap="lanyatest8">8获取所有特征值</button> | |||||
<button type="primary" class="button" bindtap="lanyatest9">9启用特征值变化notify</button> | |||||
<button type="primary" class="button" bindtap="lanyatest10">10接收蓝牙返回消息</button> | |||||
<view class="section"> | |||||
<input placeholder='请输入要发送的信息' bindinput='getmsg'/> | |||||
</view> | |||||
<button type="primary" class="button" bindtap="lanyatest11">11微信发送消息</button> | |||||
<button type="primary" class="button" bindtap="lanyatest12">12断开蓝牙设备</button> | |||||
</view> |
@ -0,0 +1,28 @@ | |||||
/* pages/lanyatest/lanyatest.wxss */ | |||||
.vertical{ | |||||
display: flex; | |||||
flex-direction: column; | |||||
} | |||||
/**index.wxss**/ | |||||
.horizontal{ | |||||
display: flex; | |||||
flex-direction: row; | |||||
} | |||||
.btinfo{ | |||||
height:100px; | |||||
} | |||||
.contentview { | |||||
margin: 0 10px; | |||||
} | |||||
.button { | |||||
margin: 5px; | |||||
} | |||||
.myview{ | |||||
height:200px; | |||||
word-break:break-all;/* 自动换行 */ | |||||
} |
@ -0,0 +1,18 @@ | |||||
// logs.js | |||||
const util = require('../../utils/util.js') | |||||
Page({ | |||||
data: { | |||||
logs: [] | |||||
}, | |||||
onLoad() { | |||||
this.setData({ | |||||
logs: (wx.getStorageSync('logs') || []).map(log => { | |||||
return { | |||||
date: util.formatTime(new Date(log)), | |||||
timeStamp: log | |||||
} | |||||
}) | |||||
}) | |||||
} | |||||
}) |
@ -0,0 +1,4 @@ | |||||
{ | |||||
"navigationBarTitleText": "查看启动日志", | |||||
"usingComponents": {} | |||||
} |
@ -0,0 +1,6 @@ | |||||
<!--logs.wxml--> | |||||
<view class="container log-list"> | |||||
<block wx:for="{{logs}}" wx:key="timeStamp" wx:for-item="log"> | |||||
<text class="log-item">{{index + 1}}. {{log.date}}</text> | |||||
</block> | |||||
</view> |
@ -0,0 +1,8 @@ | |||||
.log-list { | |||||
display: flex; | |||||
flex-direction: column; | |||||
padding: 40rpx; | |||||
} | |||||
.log-item { | |||||
margin: 10rpx; | |||||
} |
@ -0,0 +1,74 @@ | |||||
{ | |||||
"description": "项目配置文件", | |||||
"packOptions": { | |||||
"ignore": [] | |||||
}, | |||||
"setting": { | |||||
"urlCheck": true, | |||||
"es6": true, | |||||
"enhance": true, | |||||
"postcss": true, | |||||
"preloadBackgroundData": false, | |||||
"minified": true, | |||||
"newFeature": false, | |||||
"coverView": true, | |||||
"nodeModules": false, | |||||
"autoAudits": false, | |||||
"showShadowRootInWxmlPanel": true, | |||||
"scopeDataCheck": false, | |||||
"uglifyFileName": false, | |||||
"checkInvalidKey": true, | |||||
"checkSiteMap": true, | |||||
"uploadWithSourceMap": true, | |||||
"compileHotReLoad": false, | |||||
"lazyloadPlaceholderEnable": false, | |||||
"useMultiFrameRuntime": true, | |||||
"useApiHook": true, | |||||
"useApiHostProcess": true, | |||||
"babelSetting": { | |||||
"ignore": [], | |||||
"disablePlugins": [], | |||||
"outputPath": "" | |||||
}, | |||||
"enableEngineNative": false, | |||||
"useIsolateContext": true, | |||||
"userConfirmedBundleSwitch": false, | |||||
"packNpmManually": false, | |||||
"packNpmRelationList": [], | |||||
"minifyWXSS": true, | |||||
"showES6CompileOption": false | |||||
}, | |||||
"compileType": "miniprogram", | |||||
"libVersion": "2.19.4", | |||||
"appid": "wx7775ba175d855273", | |||||
"projectname": "%E8%93%9D%E7%89%99%E6%B5%8B%E8%AF%95", | |||||
"debugOptions": { | |||||
"hidedInDevtools": [] | |||||
}, | |||||
"scripts": {}, | |||||
"staticServerOptions": { | |||||
"baseURL": "", | |||||
"servePath": "" | |||||
}, | |||||
"isGameTourist": false, | |||||
"condition": { | |||||
"search": { | |||||
"list": [] | |||||
}, | |||||
"conversation": { | |||||
"list": [] | |||||
}, | |||||
"game": { | |||||
"list": [] | |||||
}, | |||||
"plugin": { | |||||
"list": [] | |||||
}, | |||||
"gamePlugin": { | |||||
"list": [] | |||||
}, | |||||
"miniprogram": { | |||||
"list": [] | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,7 @@ | |||||
{ | |||||
"desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html", | |||||
"rules": [{ | |||||
"action": "allow", | |||||
"page": "*" | |||||
}] | |||||
} |
@ -0,0 +1,59 @@ | |||||
import BLEHandler from "./bleHandler" | |||||
class BLE extends BLEHandler { | |||||
constructor(blename, emitter) { | |||||
super(blename, emitter) | |||||
} | |||||
listen(callback) { | |||||
// 蓝牙事件注册,打开channel | |||||
this.emitter.removeAllListeners("channel") | |||||
this.emitter.on("channel", callback) | |||||
} | |||||
removeListen() { | |||||
// 移除所有蓝牙事件 | |||||
this.emitter.removeAllListeners("channel") | |||||
} | |||||
async init() { | |||||
let flow = false | |||||
// 打开蓝牙适配器状态监听 | |||||
this.onBLEConnectionStateChange() | |||||
// 蓝牙适配器初始化 | |||||
await this.openAdapter() | |||||
// 搜索蓝牙设备 | |||||
await this.startSearch() | |||||
// 获取设备ID | |||||
flow = await this.onBluetoothFound() | |||||
if (!flow) return | |||||
// 停止搜索设备 | |||||
await this.stopSearchBluetooth() | |||||
// 连接蓝牙 | |||||
await this.connectBlue(); | |||||
//安卓手机需要设置MTU Size | |||||
await this.setBLEMTU(); | |||||
// 获取serviceId | |||||
await this.getBLEServices() | |||||
// 设置特征值 | |||||
await this.getCharacteristics(); | |||||
// 订阅特征值 | |||||
await this.notifyBLECharacteristicValueChange() | |||||
// 打开传输监听,等待设备反馈数据 | |||||
this.onBLECharacteristicValueChange() | |||||
} | |||||
// 发送指令 | |||||
async send(cmd, payload) { | |||||
let flow = await this.sentOrder(cmd, payload) | |||||
return flow | |||||
} | |||||
async close() { | |||||
await this.closeBLEConnection() | |||||
await this.closeBLEAdapter() | |||||
} | |||||
} | |||||
export { BLE }; |
@ -0,0 +1,296 @@ | |||||
import * as t from "./tools" | |||||
/* | |||||
import { HTTP } from "../server"; | |||||
*/ | |||||
/** | |||||
* 蓝牙工具类 | |||||
* 封装小程序蓝牙流程方法 | |||||
* 处理事件通信 | |||||
*/ | |||||
class BLEHandler { | |||||
constructor(blename, emitter) { | |||||
this.blename = blename //厂家自定义的蓝牙设备名称 | |||||
this.emitter = emitter | |||||
this.readCharacteristicId = ""; //能从硬件返回的信息中自动提取 | |||||
this.writeCharacteristicId = "00002af1-0000-1000-8000-00805f9b34fb"; //能从硬件返回的信息中自动提取 | |||||
this.notifyCharacteristicId = "00002af0-0000-1000-8000-00805f9b34fb"; //能从硬件返回的信息中自动提取 | |||||
this.deviceId = ""; //蓝牙Mac地址 | |||||
this.serviceId = "000018f0-0000-1000-8000-00805f9b34fb";//具体的serviceId要自己根据硬件提供设置。 | |||||
this.receivePacket = []; | |||||
this.recPktLength = 0; | |||||
this.recPktOffset = 0; | |||||
} | |||||
async openAdapter() { | |||||
let [err, res] = await t._openAdapter.call(this); | |||||
if (err != null) { | |||||
this.emitter.emit("channel", { | |||||
type: "connect", | |||||
data: "未打开适配器" | |||||
}) | |||||
return false; | |||||
} | |||||
return true | |||||
} | |||||
async startSearch() { | |||||
let [err, res] = await t._startSearch.call(this); | |||||
if (err != null) { | |||||
return; | |||||
} | |||||
this.emitter.emit("channel", { | |||||
type: "connect", | |||||
data: "正在连接中..." | |||||
}) | |||||
} | |||||
async onBluetoothFound() { | |||||
let [err, res] = await t._onBluetoothFound.call(this); | |||||
if (err != null) { | |||||
this.emitter.emit("channel", { | |||||
type: "connect", | |||||
data: "未找到设备" | |||||
}) | |||||
return false; | |||||
} | |||||
return true | |||||
} | |||||
async getBluetoothDevices() { | |||||
let [err, res] = await t._getBluetoothDevices.call(this); | |||||
if (err != null) { | |||||
this.emitter.emit("channel", { | |||||
type: "connect", | |||||
data: "未找到设备" | |||||
}) | |||||
return false; | |||||
} | |||||
return true | |||||
} | |||||
async stopSearchBluetooth() { | |||||
let [err, res] = await t._stopSearchBluetooth.call(this); | |||||
if (err != null) { | |||||
return; | |||||
} | |||||
} | |||||
async connectBlue() { | |||||
let [err, res] = await t._connectBlue.call(this); | |||||
if (err != null) { | |||||
return; | |||||
} | |||||
} | |||||
async setBLEMTU() { | |||||
let [err, res] = await t._setBLEMTU.call(this); | |||||
if (err != null) { | |||||
return; | |||||
} | |||||
} | |||||
async getBLEServices() { | |||||
let [err, res] = await t._getBLEServices.call(this); | |||||
if (err != null) { | |||||
return; | |||||
} | |||||
} | |||||
async getCharacteristics() { | |||||
let [err, res] = await t._getCharacteristics.call(this); | |||||
if (err != null) { | |||||
this.emitter.emit("channel", { | |||||
type: "connect", | |||||
data: "无法订阅特征值" | |||||
}) | |||||
// 取消连接 | |||||
this.closeBLEConnection() | |||||
this.closeBLEAdapter() | |||||
wx.setStorageSync("bluestatus", ""); | |||||
return false; | |||||
} | |||||
this.emitter.emit("channel", { | |||||
type: "connect", | |||||
data: "蓝牙已连接" | |||||
}) | |||||
wx.setStorageSync("bluestatus", "on"); | |||||
return true | |||||
} | |||||
async notifyBLECharacteristicValueChange() { | |||||
let [err, res] = await t._notifyBLECharacteristicValueChange.call(this); | |||||
if (err != null) { | |||||
return; | |||||
} | |||||
} | |||||
async closeBLEConnection() { | |||||
let [err, res] = await t._closeBLEConnection.call(this); | |||||
if (err != null) { | |||||
return; | |||||
} | |||||
} | |||||
async closeBLEAdapter() { | |||||
let [err, res] = await t._closeBLEAdapter.call(this); | |||||
if (err != null) { | |||||
return; | |||||
} | |||||
} | |||||
async sentOrder(cmd, payload) { | |||||
let data = t._sentOrder(cmd, payload) | |||||
console.log("-- 发送数据:", data) | |||||
let arrayBuffer = new Uint8Array(data).buffer; | |||||
let [err, res] = await t._writeBLECharacteristicValue.call(this, arrayBuffer) | |||||
if (err != null) { | |||||
return false | |||||
} | |||||
console.log("数据发送成功!") | |||||
return true | |||||
} | |||||
// 打开蓝牙适配器状态监听 | |||||
onBLEConnectionStateChange() { | |||||
wx.onBLEConnectionStateChange(res => { | |||||
// 该方法回调中可以用于处理连接意外断开等异常情况 | |||||
if (!res.connected) { | |||||
this.closeBLEAdapter() | |||||
wx.setStorageSync("bluestatus", ""); | |||||
this.emitter.emit("channel", { | |||||
type: "connect", | |||||
data: "蓝牙已断开" | |||||
}) | |||||
} | |||||
}, err => { | |||||
console.log('err', err) | |||||
}) | |||||
} | |||||
// 收到设备推送的notification | |||||
onBLECharacteristicValueChange() { | |||||
wx.onBLECharacteristicValueChange(res => { | |||||
//let arrbf = new Uint8Array(res.value) | |||||
//console.log(`收到硬件数据反馈!命令码为:${arrbf[2]}`) | |||||
//if (this._checkData(arrbf)) { | |||||
//} | |||||
let arrbf = new Uint8Array(res.value) | |||||
if (arrbf[0] == 0x89 && arrbf[1] == 0x89) | |||||
{ | |||||
let dataLength = ((arrbf[10] << 8) & 0xff00) + (arrbf[11] & 0x00ff) | |||||
this.recPktLength = 13 + dataLength | |||||
this.receivePacket = new Uint8Array(this.recPktLength) | |||||
this.recPktOffset = 0 | |||||
console.log("开始接收数据:length= " + arrbf.length + " data= " + arrbf) | |||||
this.receivePacket.set(arrbf, this.recPktOffset) | |||||
this.recPktOffset += arrbf.length; | |||||
if( this.recPktOffset == this.recPktLength){ | |||||
this.getReceivePacket(this.receivePacket) | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
console.log("继续接收数据:length= " + arrbf.length + " data= " + arrbf) | |||||
this.receivePacket.set(arrbf, this.recPktOffset) | |||||
this.recPktOffset += arrbf.length; | |||||
if( this.recPktOffset == this.recPktLength){ | |||||
this.getReceivePacket(this.receivePacket) | |||||
} | |||||
} | |||||
}) | |||||
} | |||||
/* | |||||
_uploadInfo(message) { | |||||
console.log("-- 准备数据同步!", this._mapToArray(message)) | |||||
let bleorder = wx.getStorageSync("bleorder"); | |||||
let blecabinet = wx.getStorageSync("blecabinet") | |||||
HTTP({ | |||||
url: "cabinet/uploadBlueData", | |||||
methods: "post", | |||||
data: { | |||||
cabinetQrCode: blecabinet, | |||||
order: bleorder, | |||||
message: this._mapToArray(message) | |||||
} | |||||
}).then(res => { | |||||
console.log("✔ 数据同步成功!") | |||||
}, err => { | |||||
console.log('✘ 数据同步失败', err) | |||||
}) | |||||
} | |||||
*/ | |||||
_mapToArray(arrbf) { | |||||
let arr = [] | |||||
arrbf.map(item => { | |||||
arr.push(item) | |||||
}) | |||||
return arr | |||||
} | |||||
// 校验数据正确性 | |||||
_checkData(arrbf) { | |||||
let packetLen = arrbf.length; | |||||
console.log("接收数据:" + arrbf) | |||||
// 校验帧头帧尾 | |||||
if (arrbf[0] != 0x89 || arrbf[1] != 0x89) { | |||||
console.log('不是该设备返回的包') | |||||
return false | |||||
} | |||||
if (packetLen < 14) { | |||||
console.log("包长太短,不是该设备返回的包"); | |||||
return false; | |||||
} | |||||
let dataLength = ((arrbf[10] << 8) & 0xff00) + (arrbf[11] & 0x00ff); | |||||
if (dataLength != (packetLen - 13)) { | |||||
let calLen = packetLen - 13; | |||||
console.log("✘ 数据长度错误: " + dataLength + " is not " + calLen); | |||||
return false; | |||||
} | |||||
//校验包 | |||||
let check = arrbf[0]; | |||||
for (let i = 1; i < packetLen - 1; i++) | |||||
check ^= arrbf[i]; | |||||
if (check != arrbf[packetLen - 1]) { | |||||
console.log("crc校验错误,请重发." + check); | |||||
return false; | |||||
} | |||||
console.log('✔ 数据校验成功,接收完整!') | |||||
return true | |||||
} | |||||
getReceivePacket(arrbf) | |||||
{ | |||||
let packetLen = arrbf.length; | |||||
console.log("接收数据:" + arrbf) | |||||
// 校验帧头帧尾 | |||||
if (arrbf[0] != 0x89 || arrbf[1] != 0x89) { | |||||
console.log('不是该设备返回的包') | |||||
return false | |||||
} | |||||
if (packetLen < 14) { | |||||
console.log("包长太短,不是该设备返回的包"); | |||||
return false; | |||||
} | |||||
let dataLength = ((arrbf[10] << 8) & 0xff00) + (arrbf[11] & 0x00ff); | |||||
if (dataLength != (packetLen - 13)) { | |||||
let calLen = packetLen - 13; | |||||
console.log("✘ 数据长度错误: " + dataLength + " is not " + calLen); | |||||
return false; | |||||
} | |||||
//校验包 | |||||
let check = arrbf[0]; | |||||
for (let i = 1; i < packetLen - 1; i++) | |||||
check ^= arrbf[i]; | |||||
if (check != arrbf[packetLen - 1]) { | |||||
console.log("crc校验错误,请重发." + check); | |||||
return false; | |||||
} | |||||
console.log('✔ 数据校验成功,接收完整! packet= ' + arrbf) | |||||
return true | |||||
} | |||||
} | |||||
export default BLEHandler |
@ -0,0 +1,44 @@ | |||||
export default function (err) { | |||||
if (err && err.errCode) { | |||||
// 微信BLE蓝牙错误码 | |||||
switch (err.errCode) { | |||||
case 10001: | |||||
return err.errCode + ":蓝牙适配失败,请检查手机蓝牙和定位功能是否打开" | |||||
case 10002: | |||||
return err.errCode + ":没有找到指定设备" | |||||
case 10003: | |||||
return err.errCode + ":连接失败" | |||||
case 10004: | |||||
return err.errCode + ":没有找到指定服务" | |||||
case 10005: | |||||
return err.errCode + ":没有找到指定特征值" | |||||
case 10006: | |||||
return err.errCode + ":当前连接已断开" | |||||
case 10007: | |||||
return err.errCode + ":当前特征值不支持此操作" | |||||
case 10008: | |||||
return err.errCode + ":其余所有系统上报的异常" | |||||
case 10009: | |||||
return err.errCode + ":Android 系统特有,系统版本低于 4.3 不支持 BLE" | |||||
case 10012: | |||||
return err.errCode + ":连接超时" | |||||
case 10013: | |||||
return err.errCode + ":连接 deviceId 为空或者是格式不正确" | |||||
default: | |||||
return "蓝牙功能暂不支持" | |||||
} | |||||
} else { | |||||
// 自定义错误码 | |||||
if (typeof err === 'string') { | |||||
switch (err) { | |||||
case 'device not found': | |||||
return "找不到该设备" | |||||
default: | |||||
break; | |||||
} | |||||
} else { | |||||
return "蓝牙功能暂不支持" | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,481 @@ | |||||
import errToString from "./error"; | |||||
var util = require('../util'); | |||||
let PRINT_SHOW = true //是否开启蓝牙调试 | |||||
let SYSTEM_INFO = {} | |||||
let MTU_SIZE = 512 | |||||
function toPlatformString(systemInfo, str) | |||||
{ | |||||
if (systemInfo.platform == 'android') | |||||
return str.toLowerCase(); | |||||
else if (systemInfo.platform == 'ios') | |||||
return str.toUpperCase(); | |||||
else | |||||
return str; | |||||
} | |||||
function _openAdapter() { | |||||
print(`准备初始化蓝牙适配器...`); | |||||
wx.getSystemInfo({ | |||||
success: function (res) { | |||||
print(`model: ${res.model}`); | |||||
print(`pixelRatio: ${res.pixelRatio}`); | |||||
print(`windowWidth: ${res.windowWidth}`); | |||||
print(`windowHeight: ${res.windowHeight}`); | |||||
print(`language: ${res.language}`); | |||||
print(`version: ${res.version}`); | |||||
print(`platform: ${res.platform}`); | |||||
print(`environment: ${res.environment}`); | |||||
SYSTEM_INFO = res; | |||||
} | |||||
}) | |||||
return wx.openBluetoothAdapter().then( | |||||
(res) => { | |||||
print(`✔ 适配器初始化成功!`); | |||||
return [null, res] | |||||
}, | |||||
(err) => { | |||||
print(`✘ 初始化失败!${errToString(err)}`); | |||||
return [errToString(err), null] | |||||
} | |||||
); | |||||
} | |||||
/** | |||||
* @param {Array<string>} services | |||||
* @param { Int } interval | |||||
*/ | |||||
function _startSearch() { | |||||
print(`准备搜寻附近的蓝牙外围设备...`); | |||||
return promisify(wx.startBluetoothDevicesDiscovery, { | |||||
services: [this.serviceId], //如果填写了此UUID,那么只会搜索出含有这个UUID的设备 | |||||
allowDuplicatesKey: false, | |||||
interval: 1000 | |||||
}).then( | |||||
(res) => { | |||||
print(`✔ 搜索成功!`); | |||||
return [null, res] | |||||
}, | |||||
(err) => { | |||||
print(`✘ 搜索蓝牙设备失败!${errToString(err)}`); | |||||
return [errToString(err), null] | |||||
} | |||||
); | |||||
} | |||||
/** | |||||
*@param {Array<string>} devices | |||||
*@deviceId 设备ID | |||||
*/ | |||||
function _onBluetoothFound() { | |||||
print(`监听搜寻新设备事件...`); | |||||
return _onBluetoothFound_promise.call(this).then(res => { | |||||
print(`✔ 设备 ${this.blename} 查找成功!`); | |||||
return [null, res] | |||||
}, err => { | |||||
print(`✘ 设备 ${this.blename} 查找失败!`); | |||||
return [errToString(err), null] | |||||
}) | |||||
} | |||||
/** | |||||
* @param {Array} devices 查找到设备数组 | |||||
* @param {int} count 计数器-嗅探2次 | |||||
*/ | |||||
function _onBluetoothFound_promise() { | |||||
let devices = [] | |||||
let count = 0 | |||||
return new Promise((resolve, reject) => { | |||||
wx.onBluetoothDeviceFound(res => { | |||||
devices.push(...res.devices) | |||||
print(`已嗅探设备数:${devices.length}...`) | |||||
print(`已嗅探设备信息:${JSON.stringify(devices)}`) | |||||
count++ | |||||
print(`已嗅探次数:${count}`) | |||||
//if (count > 1) | |||||
if(devices.length>0) | |||||
{ | |||||
devices.forEach(element => { | |||||
if ((element.name && element.name == this.blename) || (element.localName && element.localName == this.blename)) { | |||||
this.deviceId = element.deviceId | |||||
print(`我的设备Mac:${this.deviceId} `) | |||||
print(`我的设备名:${element.name}, ${element.localName}`) | |||||
resolve(res) | |||||
} | |||||
}); | |||||
} | |||||
reject('device not found') | |||||
}, err => { | |||||
reject(err) | |||||
}) | |||||
}) | |||||
} | |||||
/** | |||||
*@param {Array<string>} devices | |||||
*@deviceId 设备ID | |||||
*/ | |||||
function _getBluetoothDevices() { | |||||
print(`监听搜寻新设备事件...`); | |||||
let devices = [] | |||||
return wx.getBluetoothDevices().then( | |||||
(res) => { | |||||
devices.push(res.devices) | |||||
print(`已嗅探设备数:${res.devices.length}...`) | |||||
print(`已嗅探设备信息:${JSON.stringify(res.devices)}`) | |||||
if(devices.length>0) | |||||
{ | |||||
devices.forEach(element => { | |||||
if ((element.name && element.name == this.blename) || (element.localName && element.localName == this.blename)) { | |||||
this.deviceId = element.deviceId | |||||
print(`我的设备Mac:${this.deviceId} `) | |||||
print(`我的设备名:${element.name}, ${element.localName}`) | |||||
print(`✔ 设备 ${this.blename} 查找成功!`); | |||||
return [null, res] | |||||
} | |||||
}); | |||||
} | |||||
return [ "暂时没有嗅探到设备 ${this.blename}, 继续嗅探...", null] | |||||
}, | |||||
(err) => { | |||||
print(`✘ 设备 ${this.blename} 查找失败!`); | |||||
return [errToString(err), null] | |||||
} | |||||
); | |||||
} | |||||
function _getBluetoothDevices_1() { | |||||
print(`监听搜寻新设备事件...`); | |||||
return _getBluetoothDevices_promise.call(this).then(res => { | |||||
print(`✔ 设备 ${this.blename} 查找成功!`); | |||||
return [null, res] | |||||
}, err => { | |||||
print(`✘ 设备 ${this.blename} 查找失败!`); | |||||
return [errToString(err), null] | |||||
}) | |||||
} | |||||
/** | |||||
* @param {Array} devices 查找到设备数组 | |||||
* @param {int} count 计数器-嗅探2次 | |||||
*/ | |||||
function _getBluetoothDevices_promise() { | |||||
let devices = [] | |||||
print(`1111`) | |||||
return new Promise((resolve, reject) => { | |||||
print(`2222`) | |||||
wx.getBluetoothDevices(res => { | |||||
print(`3333`) | |||||
devices.push(...res.devices) | |||||
print(`已嗅探设备数:${devices.length}...`) | |||||
print(`已嗅探设备信息:${JSON.stringify(devices)}`) | |||||
if(devices.length>0) | |||||
{ | |||||
devices.forEach(element => { | |||||
if ((element.name && element.name == this.blename) || (element.localName && element.localName == this.blename)) { | |||||
this.deviceId = element.deviceId | |||||
print(`我的设备Mac:${this.deviceId} `) | |||||
print(`我的设备名:${element.name}, ${element.localName}`) | |||||
resolve(res) | |||||
} | |||||
}); | |||||
} | |||||
reject('device not found') | |||||
}, err => { | |||||
print(`4444`) | |||||
reject(err) | |||||
}) | |||||
}) | |||||
} | |||||
function _stopSearchBluetooth() { | |||||
print(`停止查找新设备...`); | |||||
return wx.stopBluetoothDevicesDiscovery().then( | |||||
(res) => { | |||||
print(`✔ 停止查找设备成功!`); | |||||
return [null, res] | |||||
}, | |||||
(err) => { | |||||
print(`✘ 停止查询设备失败!${errToString(err)}`); | |||||
return [errToString(err), null] | |||||
} | |||||
); | |||||
} | |||||
function _connectBlue() { | |||||
print(`准备连接设备...`); | |||||
return promisify(wx.createBLEConnection, { | |||||
deviceId: this.deviceId, | |||||
}).then( | |||||
(res) => { | |||||
print(`✔ 连接蓝牙成功!`); | |||||
return [null, res] | |||||
}, | |||||
(err) => { | |||||
print(`✘ 连接蓝牙失败!${errToString(err)}`); | |||||
return [errToString(err), null] | |||||
} | |||||
); | |||||
} | |||||
function _setBLEMTU() { | |||||
if (SYSTEM_INFO.platform != 'android') | |||||
{ | |||||
print(`仅安卓手机需要设置MTU Size`); | |||||
return ["仅安卓手机需要设置MTU Size", null]; | |||||
} | |||||
print(`准备设置 MTU Size...`); | |||||
return promisify(wx.setBLEMTU, { | |||||
deviceId: this.deviceId, | |||||
mtu:MTU_SIZE | |||||
}).then( | |||||
(res) => { | |||||
//console.log("setBLEMTU success >> " + JSON.stringify(res)) | |||||
print(`✔ 设置MTU Size = ${MTU_SIZE} 成功!`); | |||||
return [null, res] | |||||
}, | |||||
(err) => { | |||||
//console.log("setBLEMTU fail >> " + JSON.stringify(res)) | |||||
print(`✘ 设置MTU Size 失败!`); | |||||
return [errToString(err), null] | |||||
} | |||||
); | |||||
} | |||||
function _closeBLEConnection() { | |||||
print(`断开蓝牙连接...`) | |||||
return promisify(wx.closeBLEConnection, { | |||||
deviceId: this.deviceId, | |||||
}).then( | |||||
(res) => { | |||||
print(`✔ 断开蓝牙成功!`); | |||||
return [null, res] | |||||
}, | |||||
(err) => { | |||||
print(`✘ 断开蓝牙连接失败!${errToString(err)}`); | |||||
return [errToString(err), null] | |||||
} | |||||
); | |||||
} | |||||
function _closeBLEAdapter() { | |||||
print(`释放蓝牙适配器...`) | |||||
return wx.closeBluetoothAdapter().then(res => { | |||||
print(`✔ 释放适配器成功!`) | |||||
return [null, res] | |||||
}, err => { | |||||
print(`✘ 释放适配器失败!${errToString(err)}`) | |||||
return [errToString(err), null] | |||||
}) | |||||
} | |||||
function _getBLEServices() { | |||||
print(`获取蓝牙设备所有服务...`) | |||||
return promisify(wx.getBLEDeviceServices, { | |||||
deviceId: this.deviceId | |||||
}).then(res => { | |||||
print(`✔ 获取service成功!`) | |||||
console.log('services UUID:\n', JSON.stringify(res.services)); | |||||
for (var i = 0; i < res.services.length; i++) { | |||||
console.log("第"+(i+1) + "个UUID:" + res.services[i].uuid+"\n") | |||||
} | |||||
return [null, res] | |||||
}, err => { | |||||
print(`✘ 获取service失败!${errToString(err)}`) | |||||
return [errToString(err), null] | |||||
}) | |||||
} | |||||
function _getCharacteristics() { | |||||
print(`开始获取特征值...`); | |||||
return promisify(wx.getBLEDeviceCharacteristics, { | |||||
deviceId: this.deviceId, | |||||
serviceId: toPlatformString(SYSTEM_INFO, this.serviceId),//具有写、通知属性的服务uuid | |||||
}).then( | |||||
(res) => { | |||||
print(`✔ 获取特征值成功!`); | |||||
for (let i = 0; i < res.characteristics.length; i++) { | |||||
let item = res.characteristics[i]; | |||||
if (item.properties.read) { | |||||
this.readCharacteristicId = item.uuid; | |||||
print(`readCharacteristicId:${item.uuid}`) | |||||
} | |||||
if (item.properties.write && !item.properties.read) { | |||||
this.writeCharacteristicId = item.uuid; | |||||
print(`writeCharacteristicId:${item.uuid}`) | |||||
} | |||||
if (item.properties.notify || item.properties.indicate) { | |||||
this.notifyCharacteristicId = item.uuid; | |||||
print(`notifyCharacteristicId:${item.uuid}`) | |||||
} | |||||
} | |||||
return [null, res] | |||||
}, | |||||
(err) => { | |||||
print(`✘ 获取特征值失败!${errToString(err)}`); | |||||
return [errToString(err), null] | |||||
} | |||||
); | |||||
} | |||||
// 订阅特征值 | |||||
function _notifyBLECharacteristicValueChange() { | |||||
return promisify(wx.notifyBLECharacteristicValueChange, { | |||||
deviceId: this.deviceId, | |||||
serviceId: toPlatformString(SYSTEM_INFO, this.serviceId), | |||||
characteristicId: toPlatformString(SYSTEM_INFO, this.notifyCharacteristicId), | |||||
state: true | |||||
}).then(res => { | |||||
print(`✔ 订阅notify成功!`) | |||||
return [null, res] | |||||
}, err => { | |||||
print(`✘ 订阅notify失败!${errToString(err)}`) | |||||
return [errToString(err), null] | |||||
}) | |||||
} | |||||
/** | |||||
* 指令封装 | |||||
* @param {Array} data | |||||
*/ | |||||
function _sentOrder(cmd, payload){ | |||||
print(`开始封装指令...`) | |||||
let data = payload | |||||
let payloadLength = data.length; | |||||
let length = 13 + payload.length | |||||
let b = new Uint8Array(length); | |||||
b[0] = 0x89; | |||||
b[1] = 0x89; | |||||
b[2] = cmd; | |||||
let timestamp = new Date().getTime(); | |||||
let ts = timestamp.toString(16) | |||||
let t = util.hexStringToBytes(ts) | |||||
b.set(t, 4) | |||||
b[3] = b[9]; | |||||
b[10] = (payloadLength>>8)&0xff; | |||||
b[11] = payloadLength & 0xff; | |||||
let key = b[3]; | |||||
for (let i=0; i<payloadLength; i++) { | |||||
data[i] -= (payloadLength - i) ^ key; | |||||
data[i] = (data[i] ^ (key ^ i)); | |||||
} | |||||
b.set(data, 12) | |||||
let xor = b[0]; | |||||
for (let i=1; i<length-1; i++) | |||||
xor ^= b[i]; | |||||
b[length-1] = xor; | |||||
print(`✔ 封装成功! ${b}`) | |||||
return b; | |||||
} | |||||
function _writeBLECharacteristicValue(data) { | |||||
return promisify(wx.writeBLECharacteristicValue, { | |||||
deviceId: this.deviceId, | |||||
serviceId: toPlatformString(SYSTEM_INFO, this.serviceId), | |||||
characteristicId: toPlatformString(SYSTEM_INFO, this.writeCharacteristicId), | |||||
value: data, | |||||
}).then(res => { | |||||
print(`✔ 写入数据成功!`) | |||||
return [null, res] | |||||
}, err => { | |||||
print(`✘ 写入数据失败!${errToString(err)}`) | |||||
return [errToString(err), null] | |||||
}) | |||||
} | |||||
/** | |||||
* 对微信接口的promise封装 | |||||
* @param {function} fn | |||||
* @param {object} args | |||||
*/ | |||||
function promisify(fn, args) { | |||||
return new Promise((resolve, reject) => { | |||||
fn({ | |||||
...(args || {}), | |||||
success: (res) => resolve(res), | |||||
fail: (err) => reject(err), | |||||
}); | |||||
}); | |||||
} | |||||
/** | |||||
* 对微信接口回调函数的封装 | |||||
* @param {function} fn | |||||
*/ | |||||
function promisify_callback(fn) { | |||||
return new Promise((resolve, reject) => { | |||||
fn( | |||||
(res) => { | |||||
resolve(res); | |||||
}, | |||||
(rej) => { | |||||
reject(rej); | |||||
} | |||||
); | |||||
}); | |||||
} | |||||
function print(str) { | |||||
PRINT_SHOW ? console.log(str) : null; | |||||
} | |||||
export { | |||||
print, | |||||
_getCharacteristics, | |||||
_connectBlue, | |||||
_setBLEMTU, | |||||
_getBLEServices, | |||||
_closeBLEConnection, | |||||
_closeBLEAdapter, | |||||
_stopSearchBluetooth, | |||||
_notifyBLECharacteristicValueChange, | |||||
_onBluetoothFound, | |||||
_getBluetoothDevices, | |||||
_startSearch, | |||||
_openAdapter, | |||||
_sentOrder, | |||||
_writeBLECharacteristicValue, | |||||
promisify, | |||||
promisify_callback, | |||||
}; |
@ -0,0 +1,6 @@ | |||||
//公共配置项 | |||||
const globalData = { | |||||
appId: "", | |||||
baseUrlImg: "", | |||||
}; | |||||
export { globalData }; |
@ -0,0 +1,153 @@ | |||||
function 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(':') | |||||
} | |||||
function formatNumber(n) { | |||||
n = n.toString() | |||||
return n[1] ? n : '0' + n | |||||
} | |||||
function uint8ArrayToString(fileData){ | |||||
let dataString = ""; | |||||
for (let i = 0; i < fileData.length; i++) { | |||||
dataString += String.fromCharCode(fileData[i]); | |||||
} | |||||
return dataString | |||||
} | |||||
function stringToUint8Array(str){ | |||||
let arr = []; | |||||
for (let i = 0, j = str.length; i < j; ++i) { | |||||
arr.push(str.charCodeAt(i)); | |||||
} | |||||
let tmpUint8Array = new Uint8Array(arr); | |||||
return tmpUint8Array | |||||
} | |||||
// 微信官方给的ArrayBuffer转十六进制示例 | |||||
function ab2hex(buffer) { | |||||
let hexArr = Array.prototype.map.call( | |||||
new Uint8Array(buffer), | |||||
function (bit) { | |||||
return ('00' + bit.toString(16)).slice(-2) | |||||
} | |||||
) | |||||
return hexArr.join(','); | |||||
} | |||||
//转成可展会的文字 | |||||
function hexCharCodeToStr(hexCharCodeStr) { | |||||
let trimedStr = hexCharCodeStr.trim(); | |||||
let rawStr = trimedStr.substr(0, 2).toLowerCase() === '0x' ? trimedStr.substr(2) : trimedStr; | |||||
let len = rawStr.length; | |||||
let curCharCode; | |||||
let resultStr = []; | |||||
for (let i = 0; i < len; i = i + 2) { | |||||
curCharCode = parseInt(rawStr.substr(i, 2), 16); | |||||
resultStr.push(String.fromCharCode(curCharCode)); | |||||
} | |||||
return resultStr.join(''); | |||||
} | |||||
//转换成需要的格式 | |||||
function buf2string(buffer) { | |||||
let arr = Array.prototype.map.call(new Uint8Array(buffer), x => x) | |||||
return arr.map((char, i) => { | |||||
return String.fromCharCode(char); | |||||
}).join(''); | |||||
} | |||||
function decodeHexNibble(c) { | |||||
if (c >= 48 && c <= 57) { | |||||
return c - 48; | |||||
} else if (c >= 65 && c <= 70) { | |||||
return c - 65 + 10; | |||||
} else { | |||||
return c >= 97 && c <= 102 ? c - 97 + 10 : -1; | |||||
} | |||||
} | |||||
function decodeHexByte(s, pos) { | |||||
let hi = decodeHexNibble(s.charCodeAt(pos)); | |||||
let lo = decodeHexNibble(s.charCodeAt(pos + 1)); | |||||
return ((hi << 4) + lo); | |||||
} | |||||
function hexStringToBytesWithPadding(str, byteLen, padding) { | |||||
let len = str.length | |||||
let length = 2 * byteLen | |||||
if (length >= len && (length & 1) == 0) { | |||||
if (length == 0) { | |||||
return [0]; | |||||
} else { | |||||
let bytes = new Uint8Array(length >>> 1); | |||||
for(let i = 0; i < len; i += 2) { | |||||
bytes[i >>> 1] = decodeHexByte(str, i); | |||||
} | |||||
for(let i = 0; i < byteLen-len/2; i++) | |||||
bytes[len/2+i] = padding; | |||||
return bytes; | |||||
} | |||||
} | |||||
else | |||||
return [0]; | |||||
} | |||||
function hexStringToBytes(str) { | |||||
let s = str; | |||||
if(s.length < 12) | |||||
{ | |||||
let tmp = 12-s.length | |||||
for(let i = 0; i< tmp; i++) | |||||
s = "0" + s; | |||||
} | |||||
else | |||||
s = str.substr(s.length-12, s.length); | |||||
let start = 0 | |||||
let length = s.length | |||||
if (length >= 0 && (length & 1) == 0) { | |||||
if (length == 0) { | |||||
return new byte[0]; | |||||
} else { | |||||
let bytes = new Uint8Array(length >>> 1); | |||||
for(let i = 0; i < length; i += 2) { | |||||
bytes[i >>> 1] = decodeHexByte(s, start + i); | |||||
} | |||||
return bytes; | |||||
} | |||||
} | |||||
else | |||||
return [0]; | |||||
} | |||||
module.exports = { | |||||
formatTime: formatTime, | |||||
uint8ArrayToString: uint8ArrayToString, | |||||
stringToUint8Array: stringToUint8Array, | |||||
ab2hex: ab2hex, | |||||
hexCharCodeToStr, | |||||
hexCharCodeToStr: buf2string, | |||||
decodeHexNibble, | |||||
decodeHexNibble: decodeHexByte, | |||||
hexStringToBytesWithPadding: hexStringToBytesWithPadding, | |||||
hexStringToBytes: hexStringToBytes | |||||
} |