首页 > 解决方案 > 使用 protobufjs 和离子电容器 BLE 插件写入 ESP32 GATT 特性时出现写入特性失败错误

问题描述

从 Angular(使用 Ionic)构建 Android 应用程序以扫描 BLE 设备(ESP32 芯片)并写入其 GATT 特性。使用 Capacitor BLE 插件进行 BLE 通信和 protobufjs 创建消息(因为 ESP32 代码使用 Google 的 Protocol Buffer 机制来接受消息)。应用程序部署在三星 Galaxy Tab A7 上以部署应用程序。执行 BLEClient.write 时出现“写入特征失败”错误消息,并且无法理解失败的原因。这是我的代码(用户单击按钮时调用的 getBLE()):

import { load } from '../../../node_modules/protobufjs';
import { BleClient } from '@capacitor-community/bluetooth-le';

export class SetupPage implements OnInit {

  async getBLE(){
    try {
      let wifiid = 'wifiSSID';
      let password = 'somePassword';
      await load ('../../assets/wifi_config.proto')
      .then((root) => {
        var wifi_config_message = root.lookupType("wifi_config_package.CmdSetConfig");
        let message = wifi_config_message.create({
          ssid: wifiid,
          passphrase: password
        });
        let buffer1 = wifi_config_message.encode(message).finish();
        return buffer1;
      })
      .then(async buffer1 => {
        await BleClient.initialize();
        let connectedDevice = await BleClient.requestDevice();
        await BleClient.connect(connectedDevice.deviceId);
        let bufferView = await new DataView(buffer1.buffer);
        const result = await BleClient.write(connectedDevice.deviceId, '021a9004-0382-4aea-bff4-6b3f1c5adfb4', '021aff52-0382-4aea-bff4-6b3f1c5adfb4',bufferView);
      });
    }
    catch(error) {
      console.log('bluetooth error is: ', error);
    }
  }
}

这是 wifi_config.proto 文件的样子:

package wifi_config_package;
syntax = "proto3";

import "constants.proto";
import "wifi_constants.proto";

message CmdGetStatus {}

message RespGetStatus {
    Status status = 1;
    WifiStationState sta_state = 2;
    oneof state {
        WifiConnectFailedReason fail_reason = 10;
        WifiConnectedState connected = 11;
    }
}

message CmdSetConfig {
    string ssid = 1;
    string passphrase = 2;
    bytes bssid = 3;
    int32 channel = 4;
}

message RespSetConfig {
    Status status = 1;
}

message CmdApplyConfig {}

message RespApplyConfig {
    Status status = 1;
}

enum WiFiConfigMsgType {
    TypeCmdGetStatus = 0;
    TypeRespGetStatus = 1;
    TypeCmdSetConfig = 2;
    TypeRespSetConfig = 3;
    TypeCmdApplyConfig = 4;
    TypeRespApplyConfig = 5;
}

message WiFiConfigPayload {
    WiFiConfigMsgType msg = 1;
    oneof payload {
        CmdGetStatus cmd_get_status = 10;
        RespGetStatus resp_get_status = 11;
        CmdSetConfig cmd_set_config = 12;
        RespSetConfig resp_set_config = 13;
        CmdApplyConfig cmd_apply_config = 14;
        RespApplyConfig resp_apply_config = 15;
    }
}

我做错了什么?实现相同目标的任何替代方法(通过写入 GATT 特性通过 BLE 将数据发送到 ESP32)?我不想求助于原生 Android 应用程序开发,因为我没有这方面的经验,而且截止日期很短。此外,对 Protocol Buffer 机制不太满意,因此需要一些指导。

标签: ionic-frameworkbluetooth-lowenergyprotocol-bufferscapacitorprotobuf.js

解决方案


通过使用 Google 的 javascript 协议缓冲区代码解决了这个问题。无法弄清楚如何使用 protobufjs.create 创建正确的消息格式,尤其是因为消息需要模仿嵌套对象。这是对我有用的代码:

import * as goog from 'google-protobuf';
export class SetupPage implements OnInit {

  messages = require('../../assets/proto-js/wifi_config_pb.js');
  connectedDevice: BleDevice;
  bleScan: any;
  wifiSSID: Promise<any>;
  scanResults: Promise<[]>;
  wifiCredentials: string;
  uint8String: Uint8Array;
  buffer: Uint8Array;

  ngOnInit() {
    async getBLE(){
      await BleClient.initialize();
      var cmdSetMessage = new this.messages.CmdSetConfig();
      var wifiConfigPayloadMessage = new this.messages.WiFiConfigPayload;
      message.setSsid('wifiid');
      message.setPassphrase('password');
      wifiConfigPayloadMessage.setCmdSetConfig(cmdSetMessage);
      wifiConfigPayloadMessage.setMsg(2);
      let bytesOfStuff = await wifiConfigPayloadMessage.serializeBinary();
      this.connectedDevice = await BleClient.requestDevice();
      await BleClient.connect(this.connectedDevice.deviceId);
      BleClient.writeWithoutResponse(this.connectedDevice.deviceId, '021a9004-0382- 
      4aea-bff4-6b3f1c5adfb4', '021aff52-0382-4aea-bff4-6b3f1c5adfb4', 
      bytesOfStuff)
  }
}

在此代码可以运行之前,您需要从 npm 或其他包安装程序和 protoc 或其他编译器安装 google-protobuf,以便为每个 proto 文件生成 pb.js 文件(因为我正在使用 javascript)。在本例中,proto 文件名为 wifi_config.proto,对应的 pb.js 文件(通过运行 protoc 创建)名为 wifi_config_pb.js。

用于创建要传输的数据的函数在 pb.js 文件中定义,并对应于 proto 文件中定义的对象。如果您对这种机制的工作原理没有很好的理解,以下参考资料将有很大帮助:

https://developers.google.com/protocol-buffers/docs/proto3(谷歌协议缓冲区教程)

Ionic 中的协议缓冲区(堆栈问题)

如果您有任何问题,请 PM 我。


推荐阅读