连接蓝牙模块后丢失数据

Posted

技术标签:

【中文标题】连接蓝牙模块后丢失数据【英文标题】:Losing data after connecting the bluetooth module 【发布时间】:2020-12-27 03:55:12 【问题描述】:

目标

我正在尝试在连接后从蓝牙设备返回数据,因为要使用读写功能,需要一些数据。 示例数据name, overflowServiceUUIDs, solicitedServiceUUIDs, mtu, rssi... 和许多其他数据。因为如果我想读或写,我需要一些属性。我正在使用库react-native-ble-plx

发生了什么?

设备连接后,我丢失了一些值。

重要

type DeviceState = 
  connected: boolean;
  services: Service[];
  device: Device | null;
  characteristics: Record<string, Characteristic[]>;
;

const INITIAL_DEVICE_STATE = 
  connected: false,
  services: [],
  device: null,
  characteristics: ,
;
const [adapterState, setAdapterState] = useState(false);
const [bleDevices, setBleDevices] = useState<Device[]>([]);
const [isScanning, setIsScanning] = useState(false);
const [connectedDevice, setConnectedDevice] = useState<DeviceState>(
    INITIAL_DEVICE_STATE,
);

# The state isScaning is used to be if we are scanning devices.
# The connectedDevice state will be the connected device.

序列函数

toggleScanDevices()

会将所有设备推送到bleDevices 状态。

  const toggleScanDevices = () => 
    setIsScanning(true);
    setBleDevices([]);

    bleManager.startDeviceScan(null, , (bleError, device) => 
      if (device && _.findIndex(bleDevices,  id: device.id ) < 0) 
        bleDevices.push(device);
        setBleDevices(bleDevices);
      
    );

    setTimeout(() => 
      setIsScanning(false);
      bleManager.stopDeviceScan();
    , 5000);
  ;

toggleConnectDevice(device.name)

  const toggleConnectDevice = (name: string) => async () => 
    if (!connectedDevice.device) 
      await connectDevice(name);
     else 
      const  device  = connectedDevice;

      if (!device) return;

      await device.cancelConnection();

      if (!(await device.isConnected())) 
        setConnectedDevice(INITIAL_DEVICE_STATE);
      
    
  ;

连接设备(名称)

  const connectDevice = async (name: string) => 
    let device = findDeviceWhereNameContains(name);

    if (device === null) 
      setConnectedDevice(INITIAL_DEVICE_STATE);
      return false;
    

    let isConnected = await device.isConnected();

    if (!isConnected) 
      /* Testar aqui */
      device = await bleManager.connectToDevice(device.id);
      isConnected = await device.isConnected();
    
    device = await device.discoverAllServicesAndCharacteristics();

    device.onDisconnected((error, device) => 
      setConnectedDevice(INITIAL_DEVICE_STATE);
    );

    const services = await device.services();
    const characteristics: Record<string, Characteristic[]> = ;
    const descriptors = ;

    _.forEach(services, async service => 
      const deviceCharacteristics = await device?.characteristicsForService(
        service.uuid,
      );
      characteristics[service.uuid] = deviceCharacteristics || [];
    );

    setConnectedDevice(state => (
      ...state,
      services,
      characteristics,
      device,
    ));

    const newDevice =  ...connectedDevice, device ;
    setConnectedDevice(newDevice);
    console.log('não atualizado', connectedDevice);
    console.log('novo valor', newDevice);
  ;

findDeviceWhereNameContains(名称)

  const findDeviceWhereNameContains = (name: string) => 
    const device = bleDevices.find(item => String(item.name).includes(name));
    if (device !== undefined) 
      return device;
    
    return null;
  ;

connectDevice 函数中,我有一个let device,它接收关于findDeviceWhereNameContains 的值,如果我记录这个变量device,我会收到许多非常重要的数据,但我还没有连接。因此,当我在这里验证if (!isConnected) 时,我将连接,然后,如果我再次登录device 时,我会丢失一些值。

连接前的日志

连接后的日志

Device overflowServiceUUIDs: null, solicitedServiceUUIDs: null, localName: null, isConnectable: null, txPowerLevel: null, …
overflowServiceUUIDs: null
solicitedServiceUUIDs: null
localName: null
isConnectable: null
txPowerLevel: null
serviceUUIDs: null
serviceData: null
mtu: null
name: "MLT-BT05"
manufacturerData: null
rssi: null
id: "88:25:83:F0:30:BC"

【问题讨论】:

好吧,我想如果你用async-await重写上面的代码,问题就解决了。一般注意不要混用同步和异步。 @Eldar 我试过了,但没用。 @VagnerWentz,如果你使用的是旧版本的android,有一个known bug where The service discovery is resolved with an empty array of services without any error(第三注) @EliasSchablowski 嗨,埃利亚斯,你好吗?我看到我用的手机,安卓版本是6.0.1,你觉得有问题吗? 我认为你不应该将 .then()asyncawait 语法混用,尝试将它们转换为 await,这样你就可以通过更清晰的代码获得更好的视角 【参考方案1】:

检查您正在使用的库,它来自调用本机模块时得到的响应creates another device object,可能是这个新对象在这些字段上带有空值,replaces 是您需要的值。因为它就像现在一样工作,所以你可以在它们被删除之前将这些值 copy 到另一个对象

import pick from 'lodash/pick';

const connectDevice = async (name: string) => 
    let device = findDeviceWhereNameContains(name);
    // according to the screenshot, the object still have the
    // information you want at this point
    
    // taking advantage taht you have lodash already you can use pick
    const valuesYouNeed = pick(device, ['serviceUUIDs', ...]);

    ...

    // here you merge them back with other device's attr that are present at this point
    const newDevice =  ...pick(device, ['connected', ...]), ...valuesYouNeed ;
    setConnectedDevice(newDevice);
    console.log('não atualizado', connectedDevice);
    console.log('novo valor', newDevice);
  ;

但您担心它们不会再次被替换。

如果您认为这是 react-native-ble-plx 的错误行为,您可以打开 PR 并在 Device 构造函数中进行更改以避免这种情况发生。

由于您使用的是打字稿,因此您会对打字有一些抱怨,您可以从 react-native-ble-plx 设备类型和 pick 创建一个类型,只使用它的属性部分来省略方法并避免在您的状态。

import  Device  from 'react-native-ble-plx`;

type DeviceState = Pick<
    Device,
    | 'id'
    | 'name'
    | 'rssi'
    | 'mtu'
    | 'manufacturerData'
    | 'serviceData'
    | 'serviceUUIDs'
    | 'localName'
    | 'txPowerLevel'
    | 'solicitedServiceUUIDs'
    | 'isConnectable'
    | 'overflowServiceUUIDs'
  >

【讨论】:

嘿,您是否编辑了您对我所做的新版本的评论? @VagnerWentz 我编辑的是我的答案,之前我只是用awaits 重构了你的代码,现在我建议在它们丢失之前存储这些值 好的,我会测试,如果是对的,我会给你赏金 你认为我需要把你的例子放在我的代码中吗? 有个疑问,你说的那部分create another devices是什么意思?

以上是关于连接蓝牙模块后丢失数据的主要内容,如果未能解决你的问题,请参考以下文章

51单片机与蓝牙模块连接时的RXD与TXD要串上电阻么?

如何让手机APP接收蓝牙模块发送的数据并显示出来

简单介绍蓝牙无线模块和手机进行的车数据交互技巧

hc-05蓝牙模块6条引脚与单片机怎样连接

HC-06蓝牙模块的使用

如何让手机APP接收蓝牙模块发送的数据并显示出来