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 { DeviceToolKit as DeviceToolKitFR200 } from "@flossom-npm/iot-translater"; import OtaDeviceTypeEnum from "../OtaDeviceTypeEnum"; // 临时替代 var log = console; let deviceToolKitInstance: any = null; const deviceToolKitInstanceFR200 = new DeviceToolKitFR200("FR200"); deviceToolKitInstanceFR200.setDebug(true); import "./index.less"; class UpdateIotFR200 extends Component { constructor(props) { super(props); this.state = { name: "UpdateIotFR200", 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() { if (this.$checkTimer) clearInterval(this.$checkTimer); } componentDidMount() { console.log("componentDidMount"); this.initData(); } componentDidHide() { console.log("componentDidHide"); this.errorFun(); } async initData() { console.log("UpdateIotWL200"); deviceToolKitInstance = deviceToolKitInstanceFR200; let objStr = getStorageSync("instrument_detail"); if (objStr) { this.setState({ currentDevice: objStr, }); } 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(); let jsoncmd = { commandType: "OTAStart", otaDeviceType: "FR200", versionNo: this.$otaDataGroup.versionNo, }; console.log("startOTA jsoncmd", jsoncmd); //@ts-ignore const value = deviceToolKitInstance.toBleCommand(jsoncmd as any); 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 as any); 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 as any); 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 as any); 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 as any); 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); if (err.errCode === 10000) { let isDisconnect = getStorageSync("isDisconnectUpdate"); if (isDisconnect) { if (this.$checkTimer) clearInterval(this.$checkTimer); } } } }); setTimeout(() => { this.errorFun(); }, 1000); } /** * 处理返回的数据 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; } console.log( "json.currentPackageNo", json.currentPackageNo, this.$otaDataGroup.packageCount ); 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传输"); this.setState({ progressbar: 100, }); this.finishFun(); // quitOTA() break; default: break; } } /** * 从后端拉取固件包,并初始化ota流程的所需对象 */ getDeviceUpgrade = async () => { let res: any = await InstrumentInfo.getUpgrade({ instrumentId: this.state.currentDevice.id, isWe200: false, }); 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: any = 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) { this.quitOTA("shutDownMaskTip"); } else { this.$otaDataGroup.countDown--; } console.log(this.$otaDataGroup.countDown); }, 1000); } //升级销毁页面时关闭小程序蓝牙 onUnload() { console.log("onUnload"); if (this.$checkTimer) clearInterval(this.$checkTimer); Taro.closeBluetoothAdapter(); } onPullDownRefresh() { Taro.stopPullDownRefresh(); } onClickStop = (e) => { e.stopPropagation(); }; // 错误关闭回调 errorFun = () => { this.resetOta(); this.props.errorFun(); }; // 升级完成回调 finishFun = () => { this.props.finishFun(); }; render() { let { isShow } = this.props; let { progressbar } = this.state; return ( 设备升级中 {progressbar}% 注意事项: 1.保持设备开机状态 2.请勿切出该页面 ); } } const mapStateToProps = (state) => ({ bluetoothInfo: state.deviceInfo.bluetoothInfo, }); const mapDispatchToProps = (dispatch) => ({}); export default connect(mapStateToProps, mapDispatchToProps)(UpdateIotFR200);