TMRAppBle/script/ble.js

804 lines
30 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use strict";
/*初始化蓝牙适配器*/
//扫描时长,定时任务
let times = 5;
let scanInter;
// 连接失败次数
let connectTimes = 0;
// 蓝牙uuid
let peripheralUUID =''
// 蓝牙服务id
let serviceUUID =''
// 蓝牙特征id
let characteristicUUID =''
// 蓝牙待发送消息列表
let msgList = [];
// 蓝牙消息发送定时任务150ms
let timerMsgList = null;
// 未装料状态计数采集达到10次发送一次停止蜂鸣指令
let bleConunt=0;
// 默认不自动跳转
let allowAuto = false;
// 清除消息定时任务
clearInterval(timerMsgList)
//蜂鸣器最后控制时间
let lastTime = new Date().getSeconds()*1000+ new Date().getMilliseconds();
// 接收重量数据计数
let countLED = 0;
//判断是否稳定记录的上次重量信息
let weight = 0;
/**
* 初始化蓝牙
* @param param
*/
function initManager(param) {
ble.initManager(param, function (ret) {
if (ret.state === "poweredOn") {
scan({clean: true});
} else if (ret.state === 'poweredOff') {
api.hideProgress();
mui.alert('检查蓝牙是否打开');
document.getElementById('text').innerHTML = '检查蓝牙是否打开';
}
});
}
/**
* 扫描蓝牙
* @param param
*/
function scan(param) {
if (!uuid){
//从缓存获取uuid
uuid = api.getPrefs({ sync: true, key: 'uuid' });
}
// 存在缓存uuid
if (uuid){
// 已连接先断开
isConnected({peripheralUUID: uuid},function(ret){
if(ret){
disconnect({peripheralUUID: uuid});
}
})
}
//定时扫描
clearInterval(scanInter)
times = 5;
ble.scan(param, function (ret) {
if (ret.status) {
scanInter = setInterval(function (){
if (times>0){
times --;
let wifiDom = document.getElementById('wifiDom');
wifiDom.innerHTML = "扫描中"+times;
api.showProgress({
title: '扫描中'+times+'...',
modal: true
});
}else {
stopScan()
clearInterval(scanInter)
getPeripheral();
}
},1000)
}
});
}
/**
* 停止扫描
*/
function stopScan(){
ble.stopScan()
}
/**
* 获取扫描结果
*/
function getPeripheral() {
ble.getPeripheral(function (ret) {
bleData = []
let wifiDom = document.getElementById('wifiDom');
if (ret.peripherals.length > 0) {
ret.peripherals.forEach(function (p) {
if (undefined !== p.name) {
if (p.name.indexOf("TMR_BLE") === -1){
return false
}else{
console.log(p.name);
mui.toast("已扫描到" +p.name,{duration:3500,type:'div'});
wifiDom.innerHTML = p.name+'(未连接)';
document.getElementById('showBlePicker').setAttribute("class", 'btnc mui-btn-inline mui-btn-primary');
let json = { value: p.uuid, text: p.name };
bleData.push(json);
//自动连接上次蓝牙
if (uuid && uuid === p.uuid){
document.getElementById('showBlePicker').innerHTML = p.name
connect({peripheralUUID: uuid});
// isConnected({peripheralUUID: uuid},function(ret){
// if(ret){
// disconnect({peripheralUUID: uuid});
// connect({peripheralUUID: uuid});
// }else{
// connect({peripheralUUID: uuid});
// }
// })
}
}
}
});
if(!bleData.length>0){
mui.toast("暂未扫描到蓝牙设备",{duration:3500,type:'div'});
document.getElementById('showBlePicker').setAttribute("class", 'btnc mui-btn-inline mui-btn-primary dis');
wifiDom.innerHTML = "重新扫描";
}else{
bleInit()
}
}
api.hideProgress();
});
}
/**
* 连接蓝牙
* @param param
*/
function connect(param) {
let wifiDom = document.getElementById('wifiDom');
wifiDom.innerHTML = "";
api.showProgress({
title: '蓝牙连接中...',
modal: true
});
ble.connect(param, function (ret, err) {
if (ret.status) {
wifiDom.innerHTML = '已连接';
api.hideProgress();
connetcedStatus = true
// 缓存蓝牙设备uuid方便自动连接
api.setPrefs({ key: 'uuid', value: param.peripheralUUID });
//累计连接次数
if (connectTimes>0){
addNotice(1,'#02a7f0',sbId + '主机端第'+connectTimes+'次重连成功');
}else {
addNotice(1,'#02a7f0',sbId + '主机端初始化连接成功');
}
//连接成功清空连接次数
connectTimes = 0;
document.getElementById('text').innerHTML = '设备已连接';
text = '设备已连接';
// console.log('主机端连接成功')
//设置MTU包大小
ble.setMtu({
peripheralUUID: param.peripheralUUID,
mtu:150
},function(ret){
if(ret.status){
// 加载图表
initWeight();
discoverService({peripheralUUID: param.peripheralUUID});
}else{
mui.alert(ret.code)
}
});
}else {
console.log('主机端连接失败'+JSON.stringify(err))
wifiDom.innerHTML = '连接失败';
api.hideProgress();
connetcedStatus = false
//累计连接次数
if (connectTimes > 0){
if(connectTimes%10 === 0){
addNotice(4,'red',sbId + '主机端第'+connectTimes+'次重连失败');
}
}else {
addNotice(4,'red',sbId + '主机端连接失败,开始尝试重连');
}
//连接失败一次加一次
connectTimes ++;
setTimeout(function (){
if (!connetcedStatus && uuid && feedStatus){
console.log("连接失败!尝试重连" + uuid);
wifiDom.innerHTML = '尝试重连';
connect({peripheralUUID: uuid});
}
},3000)
}
});
}
/*断开连接*/
function disconnect(param) {
ble.disconnect(param, function (ret, err) {
if (ret.status) {
console.log("断开连接成功!");
} else {
console.log("断开连接失败!"+JSON.stringify(err));
}
});
}
/*判断是否已连接*/
function isConnected(param,callback){
ble.isConnected(param, function(ret) {
if (ret.status) {
// console.log('已连接');
}
callback(ret.status)
});
}
setTimeout(() => {
timerMsgList = setInterval(function () {
select(db, 'SELECT * FROM t_ble_msg order by id', function (ret, err) {
if (!ret.status) {
console.log(JSON.stringify(err))
}
var data = ret.data
// console.log(data.length)
if (data.length > 0) {
// console.log(Number(data[0].id))
// 发送报文
let msg = data[0].text;
var sql = "delete from t_ble_msg where id = '" + Number(data[0].id) + "'";
execute(db, sql, function (ret, err) {
if (!ret.status) {
console.log(JSON.stringify(err))
}
})
let param1 = {
peripheralUUID: peripheralUUID,
serviceUUID: serviceUUID,
characteristicUUID: characteristicUUID,
value: msg,
writeType:'withoutResponse'
};
if(connetcedStatus && peripheralUUID && serviceUUID && characteristicUUID){
writeValueForCharacteristic(param1, function (ret) {
// led屏幕
var booleanLed = msg.startsWith('FF05') && msg.substr(8,4) === 'AAA5';
// 设备消息数据同步
var booleanSendWeight = msg.startsWith('FF0A0004');
if (ret.status && msg.length > 12 && (booleanLed || booleanSendWeight)) {
// 同步刷新图表
// 饲喂状态刷新实时状态,否则不刷新装料信息
if(feedStatus && (allowAuto || weightBeforefix ==='1')){
renderUnload();
feedMyChart.setOption({
dataset: {
source: [[1, _feedNum]]
}
});
}
renderLoad();
weightMyChart.setOption({
dataset: {
source: [[1, nowWeight]]
}
});
}
// console.log(ret.status)
});
}
}
})
}, 100);
}, 3000);
// /*蓝牙消息发送定时任务150ms*/
// timerMsgList = setInterval(function(){
// // console.log(new Date().getSeconds()+ ' ' + new Date().getMilliseconds() +' ' + msgList.length)
// if (msgList.length > 0) {
// // 发送报文
// let msg = msgList[0];
// msgList.splice(0, 1);
// let param1 = {
// peripheralUUID: peripheralUUID,
// serviceUUID: serviceUUID,
// characteristicUUID: characteristicUUID,
// value: msg,
// writeType:'withoutResponse'
// };
// if(connetcedStatus && peripheralUUID && serviceUUID && characteristicUUID){
// writeValueForCharacteristic(param1, function (ret) {
// // console.log(ret.status)
// });
// }
// }
// },100)
// let mss = '';
// setInterval(function(){
// // console.log(currTimeFnMs(new Date))
// let param1 = {
// peripheralUUID: peripheralUUID,
// serviceUUID: serviceUUID,
// characteristicUUID: characteristicUUID,
// value: mss,
// writeType:'withoutResponse'
// };
// if(connetcedStatus && peripheralUUID && serviceUUID && characteristicUUID && mss.length>0){
// writeValueForCharacteristic(param1, function (ret) {
// // console.log(ret.status)
// });
// }
// },100)
function currTimeFnMs(_date) {
var _year = _date.getFullYear();
var _month = _date.getMonth() + 1 < 10 ? '0' + (_date.getMonth() + 1) : _date.getMonth() + 1;
var _day = _date.getDate() < 10 ? '0' + _date.getDate() : _date.getDate();
var _hour = _date.getHours() < 10 ? '0' + _date.getHours() : _date.getHours();
var _minutes = _date.getMinutes() < 10 ? '0' + _date.getMinutes() : _date.getMinutes();
var _seconds = _date.getSeconds() < 10 ? '0' + _date.getSeconds() : _date.getSeconds();
var _ms = _date.getMilliseconds() < 10 ? '0' + _date.getMilliseconds() : _date.getMilliseconds();
return _year + "-" + _month + "-" + _day + " " + _hour + ":" + _minutes + ":" + _seconds + " "+_ms;
}
/*扫描蓝牙服务*/
function discoverService(param) {
ble.discoverService(param, function (ret) {
if (ret.services.length > 0) {
// console.log("发现服务成功!");
ret.services.forEach(function (ret4) {
if (ret4.indexOf("0000ffe") !== -1) {
if (ret4 && ret4.length > 0) {
//发现特征
discoverCharacteristics({
serviceUUID: ret4,
peripheralUUID: param.peripheralUUID
}, function (ret5) {
if(ret5.indexOf("0000ffe2")!==-1){
return false
}
// console.log(ret5)
peripheralUUID = param.peripheralUUID;
serviceUUID =ret4;
characteristicUUID =ret5;
//监听消息
setNotify({
peripheralUUID: param.peripheralUUID,
serviceUUID: ret4,
characteristicUUID: ret5
}, function (ret6) {
if (ret6 !== undefined && ret6 !=='') {
if (isNaN(ret6)) {
return false
}
//实时总重量
nowWeight = ret6;
// 实时重量保存
totalList.push({
time: currTimeFnMs(new Date()),
nowWeight: nowWeight
});
//计算实时重量均值
const filteredValue = weightDataFilter.filter(nowWeight);
//组装并发送实时重量LED屏报文
getMess({
peripheralUUID: param.peripheralUUID,
serviceUUID: ret4,
characteristicUUID: ret5,
value: ret6
}, function (ret7) {
});
// 1装料状态
// 2已校准或不需要校准
if(feedStatus && (allowAuto || weightBeforefix ==='1')){
//第一次加载
if (first) {
first = false;
beforeWeight = nowWeight;
}
if (load) {
_feedNum = nowWeight - beforeWeight;
// _feedNum = (filteredValue - beforeWeight).toFixed(0);
document.getElementById('feedNum').innerHTML = '<font style="color:blue">:' + _planSum + '</font>/<font style="color:green">已装:' + _feedNum + '</font>';
} else {
_feedNum = beforeWeight - nowWeight;
// _feedNum = (beforeWeight - filteredValue).toFixed(0);
document.getElementById('feedNum').innerHTML = '<font style="color:blue">:' + _planSum + '</font>/<font style="color:green">已卸:' + _feedNum + '</font>';
}
// 显示饲料名称+计划饲喂量
text = feedName + _planSum;
// 计划-饲喂
var feedErr = _planSum-_feedNum;
if (isNaN(feedErr)) {
return false
}
// console.log(beforeWeight,nowWeight)
// console.log("feedErr"+feedErr,"allow:"+allow,"_feedNum:"+_feedNum,"_planSum:"+_planSum)
//蜂鸣器判断
buzzer(feedErr)
// 判断重量是否稳定
const ifSta = isStable(weightDataFilter.dataBuffer, threshold);
// 判断
// 1已开启自动跳转autoJump
// 2已校准allowAuto或者不需要校准weightBeforefix
// 3已满足误差或者已装够
if (autoJump==='0' && (feedErr <= allow || _feedNum > _planSum) && (allowAuto || weightBeforefix === '1')) {
// 已稳定
if(ifSta){
//稳定数据包
wendinSize.push({time:new Date().getTime(),val:nowWeight})
// 稳定时长
const staTimes = (wendinSize[wendinSize.length - 1].time - wendinSize[0].time) / 1000;
console.log('数据稳定时长'+staTimes)
document.getElementById('isfix').innerHTML = '<font style="color:green;font-size: x-large;">稳定'+staTimes.toFixed(0)+'</font>'
if(staTimes > weightSize){
console.log("重量稳定", currTimeFn(new Date()));
weightDataFilter.dataBuffer = []
wendinSize = []
remark = '自动跳转'
document.getElementById('submitData').click();
}
}else{
// 不稳定清空所有数据
weightDataFilter.dataBuffer = []
wendinSize = []
}
}
}
}
});
});
}
}
});
} else {
console.log("发现服务失败!");
}
});
}
function buzzer(feedErr){
// 蜂鸣器校验基础值大于500的饲料取500为标准
let count;
if (_planSum >= 500) {
count = 500
} else {
count = _planSum
}
// 计算饲料装料量与基础值的误差比例
let ration = feedErr / count;
// 误差分为100%-20%(停止蜂鸣)10%-20%(间隔05)5%-10%(间隔03),2%-5%(间隔01),-100%-2%(长鸣)
if (ration > 0.2) {
bleConunt ++;
if (statusEle || (bleConunt >= 10)) {
bleConunt=0;
status = '';
statusEle = false;
msgList = [];
control("00", "00");
setTimeout(function () {
}, 500);
}
} else if (0.1 < ration && ration <= 0.2) {
time = "05";
if (!statusEle || lastTime !== time) {
lastTime = time;
status = '间隔';
statusEle = true;
msgList = [];
console.log("开始蜂鸣" + time);
control("60", time);
setTimeout(function () {
}, 500);
}
} else if (0.05 < ration && ration <= 0.1) {
time = "03";
if (!statusEle || lastTime !== time) {
lastTime = time;
status = '间隔';
statusEle = true;
msgList = [];
console.log("开始蜂鸣" + time);
control("60", time);
setTimeout(function () {
}, 500);
}
} else if (0.02 < ration && ration <= 0.05) {
time = "01";
if (!statusEle || lastTime !== time) {
lastTime = time;
status = '间隔';
statusEle = true;
msgList = [];
console.log("开始蜂鸣" + time);
control("60", time);
setTimeout(function () {
}, 500);
}
} else {
if (status === '间隔' || status === '') {
status = '长鸣';
statusEle = true;
msgList = [];
console.log("开始长鸣");
control("40", "02");
setTimeout(function () {
}, 500);
setTimeout(function() {
console.log("开始长鸣")
control("40", "02");
setTimeout(function() {
}, 500)
}, 500)
}
}
}
/**
* 判断一组数据是否稳定在threshold误差范围内
* @param data
* @param threshold
* @returns {boolean}
*/
function isStable(data, threshold) {
// 确保输入的数据是一个数组
if (!Array.isArray(data)) {
throw new Error('Data must be an array');
}
// 确保输入的阈值是数字
if (typeof threshold !== 'number') {
throw new Error('Threshold must be a number');
}
// 找到数组中的最大值和最小值
const min = Math.min(...data);
const max = Math.max(...data);
// 计算差值的绝对值
const difference = Math.abs(max - min);
// 比较差值和阈值
return difference <= threshold;
}
/*扫描特征*/
function discoverCharacteristics(param, callback) {
ble.discoverCharacteristics(param, function (ret) {
let res = '';
if (ret.characteristics.length > 0) {
// console.log("发现特征成功!");
ret.characteristics.forEach(function (s) {
if (s.serviceUUID === param.serviceUUID) {
callback(s.uuid);
}
});
} else {
console.log("发现特征失败!");
callback(res);
}
});
}
/*适配两种称数据解析*/
function StringToNum(hexx){
var hex = hexx.toString(); //force conversion
var str = '';
var num = '';
for (var i = 0; i < hex.length; i += 2) {
num = String.fromCharCode(parseInt(hex.substr(i, 2), 16));
if((num >= '0' && num <= '9') || (num === '-'))
{
str += num;
}
else
{
if(str.length !== 0)
{
return str
}
}
}return str;
}
var weiNum = 0;
/*监听蓝牙数据,转换重量数据*/
function setNotify(param, callback) {
ble.setNotify(param, function (ret) {
var res;
var value = ret.characteristic.value;
// if (ret && value.indexOf('ff01') !== -1) {
// 获取设备称实时数据
if (ret && value.startsWith("ff01") && value.length > 8 && value.length < 50 ){
var wei = value.substr(8, value.length-8);
weiNum++;
if (shujubao >= 1 && weiNum >= (shujubao/2).toFixed(0)){
res = Math.round(Number(StringToNum(wei)));
}
// 发送实时重量和校准重量到其他平板
if(weiNum >= shujubao && undefined !== res && sbId && undefined !== beforeWeight){
weiNum = 0;
var weiHex = decimalToHex(res>0?res:res+65536).replace(' ','');
var sbIdHex = decimalToHex(sbId).replace(' ','');
var beforeHex = decimalToHex(beforeWeight>0?beforeWeight:beforeWeight+65536).replace(' ','');
var banciHex = decimalToHex(classCode).replace(' ','');
var checiHex = decimalToHex(trainNumber).replace(' ','');
var feedInexHex = decimalToHex(feedIndex).replace(' ','');
weiHex = weiHex.length < 4?'00'+weiHex:weiHex;
sbIdHex = sbIdHex.length < 4?'00'+sbIdHex:sbIdHex;
beforeHex = beforeHex.length < 4?'00'+beforeHex:beforeHex;
if(feedStatus){
var bleStr = 'FF0A0009'+weiHex+beforeHex+sbIdHex+banciHex+checiHex+feedInexHex;
// msgList.push(bleStr);
// console.log(bleStr)
execute(db, "INSERT INTO t_ble_msg (id,text) VALUES ("+new Date().getTime()+",'"+bleStr+"');", function (ret, err) {})
}
}
}
// 接收其他平板发来的校准重量和实时重量
if (feedStatus && ret && value.startsWith("ff0a") && sbId === parseInt(value.substr(8, 4),16)){
var sbId_now = parseInt(value.substr(8, 4),16);
var feedIdx = parseInt(value.substr(12, 2),16);
console.log(sbId)
if(sbId !== sbId_now || feedIndex !== feedIdx || !load){
return false
}
weightDataFilter.dataBuffer = []
wendinSize = []
document.getElementById('submitData').click();
}
callback(res);
});
}
function decimalToHex(decimal) {
let hex = decimal.toString(16);
if (hex.length % 2 !== 0) {
hex = "0" + hex;
}
if (hex.length > 2) {
var str = '';
for (var i = 0; i < hex.length; i += 2) {
str = str + hex.substr(i, 2) + ' '
}
return str.trim()
}
return hex;
}
/*发送消息到蓝牙*/
function writeValueForCharacteristic(param, callback) {
if (param.value && connetcedStatus){
ble.writeValueForCharacteristic(param, function (ret) {
// console.log(param.value)
if(param.value.startsWith('FF0A0009')){
// console.log(JSON.stringify(ret))
}
if (ret.status) {
// console.log("发送成功");
} else {
console.log("发送失败:"+param.value);
// msgList.push("FF0A000404140414");
}
callback(ret);
});
}
}
/*组装报文并发数*/
function getMess(param, callback) {
var param1 = {
SF: "AA A5 ",
LEN: '1A 00 ',
DES: 'FF FF ',
SRC: '12 34 ',
TID: 'B0 A1 ',
CMD1: '38 02 ',
X: '00 00 ',
Y: '00 00 ',
WIDTH: '40 00 ',
HEIGHT: '20 00 ',
FORMAT: '00 00 01 00 ',
CNT: '04 00 ',
CRC: '00 00 ',
EF: '5A 55 ',
msg: ''
};
var newmsg = feedName;
if(!newmsg.length>0){
return false
}
var msglen = newmsg.getByteLen();
var ttr;
if (Number(_planSum - _feedNum) >= 0) {
ttr = '少';
echartsType = '少';
} else {
ttr = '多';
echartsType = '多';
}
if (msglen < 8) {
for (var i = 0; i < 8 - msglen; i++) {
newmsg = newmsg + ' ';
}
newmsg = newmsg + ttr;
} else {
newmsg = feedName + ttr;
}
// 不是装料状态班次饲喂完成显示
if(!feedStatus){
var newmsg = batchName+'次';
var msglen = newmsg.getByteLen();
var ttr = '';
if (msglen < 8) {
for (var i = 0; i < 8 - msglen; i++) {
newmsg = newmsg + ' ';
}
newmsg = newmsg + ttr;
} else {
newmsg = feedName + ttr;
}
param1.msg = newmsg + '饲喂完成';
}else{
// param1.msg = newmsg + Math.abs(Number(_planSum - _feedNum)).toFixed(0) + 'kg';
param1.msg = newmsg + Math.abs(Number(_planSum - _feedNum)).toFixed(0);
}
// param1.msg = newmsg + Math.abs(Number(param.value)).toFixed(0) + 'kg'
// console.log(param1.msg)
//组装字符卡LED报文
zfk.getMsg(param1, function (ret, err) {
if (!ret.status){
console.log(JSON.stringify(err))
}
let str = ret.sendMsg;
str = str.replace(/\s+/g, "");
let num = str.length / 2;
param.value = "FF0500" + num.toString(16) + str;
countLED ++;
// 称重量数据3包取1包
// console.log(shujubao)
//LED报文
if (countLED >= shujubao){
countLED = 0 ;
// msgList.push(param.value);
execute(db, "INSERT INTO t_ble_msg (id,text) VALUES ("+new Date().getTime()+",'"+param.value+"');", function (ret, err) {})
}
});
callback(param1.msg)
}
/*初始化重量图表*/
function initWeight() {
api.showProgress({
title: '图表数据加装中...',
modal: true
});
renderUnload();
renderLoad();
feedMyChart.setOption({
dataset: {
source: [[1, _feedNum]]
}
});
weightMyChart.setOption({
dataset: {
source: [[1, nowWeight]]
}
});
api.hideProgress();
clearInterval(totalInterval);
totalUpload = true;
noticeUpload = true;
totalList = [];
totalInterval = setInterval(function () {
totalWeightUpload();
}, 3000);
document.getElementById('submitData').setAttribute("class", 'btnc mui-btn-success');
document.getElementById('text').innerHTML = 'V' + api.appVersion;
api.setGlobalData({key: 'startTime', value: currTimeFn(new Date())});
}