| @ -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 | |||||
| } | |||||