更多信息请访问:Harmonyos技术社区https://harmonyos.51cto.com是经常和最常威胁公共安全和社会的重大灾难之一发展。火给人类带来了文明、进步、光明和温暖。然而,它有时是人类的朋友,有时又是人类的敌人。失控的火灾会给人类带来灾难。在消防方面,火焰传感报警系统具有其价值。那么我们如何检测火焰呢?本文主要介绍基于LYEVK-3861物联网开发板套件的火焰传感器,开发具有火焰传感器报警功能的HarmonyOS应用,主要实现蓝牙设备扫描、连接、火焰检测、设置报警阈值。1.效果演示2.环境准备本贴不详细讲解实验环境的搭建。实验环境的具体准备请参考:《HarmonyOS 官方文档》LYEVK-3861物联网开发板套件:(权限P:APP下发;G:设备请求;R:设备上报)4.开发调试蓝牙交互打包BleHelper工具类,通过BLE扫描广播提供的开放能力,可以获取周边设备,启动或停止BLE扫描广播。4.1BLE扫描MyBleCentralManagerCallback继承BleCentralManagerCallback类实现scanResultEvent和scanFailedEvent回调函数接收扫描结果。BleCentralManager(BleCentralManagerCallbackcallback)接口获取中心设备管理对象。调用startScan()扫描蓝牙设备。/***扫描设备*@paramfilters设备过滤器*@since2021-10-09*/publicvoidstartScan(Listfilters){centralManager=newBleCentralManager(context,newMyBleCentralManagerCallback());centralManager.startScan(filters);}/***扫描设备回调**@since2021-10-09*/privateclassMyBleCentralManagerCallbackimplementsBleCentralManagerCallback{//扫描结果回调@OverridepublicvoidscanResultEvent(BleScanResultbleScanResult){if(mBleManagerCallback!=null){mBleManagerCallback.scanResult/ResultcanCallback(广播获取)ServiceuuidsList数据中的uuids=bleScanResult.getServiceUuids();for(UUIDuuid:uuids){if(SERVICE_UUID.equals(uuid.toString())){peripheralDevice=bleScanResult.getPeripheralDevice();intlength=peripheralDevice.toString()。length();StringdeviceId=peripheralDevice.toString().substring(length-CUT_LENGTH,length);stopScan();bleConnect();}}}//扫描失败回调@OverridepublicvoidscanFailedEvent(inevent){HiLog.debug(loglabel,"扫描失败scanFailedEvent()");}//组扫描成功回调@OverridepublicvoidgroupScanResultsEvent(Listlist){//使用组扫描时在这里处理扫描结果}}4.2建立连接扫描成功,匹配服务UUIDFFB0,调用bleConnect()连接开发板蓝牙触发connectionStateChangedEvent(intconnectionState)callback,connectionState=2连接成功,然后调用discoverServices()接口发现服务。在回调servicesDiscoveredEvent(intstatus)中获取外围设备支持的服务和特征值,然后才能调用读写方法读取或写入对应的特征值数据。在characteristicChangedEvent(GattCharacteristiccharacteristic)特性变化的回调中,分析传感器上报的数据,校验等,具体的数据解析逻辑在ProtocolEntity中的parseCharacteristic(StringhexStr)方法中。/***连接到BLE外围设备**@since2021-10-09*/publicvoidbleConnect(){peripheralDevice.connect(false,newBlePeripheralCallback(){//回调在外围设备上发现的服务@OverridepublicvoidservicesDiscoveredEvent(intstatus){super.servicesDiscoveredEvent(status);if(status==BlePeripheralDevice.OPERATION_SUCC){HiLog.debug(loglabel,"servicesDiscoveredEvent()foundsuccessfully");for(GattServiceservice:peripheralDevice.getServices()){checkGattCharacteristic(service);}if(mBleManagerCallback!=null){mBleManagerCallback.connectCallback(status);}}}privatevoidcheckGattCharacteristic(GattServiceservice){for(GattCharacteristictmpChara:service.getCharacteristics()){if(tmpChara.getUuid().equals(UUID.fromString(NOTIFY_CHARACTER)_UUID)){//启用特征通知peripheralDevice.setNotifyCharacteristic(tmpChara,true);}if(tmpChara.getUuid().equals(UUID.fromString(WRITE_CHARACTER_UUID))){//获取GattCharacteristicwriteCharacteristic=tmpChara;}}}//连接状态通道ange回调@OverridepublicvoidconnectionStateChangeEvent(intconnectionState){super.connectionStateChangeEvent(connectionState);if(connectionState==ProfileBase.STATE_CONNECTED&&!isConnected){HiLog.debug(loglabel,"连接成功connectionStateChangeEvent()connectionState:"+connectionState);isConnected=true;//连接成功,找到GATT在周边设备Service上,部分手机发现服务失败,需要延迟调用discoverServices()peripheralDevice.discoverServices();}}//特性改变的回调@OverridepublicvoidcharacteristicChangedEvent(GattCharacteristiccharacteristic){super.characteristicChangedEvent(characteristic);byte[]value=characteristic.getValue();if(value==null)return;StringtoHexStr=DataUtils.toHex(value);booleanisVerify=BleHelper.verifyProtocol(toHexStr);//验证if(isVerify){if(protocolEntity==null){protocolEntity=newProtocolEntity();}protocolEntity.parseCharacteristic(toHexStr);如果(mBleManagerCallback!=null){mBleManagerCallback.characteristicChangedCallback(protocolEntity,toHexStr);}}}});}4.3预报警阈值下发设置火焰报警距离阈值,tagId为0002,当火焰传感器检测到火焰且低于本设置设定的阈值时,设备会上报预警使用通过发现服务servicesDiscoveredEvent()回调获得的writeCharacteristic特性写入数据。数据传递格式按照3.3数据透传协议。/***主动获取标签设备数据,通过Write(消息类型0x01)、Notify接收数据*/publicvoidreadInitiativeByTags(ListtagIds){Stringhex=getTagsCommandHexStr(tagIds);bleManagerWrite(hex);}/***WriteTag设备数据,通过Write(messagetype0x01),Notify接收数据*/publicvoidwriteBleByTag(StringtagId,Stringvalue){Stringhex=getTagCommandHexStr(tagId,Integer.parseInt(value));bleManagerWrite(hex);}privatevoidbleManagerWrite(Stringhex){if(peripheralDevice==null){return;}writeCharacteristic.setValue(hex.getBytes(StandardCharsets.UTF_8));peripheralDevice.writeCharacteristic(writeCharacteristic);}/***写命令获取所有Tagdata**@paramtagIdstagset*/privateStringgetTagsCommandHexStr(ListtagIds){try{StringBuildersb=newStringBuilder();Stringbyte1=PROTOCOL_ID;//串口协议IDStringbyte2=PROTOCOL_VERSION;Stringbyte3=TYPE_OBTAIN;intdataLen=8*tagIds.size();Stringbyte4=DataUtils.encodeHex(dataLen,4);StringbyteTagLen=DataUtils.encodeHex(4,4);StringbyteTagValue="00000000";StringBuildersbTag=newStringBuilder();for(Strigit:tagIds){sbTag.append(it).append(byteTagLen).append(byteTagValue);}sb.append(byte1).append(byte2).append(byte3).append(byte4).append(sbTag);StringhexStrSum=DataUtils.makeChecksum(sb.toString());intprotocolVerify=DataUtils.decodeHEX(hexStrSum)%256;StringbyteLast=DataUtils.encodeHex(protocolVerify);sb.append(byteLast);returnsb.toString();}catch(异常){e.printStackTrace();}return"";}/***获取单个Tag数据的写指令**@paramtagId0001*@Paramvalue写入值*/privateStringgetTagCommandHexStr(StringtagId,intvalue){try{StringBuildersb=newStringBuilder();Stringbyte1=PROTOCOL_ID;//串行协议标准Stringbyte2=PROTOCOL_VERSION;Stringbyte3=TYPE_ISSUED;intdataLen=8;Stringbyte4=DataUtils.encodeHex(dataLen,4);StringbyteTagId=tagId;StringbyteTagLen=DataUtils.encodeHex(4,4);StringbyteTag=DataUtils.encodeHex(value,8);sb.append(byte1).append(byte2).append(byte3).append(byte4).append(byteTagId).append(byteTagLen).append(byteTagValue);StringhexStrSum=DataUtils.makeChecksum(sb.toString());intprotocolVerify=DataUtils.decodeHEX(hexStrSum)%256;StringbyteLast=DataUtils.encodeHex(protocolVerify);sb.append(byteLast);returnsb.toString();}catch(Exceptione){e.printStackTrace();}return"";}4.4火焰距离上报火焰距离上报,通知应用,启动预警通过3.3数据透传协议,分析设备上报的火焰距离。/***协议校验(从协议标识的第一段累加到协议内容的最后一个字节,然后取256的余数)**@paramhexStrA55A01000008000200040000008C*/publicstaticbooleanverifyProtocol(StringhexStr){if(hexStr.isEmpty())返回假;StringcheckHex=hexStr.substring(0,hexStr.lastIndexOf(""));StringlastHex=hexStr.substring(hexStr.lastIndexOf("")+1);StringhexStrSum=DataUtils.makeChecksum(checkHex);returnDataUtils.decodeHEX(hexStrSum)%256==DataUtils.decodeHEX(lastHex);}/***根据串口协议分析*/publicbooleanparseCharacteristic(StringhexStr){try{String[]hexs=hexStr.split("");version=DataUtils.decodeHEX(hexs[2]);messageType=DataUtils.decodeHEX(hexs[3]);dataLen=DataUtils.decodeHEX(hexs[4]+hexs[5]);for(inti=0;i