|
|
|
|
@ -0,0 +1,462 @@
|
|
|
|
|
import Taro from "@tarojs/taro";
|
|
|
|
|
import classnames from "classnames";
|
|
|
|
|
|
|
|
|
|
import { Component, PropsWithChildren, useEffect, useState } from "react";
|
|
|
|
|
import { Block, View, Text, PageMeta } from "@tarojs/components";
|
|
|
|
|
import { Popup, Progress } from "@antmjs/vantui";
|
|
|
|
|
|
|
|
|
|
import { connect } from "react-redux";
|
|
|
|
|
import {
|
|
|
|
|
msg,
|
|
|
|
|
back,
|
|
|
|
|
showModal,
|
|
|
|
|
go,
|
|
|
|
|
loading,
|
|
|
|
|
getStorageSync,
|
|
|
|
|
} from "@/utils/traoAPI";
|
|
|
|
|
import { InstrumentInfo } from "@/utils/Interface";
|
|
|
|
|
import {
|
|
|
|
|
notifyBLECharacteristicValueChange,
|
|
|
|
|
writeBLECharacteristicValue,
|
|
|
|
|
sendCommand,
|
|
|
|
|
} from "@/utils/bluetoothWXAPI";
|
|
|
|
|
import {
|
|
|
|
|
ab2hex,
|
|
|
|
|
ccrc8,
|
|
|
|
|
filterBleData,
|
|
|
|
|
hex2int,
|
|
|
|
|
string2buffer,
|
|
|
|
|
} from "@/utils/util";
|
|
|
|
|
import {
|
|
|
|
|
Stringkit,
|
|
|
|
|
TResponseFromDevice,
|
|
|
|
|
} from "@flossom-npm/iot-translater-we100";
|
|
|
|
|
|
|
|
|
|
// 通过设备类型判断给 deviceToolKitInstance 赋值
|
|
|
|
|
import { DeviceToolKit as DeviceToolKitWE100 } from "@flossom-npm/iot-translater-we100";
|
|
|
|
|
|
|
|
|
|
import InstrumentTypeEnum from "../InstrumentTypeEnum";
|
|
|
|
|
import OtaDeviceTypeEnum from "../OtaDeviceTypeEnum";
|
|
|
|
|
|
|
|
|
|
// 临时替代
|
|
|
|
|
var log = console;
|
|
|
|
|
var deviceToolKitInstance: any = null;
|
|
|
|
|
deviceToolKitInstance = new DeviceToolKitWE100("WE100", "WL200");
|
|
|
|
|
|
|
|
|
|
import "./index.less";
|
|
|
|
|
|
|
|
|
|
class UpdateIotWL200 extends Component<any, any> {
|
|
|
|
|
constructor(props) {
|
|
|
|
|
super(props);
|
|
|
|
|
this.state = {
|
|
|
|
|
name: "UpdateIotWL200",
|
|
|
|
|
progressbar: 1, // 进度条
|
|
|
|
|
|
|
|
|
|
currentDevice: {},
|
|
|
|
|
|
|
|
|
|
hadStartOta: false, // 是否开始ota
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$instance = Taro.getCurrentInstance();
|
|
|
|
|
$checkTimer: any = null;
|
|
|
|
|
// 与页面渲染无关的数据
|
|
|
|
|
$otaDataGroup: any = {
|
|
|
|
|
// 包大小,面罩设置为100,主机设置为240
|
|
|
|
|
packageSize: 240, //每个包的大小上限(单位是字节)
|
|
|
|
|
otaBin: null, //固件包buffer形式,从16进制字符串转换成
|
|
|
|
|
otaHexString: "", //固件包的16进制字符串,从后端接口返回
|
|
|
|
|
packageLength: 0, //升级包的总长度(单位是字节)
|
|
|
|
|
packageCount: 0, //分包后的总包数
|
|
|
|
|
otaData: [], //分包数组
|
|
|
|
|
packageCrc8: "", //总包的校验码
|
|
|
|
|
versionNo: "", //包的版本号
|
|
|
|
|
otaCurrentPackageIndex: 0, //现在正在传输的分包索引
|
|
|
|
|
countDown: 7,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
async onLoad() {}
|
|
|
|
|
componentDidMount() {
|
|
|
|
|
this.initData();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async initData() {
|
|
|
|
|
console.log("UpdateIotWL200");
|
|
|
|
|
let objStr = getStorageSync("instrument_detail");
|
|
|
|
|
if (objStr) {
|
|
|
|
|
let info = JSON.parse(objStr);
|
|
|
|
|
|
|
|
|
|
this.setState({
|
|
|
|
|
currentDevice: info,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (info.model == InstrumentTypeEnum.WL200) {
|
|
|
|
|
deviceToolKitInstance = new DeviceToolKitWE100("WE100", "WL200");
|
|
|
|
|
} else {
|
|
|
|
|
deviceToolKitInstance = new DeviceToolKitWE100("WE100", "M01");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
this.notifyBLECharacteristicValueChange();
|
|
|
|
|
this.getDeviceUpgrade();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 拆分升级包
|
|
|
|
|
*/
|
|
|
|
|
async getUpgradeData() {
|
|
|
|
|
//解析获取升级包更新数据
|
|
|
|
|
const { otaHexString, packageSize } = this.$otaDataGroup;
|
|
|
|
|
if (!otaHexString?.length) {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
let arr: any = [];
|
|
|
|
|
for (let i = 0, len = otaHexString.length; i < len; i += packageSize * 2) {
|
|
|
|
|
let index = i + packageSize * 2;
|
|
|
|
|
let value = otaHexString.slice(i, index);
|
|
|
|
|
arr.push(value);
|
|
|
|
|
}
|
|
|
|
|
return arr;
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* 重置OTA状态
|
|
|
|
|
*/
|
|
|
|
|
resetOta() {
|
|
|
|
|
this.$otaDataGroup = {
|
|
|
|
|
...this.$otaDataGroup,
|
|
|
|
|
otaCurrentPackageIndex: 0,
|
|
|
|
|
otaData: [],
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* 启动ota
|
|
|
|
|
*/
|
|
|
|
|
startOTA() {
|
|
|
|
|
this.resetOta();
|
|
|
|
|
const { currentDevice } = this.state;
|
|
|
|
|
let jsoncmd = {
|
|
|
|
|
commandType: "OTAStart",
|
|
|
|
|
otaDeviceType: "",
|
|
|
|
|
versionNo: this.$otaDataGroup.versionNo,
|
|
|
|
|
};
|
|
|
|
|
// 根据设备类型传 otaDeviceType
|
|
|
|
|
if (currentDevice.model == InstrumentTypeEnum.M01) {
|
|
|
|
|
jsoncmd.otaDeviceType = OtaDeviceTypeEnum.WE100;
|
|
|
|
|
} else {
|
|
|
|
|
jsoncmd.otaDeviceType = OtaDeviceTypeEnum.WL200;
|
|
|
|
|
}
|
|
|
|
|
// deviceToolKitInstance.setDebug(true)
|
|
|
|
|
|
|
|
|
|
//@ts-ignore
|
|
|
|
|
const value = deviceToolKitInstance.toBleCommand(jsoncmd);
|
|
|
|
|
console.log(jsoncmd);
|
|
|
|
|
sendCommand({ value }).then((res) => {
|
|
|
|
|
this.setState({
|
|
|
|
|
hadStartOta: true,
|
|
|
|
|
});
|
|
|
|
|
this.createTimer();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* 准备ota
|
|
|
|
|
*/
|
|
|
|
|
preOTA() {
|
|
|
|
|
const { packageCount, packageLength, packageCrc8, versionNo } =
|
|
|
|
|
this.$otaDataGroup;
|
|
|
|
|
let jsoncmd = {
|
|
|
|
|
commandType: "OTAPrepare",
|
|
|
|
|
packageCount,
|
|
|
|
|
packageLength,
|
|
|
|
|
packageCrc8,
|
|
|
|
|
versionNo,
|
|
|
|
|
};
|
|
|
|
|
console.info("OTAPrepare json => ", jsoncmd);
|
|
|
|
|
//@ts-ignore
|
|
|
|
|
const value = deviceToolKitInstance.toBleCommand(jsoncmd);
|
|
|
|
|
sendCommand({ value });
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* ota升级
|
|
|
|
|
*/
|
|
|
|
|
processOTA(i, data) {
|
|
|
|
|
const { packageCount, packageLength } = this.$otaDataGroup;
|
|
|
|
|
if (!packageLength) {
|
|
|
|
|
this.quitOTA();
|
|
|
|
|
}
|
|
|
|
|
let jsoncmd = {
|
|
|
|
|
commandType: "OTAUpdating",
|
|
|
|
|
packageCount,
|
|
|
|
|
packageLength,
|
|
|
|
|
currentPackageNo: i + 1,
|
|
|
|
|
currentPackageLength: data.length / 2,
|
|
|
|
|
currentPackageContent: data,
|
|
|
|
|
};
|
|
|
|
|
console.info("OTAUpdating json => ", jsoncmd);
|
|
|
|
|
//@ts-ignore
|
|
|
|
|
const value = deviceToolKitInstance.toBleCommand(jsoncmd);
|
|
|
|
|
sendCommand({ value });
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* ota升级完成
|
|
|
|
|
*/
|
|
|
|
|
async finishedOTA() {
|
|
|
|
|
let jsoncmd = {
|
|
|
|
|
commandType: "OTAUpdateFinish",
|
|
|
|
|
versionNo: this.$otaDataGroup.versionNo,
|
|
|
|
|
};
|
|
|
|
|
clearInterval(this.$checkTimer);
|
|
|
|
|
log.info("ota成功日志, 清除计时器");
|
|
|
|
|
//@ts-ignore
|
|
|
|
|
const value = deviceToolKitInstance.toBleCommand(jsoncmd);
|
|
|
|
|
sendCommand({ value }).then((res) => {
|
|
|
|
|
this.resetOta();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* ota升级强制退出
|
|
|
|
|
*/
|
|
|
|
|
quitOTA(errorString = "") {
|
|
|
|
|
// log.info('ota失败日志', errorString);
|
|
|
|
|
console.log("ota失败日志", errorString);
|
|
|
|
|
const errorMap = {
|
|
|
|
|
packageError: "总包错误",
|
|
|
|
|
packageNumError: "包号错误",
|
|
|
|
|
checkedError: "校验错误",
|
|
|
|
|
dataLengthError: "数据总长度错误",
|
|
|
|
|
dataCRCError: "数据总数CRC错误",
|
|
|
|
|
updateTimeOut: "数据更新超时",
|
|
|
|
|
};
|
|
|
|
|
let jsoncmd = {
|
|
|
|
|
commandType: "OTAQuit",
|
|
|
|
|
};
|
|
|
|
|
//@ts-ignore
|
|
|
|
|
const value = deviceToolKitInstance.toBleCommand(jsoncmd);
|
|
|
|
|
sendCommand({ value })
|
|
|
|
|
.then((res) => {
|
|
|
|
|
this.resetOta();
|
|
|
|
|
// this.showError(errorMap[errorString] || tipMap[errorString] || '发生错误')
|
|
|
|
|
})
|
|
|
|
|
.catch((err) => {
|
|
|
|
|
if (!this.state.hadShowError) {
|
|
|
|
|
this.setState({
|
|
|
|
|
hadShowError: true,
|
|
|
|
|
});
|
|
|
|
|
// log.info('ota失败日志', '发送日志OTAQuit失败', err);
|
|
|
|
|
console.info("ota失败日志", "发送日志OTAQuit失败", err);
|
|
|
|
|
// this.showError(errorMap[errorString] || tipMap[errorString] || '发生错误')
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 处理返回的数据 OTA用
|
|
|
|
|
*/
|
|
|
|
|
async parseData(json) {
|
|
|
|
|
console.log("parseData json.commandType", json.commandType);
|
|
|
|
|
if (!json || !json.commandType) return;
|
|
|
|
|
switch (json.commandType) {
|
|
|
|
|
case "OTAStart":
|
|
|
|
|
if (json.responseStatus == "OK") {
|
|
|
|
|
const otaData = await this.getUpgradeData();
|
|
|
|
|
this.$otaDataGroup = {
|
|
|
|
|
...this.$otaDataGroup,
|
|
|
|
|
otaData,
|
|
|
|
|
};
|
|
|
|
|
this.$otaDataGroup.otaCurrentPackageIndex = 0;
|
|
|
|
|
this.preOTA();
|
|
|
|
|
} else {
|
|
|
|
|
this.quitOTA(json.responseStatus);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case "OTAPrepare":
|
|
|
|
|
if (json.responseStatus == "OK") {
|
|
|
|
|
this.processOTA(0, this.$otaDataGroup.otaData[0]);
|
|
|
|
|
} else {
|
|
|
|
|
this.quitOTA(json.responseStatus);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case "OTAUpdating":
|
|
|
|
|
if (json.responseStatus == "OK") {
|
|
|
|
|
let ota = this.$otaDataGroup;
|
|
|
|
|
let progressbar =
|
|
|
|
|
(ota.otaCurrentPackageIndex / ota.packageCount) * 100;
|
|
|
|
|
this.setState({
|
|
|
|
|
progressbar: (progressbar <= 1 ? 1 : progressbar).toFixed(0),
|
|
|
|
|
});
|
|
|
|
|
if (!json.currentPackageNo) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (json.currentPackageNo < this.$otaDataGroup.packageCount) {
|
|
|
|
|
this.$otaDataGroup.otaCurrentPackageIndex++;
|
|
|
|
|
this.processOTA(
|
|
|
|
|
this.$otaDataGroup.otaCurrentPackageIndex,
|
|
|
|
|
this.$otaDataGroup.otaData[
|
|
|
|
|
this.$otaDataGroup.otaCurrentPackageIndex
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
this.finishedOTA();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
this.quitOTA(json.responseStatus);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case "OTAUpdateFinish":
|
|
|
|
|
console.log("完成OTA传输");
|
|
|
|
|
log.info("ota成功日志, 但是这个分支什么都没做");
|
|
|
|
|
// quitOTA()
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* 从后端拉取固件包,并初始化ota流程的所需对象
|
|
|
|
|
*/
|
|
|
|
|
getDeviceUpgrade = async () => {
|
|
|
|
|
let res: any = await InstrumentInfo.getUpgrade({
|
|
|
|
|
instrumentId: this.state.currentDevice.id,
|
|
|
|
|
isWe200: true,
|
|
|
|
|
});
|
|
|
|
|
if (res.data.data == "解析失败") {
|
|
|
|
|
// this.showError('文件解析失败');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (res.data.code !== 200) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const otaHexString = res.data.data;
|
|
|
|
|
const otaBin = string2buffer(res.data.data);
|
|
|
|
|
const packageLength = otaBin?.byteLength || 0;
|
|
|
|
|
const packageSize = this.$otaDataGroup.packageSize;
|
|
|
|
|
const packageCrc8 = Stringkit.getCrc8CodeByString(otaHexString);
|
|
|
|
|
const packageCount = Math.ceil(packageLength / packageSize);
|
|
|
|
|
let { iotVersion: versionNo } = this.state.currentDevice;
|
|
|
|
|
this.$otaDataGroup = {
|
|
|
|
|
...this.$otaDataGroup,
|
|
|
|
|
otaHexString,
|
|
|
|
|
otaBin,
|
|
|
|
|
packageLength,
|
|
|
|
|
packageSize,
|
|
|
|
|
packageCrc8,
|
|
|
|
|
packageCount,
|
|
|
|
|
versionNo,
|
|
|
|
|
};
|
|
|
|
|
console.log("this.$otaDataGroup ", this.$otaDataGroup);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
notifyBLECharacteristicValueChange = () => {
|
|
|
|
|
const bluetoothInfo = this.props.bluetoothInfo;
|
|
|
|
|
notifyBLECharacteristicValueChange({
|
|
|
|
|
deviceId: bluetoothInfo.deviceId,
|
|
|
|
|
servicesuuid: bluetoothInfo.servicesuuid,
|
|
|
|
|
characteristicsuuid1: bluetoothInfo.characteristicsuuid1,
|
|
|
|
|
characteristicsuuid0: bluetoothInfo.characteristicsuuid0,
|
|
|
|
|
}).then((res) => {
|
|
|
|
|
Taro.onBLECharacteristicValueChange((value) => {
|
|
|
|
|
// let str = ab2hex(value.value); //转为16进制字符串
|
|
|
|
|
// console.log('返回',str)
|
|
|
|
|
const jsonStatus = deviceToolKitInstance.toJsonStatus(value.value);
|
|
|
|
|
log.info("OTA页面设备响应数据打印==》", JSON.stringify(jsonStatus));
|
|
|
|
|
console.info("onBLECharacteristicValueChange json => ", jsonStatus);
|
|
|
|
|
this.$otaDataGroup.currentPackageNo = jsonStatus.currentPackageNo;
|
|
|
|
|
|
|
|
|
|
this.$otaDataGroup.countDown = 7;
|
|
|
|
|
this.parseData(jsonStatus);
|
|
|
|
|
});
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
this.startOTA();
|
|
|
|
|
}, 500);
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
createTimer() {
|
|
|
|
|
log.info("设备ota计时器创建成功");
|
|
|
|
|
this.$checkTimer = setInterval(() => {
|
|
|
|
|
// 超过7s没有回包, 直接断开
|
|
|
|
|
if (this.$otaDataGroup.countDown <= 0 && this.state.hadStartOta) {
|
|
|
|
|
if (this.state.currentDevice.model == InstrumentTypeEnum.M01) {
|
|
|
|
|
this.quitOTA("shutDownMaskTip");
|
|
|
|
|
} else {
|
|
|
|
|
this.quitOTA("updateTimeOut");
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
this.$otaDataGroup.countDown--;
|
|
|
|
|
}
|
|
|
|
|
console.log(this.$otaDataGroup.countDown);
|
|
|
|
|
}, 1000);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//升级销毁页面时关闭小程序蓝牙
|
|
|
|
|
onUnload() {
|
|
|
|
|
if (this.$checkTimer) clearInterval(this.$checkTimer);
|
|
|
|
|
Taro.closeBluetoothAdapter();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onPullDownRefresh() {
|
|
|
|
|
Taro.stopPullDownRefresh();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onClose = () => {
|
|
|
|
|
this.props.close();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
onConfirm = () => {
|
|
|
|
|
this.props.confirm();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
onClickStop = (e) => {
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
render() {
|
|
|
|
|
let { isShow } = this.props;
|
|
|
|
|
return (
|
|
|
|
|
<Block>
|
|
|
|
|
<PageMeta pageStyle={isShow ? "overflow: hidden;" : ""} />
|
|
|
|
|
<Popup
|
|
|
|
|
show={isShow}
|
|
|
|
|
closeOnClickOverlay={false}
|
|
|
|
|
round
|
|
|
|
|
overlayStyle="width: 100vw;padding: 0;"
|
|
|
|
|
onClick={this.onClickStop}
|
|
|
|
|
>
|
|
|
|
|
<View
|
|
|
|
|
className={classnames(
|
|
|
|
|
"common-box",
|
|
|
|
|
"common-progress-box",
|
|
|
|
|
"common-large"
|
|
|
|
|
)}
|
|
|
|
|
catchMove
|
|
|
|
|
>
|
|
|
|
|
<View className={classnames("common-popup-title", "margin-samll")}>
|
|
|
|
|
设备升级中
|
|
|
|
|
</View>
|
|
|
|
|
<View className="common-popup-content-box">
|
|
|
|
|
<View className={classnames("common-popup-content", "text-left")}>
|
|
|
|
|
<View className="progress">
|
|
|
|
|
<Progress
|
|
|
|
|
percentage={0.01 * 100}
|
|
|
|
|
strokeWidth="12"
|
|
|
|
|
color="linearGradient(to right, #eecda1, #ffe9c7) !important"
|
|
|
|
|
/>
|
|
|
|
|
<View className="percent"> {0.01 * 100}%</View>
|
|
|
|
|
</View>
|
|
|
|
|
<View className="progress-tips">注意事项:</View>
|
|
|
|
|
<View className="progress-tips">1.保持设备开机状态</View>
|
|
|
|
|
<View className="progress-tips">2.请勿切出该页面</View>
|
|
|
|
|
</View>
|
|
|
|
|
</View>
|
|
|
|
|
</View>
|
|
|
|
|
</Popup>
|
|
|
|
|
</Block>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const mapStateToProps = (state) => ({
|
|
|
|
|
bluetoothInfo: state.deviceInfo.bluetoothInfo,
|
|
|
|
|
});
|
|
|
|
|
const mapDispatchToProps = (dispatch) => ({});
|
|
|
|
|
export default connect(mapStateToProps, mapDispatchToProps)(UpdateIotWL200);
|