Browse Source

小程序蓝牙通信例子

master
walson_8 3 years ago
parent
commit
1851e76b7b
30 changed files with 3258 additions and 0 deletions
  1. +33
    -0
      app.js
  2. +16
    -0
      app.json
  3. +10
    -0
      app.wxss
  4. +800
    -0
      miniprogram_npm/eventemitter2/index.js
  5. +1
    -0
      miniprogram_npm/eventemitter2/index.js.map
  6. +191
    -0
      pages/asyntest/asyntest.js
  7. +3
    -0
      pages/asyntest/asyntest.json
  8. +18
    -0
      pages/asyntest/asyntest.wxml
  9. +28
    -0
      pages/asyntest/asyntest.wxss
  10. +212
    -0
      pages/index/index.js
  11. +3
    -0
      pages/index/index.json
  12. +41
    -0
      pages/index/index.wxml
  13. +41
    -0
      pages/index/index.wxss
  14. +637
    -0
      pages/lanyatest/lanyatest.js
  15. +3
    -0
      pages/lanyatest/lanyatest.json
  16. +29
    -0
      pages/lanyatest/lanyatest.wxml
  17. +28
    -0
      pages/lanyatest/lanyatest.wxss
  18. +18
    -0
      pages/logs/logs.js
  19. +4
    -0
      pages/logs/logs.json
  20. +6
    -0
      pages/logs/logs.wxml
  21. +8
    -0
      pages/logs/logs.wxss
  22. +74
    -0
      project.config.json
  23. +7
    -0
      sitemap.json
  24. +59
    -0
      utils/btls/ble.js
  25. +296
    -0
      utils/btls/bleHandler.js
  26. +44
    -0
      utils/btls/error.js
  27. +481
    -0
      utils/btls/tools.js
  28. +6
    -0
      utils/global.js
  29. +8
    -0
      utils/long.js
  30. +153
    -0
      utils/util.js

+ 33
- 0
app.js View File

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

+ 16
- 0
app.json View File

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

+ 10
- 0
app.wxss View File

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

+ 800
- 0
miniprogram_npm/eventemitter2/index.js View File

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

+ 1
- 0
miniprogram_npm/eventemitter2/index.js.map
File diff suppressed because it is too large
View File


+ 191
- 0
pages/asyntest/asyntest.js View File

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

+ 3
- 0
pages/asyntest/asyntest.json View File

@ -0,0 +1,3 @@
{
"usingComponents": {}
}

+ 18
- 0
pages/asyntest/asyntest.wxml View File

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

+ 28
- 0
pages/asyntest/asyntest.wxss View File

@ -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;/* 自动换行 */
}

+ 212
- 0
pages/index/index.js View File

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

+ 3
- 0
pages/index/index.json View File

@ -0,0 +1,3 @@
{
"usingComponents": {}
}

+ 41
- 0
pages/index/index.wxml View File

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

+ 41
- 0
pages/index/index.wxss View File

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

+ 637
- 0
pages/lanyatest/lanyatest.js View File

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

+ 3
- 0
pages/lanyatest/lanyatest.json View File

@ -0,0 +1,3 @@
{
"usingComponents": {}
}

+ 29
- 0
pages/lanyatest/lanyatest.wxml View File

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

+ 28
- 0
pages/lanyatest/lanyatest.wxss View File

@ -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;/* 自动换行 */
}

+ 18
- 0
pages/logs/logs.js View File

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

+ 4
- 0
pages/logs/logs.json View File

@ -0,0 +1,4 @@
{
"navigationBarTitleText": "查看启动日志",
"usingComponents": {}
}

+ 6
- 0
pages/logs/logs.wxml View File

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

+ 8
- 0
pages/logs/logs.wxss View File

@ -0,0 +1,8 @@
.log-list {
display: flex;
flex-direction: column;
padding: 40rpx;
}
.log-item {
margin: 10rpx;
}

+ 74
- 0
project.config.json View File

@ -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": []
}
}
}

+ 7
- 0
sitemap.json View File

@ -0,0 +1,7 @@
{
"desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
"rules": [{
"action": "allow",
"page": "*"
}]
}

+ 59
- 0
utils/btls/ble.js View File

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

+ 296
- 0
utils/btls/bleHandler.js View File

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

+ 44
- 0
utils/btls/error.js View File

@ -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 "蓝牙功能暂不支持"
}
}
}

+ 481
- 0
utils/btls/tools.js View File

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

+ 6
- 0
utils/global.js View File

@ -0,0 +1,6 @@
//公共配置项
const globalData = {
appId: "",
baseUrlImg: "",
};
export { globalData };

+ 8
- 0
utils/long.js
File diff suppressed because it is too large
View File


+ 153
- 0
utils/util.js View File

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

Loading…
Cancel
Save