HarmonyOS基于LYEVK-3861開(kāi)發(fā)火焰報(bào)警系統(tǒng)
想了解更多內(nèi)容,請(qǐng)?jiān)L問(wèn):
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
前言
在各種災(zāi)害中,火災(zāi)是最經(jīng)常、最普遍地威脅公眾安全和社會(huì)發(fā)展的主要災(zāi)害之一?;鸾o人類(lèi)帶來(lái)文明進(jìn)步、光明和溫暖。但是,有時(shí)它是人類(lèi)的朋友,有時(shí)是人類(lèi)的敵人。失去控制的火,就會(huì)給人類(lèi)造成災(zāi)難。說(shuō)到火災(zāi)的控制,一套火焰感應(yīng)報(bào)警系統(tǒng)就有其價(jià)值了。那我們?nèi)绾稳z測(cè)火焰呢?
本文內(nèi)容主要講述基于LYEVK-3861物聯(lián)網(wǎng)開(kāi)發(fā)板套件的火焰?zhèn)鞲衅?,開(kāi)發(fā)一個(gè)具有火焰感應(yīng)報(bào)警功能的HarmonyOS應(yīng)用,主要實(shí)現(xiàn)藍(lán)牙設(shè)備掃描,連接,檢測(cè)火焰,設(shè)置報(bào)警閾值。
1.效果演示

2.環(huán)境準(zhǔn)備
本貼不對(duì)實(shí)驗(yàn)環(huán)境搭建做詳細(xì)說(shuō)明。具體準(zhǔn)備實(shí)驗(yàn)環(huán)境請(qǐng)參考:
- 《HarmonyOS 官方文檔》
- LYEVK-3861 物聯(lián)網(wǎng)開(kāi)發(fā)板套件
3.藍(lán)牙通信說(shuō)明
3.1 藍(lán)牙通信協(xié)議:
3.2 藍(lán)牙通信流程:

3.3 數(shù)據(jù)透?jìng)鲄f(xié)議:
3.3.1 串口協(xié)議:
3.3.2 數(shù)據(jù)協(xié)議:
(permission P:APP下發(fā);G:設(shè)備請(qǐng)求;R:設(shè)備上報(bào))
4.開(kāi)發(fā)調(diào)試
藍(lán)牙交互封裝BleHelper工具類(lèi),通過(guò)BLE掃描和廣播提供的開(kāi)放能力,可以根據(jù)指定狀態(tài)獲取外圍設(shè)備、啟動(dòng)或停止BLE掃描、廣播。
4.1 進(jìn)行BLE掃描
- MyBleCentralManagerCallback繼承BleCentralManagerCallback類(lèi)實(shí)現(xiàn)scanResultEvent和scanFailedEvent回調(diào)函數(shù),用于接收掃描結(jié)果。
- BleCentralManager(BleCentralManagerCallback callback)接口獲取中心設(shè)備管理對(duì)象。
- 調(diào)用startScan()掃描藍(lán)牙設(shè)備。
- /**
- * 掃描設(shè)備
- * @param filters 設(shè)備過(guò)濾器
- * @since 2021-10-09
- */
- public void startScan(List<BleScanFilter> filters) {
- centralManager = new BleCentralManager(context, new MyBleCentralManagerCallback());
- centralManager.startScan(filters);
- }
- /**
- * 掃描設(shè)備回調(diào)
- *
- * @since 2021-10-09
- */
- private class MyBleCentralManagerCallback implements BleCentralManagerCallback {
- // 掃描結(jié)果的回調(diào)
- @Override
- public void scanResultEvent(BleScanResult bleScanResult) {
- if (mBleManagerCallback != null) {
- mBleManagerCallback.scanResultCallback(bleScanResult);
- }
- // 獲取廣播數(shù)據(jù)中的服務(wù)uuids
- List<UUID> uuids = bleScanResult.getServiceUuids();
- for (UUID uuid : uuids) {
- if (SERVICE_UUID.equals(uuid.toString())) {
- peripheralDevice = bleScanResult.getPeripheralDevice();
- int length = peripheralDevice.toString().length();
- String deviceId = peripheralDevice.toString().substring(length - CUT_LENGTH, length);
- stopScan();
- bleConnect();
- }
- }
- }
- // 掃描失敗回調(diào)
- @Override
- public void scanFailedEvent(int event) {
- HiLog.debug(loglabel, "掃描失敗 scanFailedEvent()");
- }
- // 組掃描成功回調(diào)
- @Override
- public void groupScanResultsEvent(List<BleScanResult> list) {
- // 使用組掃描時(shí)在此對(duì)掃描結(jié)果進(jìn)行處理
- }
- }
4.2 建立連接
- 掃描成功,匹配服務(wù)UUID FFB0,調(diào)用bleConnect()連接開(kāi)發(fā)板藍(lán)牙。
- 觸發(fā)connectionStateChangedEvent(int connectionState)回調(diào),connectionState=2連接成功,然后調(diào)用discoverServices()接口發(fā)現(xiàn)服務(wù)。
- 在回調(diào)servicesDiscoveredEvent(int status)中獲取外圍設(shè)備支持的服務(wù)和特征值,此時(shí)才能調(diào)用read和write方法讀取或者寫(xiě)入對(duì)應(yīng)特征值數(shù)據(jù)。
- characteristicChangedEvent(GattCharacteristic characteristic)特征變更的回調(diào)中,解析傳感器上報(bào)數(shù)據(jù)、校驗(yàn)等。具體數(shù)據(jù)解析邏輯在ProtocolEntity中parseCharacteristic(String hexStr)方法。
- /**
- * 連接到BLE外圍設(shè)備
- *
- * @since 2021-10-09
- */
- public void bleConnect() {
- peripheralDevice.connect(false, new BlePeripheralCallback() {
- // 在外圍設(shè)備上發(fā)現(xiàn)服務(wù)的回調(diào)
- @Override
- public void servicesDiscoveredEvent(int status) {
- super.servicesDiscoveredEvent(status);
- if (status == BlePeripheralDevice.OPERATION_SUCC) {
- HiLog.debug(loglabel, "發(fā)現(xiàn)服務(wù)成功 servicesDiscoveredEvent()");
- for (GattService service : peripheralDevice.getServices()) {
- checkGattCharacteristic(service);
- }
- if (mBleManagerCallback != null) {
- mBleManagerCallback.connectCallback(status);
- }
- }
- }
- private void checkGattCharacteristic(GattService service) {
- for (GattCharacteristic tmpChara : service.getCharacteristics()) {
- if (tmpChara.getUuid().equals(UUID.fromString(NOTIFY_CHARACTER_UUID))) {
- // 啟用特征通知
- peripheralDevice.setNotifyCharacteristic(tmpChara, true);
- }
- if (tmpChara.getUuid().equals(UUID.fromString(WRITE_CHARACTER_UUID))) {
- // 獲取GattCharacteristic
- writeCharacteristic = tmpChara;
- }
- }
- }
- // 連接狀態(tài)變更的回調(diào)
- @Override
- public void connectionStateChangeEvent(int connectionState) {
- super.connectionStateChangeEvent(connectionState);
- if (connectionState == ProfileBase.STATE_CONNECTED && !isConnected) {
- HiLog.debug(loglabel, "連接成功 connectionStateChangeEvent() connectionState:" + connectionState);
- isConnected = true;
- // 連接成功在外圍設(shè)備上發(fā)現(xiàn)GATT服務(wù),部分手機(jī)發(fā)現(xiàn)服務(wù)失敗,需要延遲調(diào)用discoverServices()
- peripheralDevice.discoverServices();
- }
- }
- // 特征變更的回調(diào)
- @Override
- public void characteristicChangedEvent(GattCharacteristic characteristic) {
- super.characteristicChangedEvent(characteristic);
- byte[] value = characteristic.getValue();
- if (value == null) return;
- String toHexStr = DataUtils.toHex(value);
- boolean isVerify = BleHelper.verifyProtocol(toHexStr);//校驗(yàn)
- if (isVerify) {
- if (protocolEntity == null) {
- protocolEntity = new ProtocolEntity();
- }
- protocolEntity.parseCharacteristic(toHexStr);
- if (mBleManagerCallback != null) {
- mBleManagerCallback.characteristicChangedCallback(protocolEntity, toHexStr);
- }
- }
- }
- });
- }
4.3 預(yù)警閾值下發(fā)
- 設(shè)置火焰報(bào)警距離閾值,tagId為0002,當(dāng)火焰?zhèn)鞲衅靼l(fā)現(xiàn)火焰,并小于此設(shè)置的閾值時(shí),設(shè)備上報(bào)預(yù)警。
- 通過(guò)發(fā)現(xiàn)服務(wù)servicesDiscoveredEvent()回調(diào)獲取的writeCharacteristic特征,寫(xiě)入數(shù)據(jù)。數(shù)據(jù)下發(fā)格式按照3.3數(shù)據(jù)透?jìng)鲄f(xié)議。
- /**
- * 主動(dòng)去獲取所Tag設(shè)備數(shù)據(jù),通過(guò)Write(消息類(lèi)型0x01), Notify接收數(shù)據(jù)
- */
- public void readInitiativeByTags(List<String> tagIds) {
- String hex = getTagsCommandHexStr(tagIds);
- bleManagerWrite(hex);
- }
- /**
- * 寫(xiě)Tag設(shè)備數(shù)據(jù),通過(guò)Write(消息類(lèi)型0x01), Notify接收數(shù)據(jù)
- */
- public void writeBleByTag(String tagId, String value) {
- String hex = getTagCommandHexStr(tagId, Integer.parseInt(value));
- bleManagerWrite(hex);
- }
- private void bleManagerWrite(String hex) {
- if (peripheralDevice == null) {
- return;
- }
- writeCharacteristic.setValue(hex.getBytes(StandardCharsets.UTF_8));
- peripheralDevice.writeCharacteristic(writeCharacteristic);
- }
- /**
- * 獲取所有Tag數(shù)據(jù)的Write指令
- *
- * @param tagIds tag集
- */
- private String getTagsCommandHexStr(List<String> tagIds) {
- try {
- StringBuilder sb = new StringBuilder();
- String byte1 = PROTOCOL_ID; //串口協(xié)議標(biāo)識(shí)
- String byte2 = PROTOCOL_VERSION;
- String byte3 = TYPE_OBTAIN;
- int dataLen = 8 * tagIds.size();
- String byte4 = DataUtils.encodeHex(dataLen, 4);
- String byteTagLen = DataUtils.encodeHex(4, 4);
- String byteTagValue = "00000000";
- StringBuilder sbTag = new StringBuilder();
- for (String it : tagIds) {
- sbTag.append(it).append(byteTagLen).append(byteTagValue);
- }
- sb.append(byte1).append(byte2).append(byte3).append(byte4).append(sbTag);
- String hexStrSum = DataUtils.makeChecksum(sb.toString());
- int protocolVerify = DataUtils.decodeHEX(hexStrSum) % 256;
- String byteLast = DataUtils.encodeHex(protocolVerify);
- sb.append(byteLast);
- return sb.toString();
- } catch (Exception e) {
- e.printStackTrace();
- }
- return "";
- }
- /**
- * 獲取單個(gè)Tag數(shù)據(jù)的Write指令
- *
- * @param tagId 0001
- * @Param value 寫(xiě)入值
- */
- private String getTagCommandHexStr(String tagId, int value) {
- try {
- StringBuilder sb = new StringBuilder();
- String byte1 = PROTOCOL_ID; //串口協(xié)議標(biāo)識(shí)
- String byte2 = PROTOCOL_VERSION;
- String byte3 = TYPE_ISSUED;
- int dataLen = 8;
- String byte4 = DataUtils.encodeHex(dataLen, 4);
- String byteTagId = tagId;
- String byteTagLen = DataUtils.encodeHex(4, 4);
- String byteTagValue = DataUtils.encodeHex(value, 8);
- sb.append(byte1).append(byte2).append(byte3).append(byte4)
- .append(byteTagId).append(byteTagLen).append(byteTagValue);
- String hexStrSum = DataUtils.makeChecksum(sb.toString());
- int protocolVerify = DataUtils.decodeHEX(hexStrSum) % 256;
- String byteLast = DataUtils.encodeHex(protocolVerify);
- sb.append(byteLast);
- return sb.toString();
- } catch (Exception e) {
- e.printStackTrace();
- }
- return "";
- }
4.4 火焰距離上報(bào)
- 火焰距離上報(bào),通知應(yīng)用,開(kāi)始預(yù)警。
- 通過(guò)3.3數(shù)據(jù)透?jìng)鲄f(xié)議,解析設(shè)備上報(bào)的火焰距離。
- /**
- * 協(xié)議校驗(yàn) (從協(xié)議標(biāo)識(shí)首節(jié)至協(xié)議內(nèi)容尾字節(jié)求累加和后再對(duì) 256 取余)
- *
- * @param hexStr 帶空格的 A5 5A 01 00 00 08 00 02 00 04 00 00 00 8C
- */
- public static boolean verifyProtocol(String hexStr) {
- if (hexStr.isEmpty()) return false;
- String checkHex = hexStr.substring(0, hexStr.lastIndexOf(" "));
- String lastHex = hexStr.substring(hexStr.lastIndexOf(" ") + 1);
- String hexStrSum = DataUtils.makeChecksum(checkHex);
- return DataUtils.decodeHEX(hexStrSum) % 256 == DataUtils.decodeHEX(lastHex);
- }
- /**
- * 根據(jù)串口協(xié)議解析
- */
- public boolean parseCharacteristic(String hexStr) {
- try {
- String[] hexs = hexStr.split(" ");
- version = DataUtils.decodeHEX(hexs[2]);
- messageType = DataUtils.decodeHEX(hexs[3]);
- dataLen = DataUtils.decodeHEX(hexs[4] + hexs[5]);
- for (int i = 0; i < dataLen / 8; i++) {
- int startIndex = 6 + (i * 8);
- DeviceData deviceData = new DeviceData();
- deviceData.tagId = DataUtils.decodeHEX(hexs[startIndex] + hexs[startIndex + 1]);
- deviceData.len = DataUtils.decodeHEX(hexs[startIndex + 2] + hexs[startIndex + 3]);
- deviceData.value = DataUtils.decodeHEX(hexs[startIndex + 4] + hexs[startIndex + 5] +
- hexs[startIndex + 6] + hexs[startIndex + 7]);
- deviceListMap.put(deviceData.tagId, deviceData);
- }
- protocolVerify = DataUtils.decodeHEX(hexs[6 + dataLen]);
- } catch (Exception e) {
- e.printStackTrace();
- return false;
- }
- return true;
- }
5.結(jié)語(yǔ)
以上就是LYEVK-3861物聯(lián)網(wǎng)開(kāi)發(fā)板火焰?zhèn)鞲衅鞯念A(yù)警功能,和應(yīng)用程序交互的一個(gè)相對(duì)簡(jiǎn)單的流程。場(chǎng)景的交互還有很多種,比如在此基礎(chǔ)上搭建遠(yuǎn)程云端系統(tǒng),實(shí)現(xiàn)遠(yuǎn)程火焰監(jiān)控實(shí)時(shí)預(yù)警。有興趣的伙伴也可以根據(jù)開(kāi)發(fā)板其他傳感器組合成不同的智能場(chǎng)景。
想了解更多內(nèi)容,請(qǐng)?jiān)L問(wèn):
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)