连接蓝牙模块后数据丢失

Vag*_*ntz 11 bluetooth bluetooth-lowenergy typescript react-native react-native-ble-plx

客观的

我试图在连接后从蓝牙设备返回数据,因为要使用读写功能,需要一些数据。示例数据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: {},
};
Run Code Online (Sandbox Code Playgroud)
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.
Run Code Online (Sandbox Code Playgroud)

序列函数

切换扫描设备()

将所有设备推送到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);
  };
Run Code Online (Sandbox Code Playgroud)

切换连接设备(设备名称)

  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);
      }
    }
  };
Run Code Online (Sandbox Code Playgroud)

连接设备(名称)

  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);
  };
Run Code Online (Sandbox Code Playgroud)

findDeviceWhereNameContains(name)

  const findDeviceWhereNameContains = (name: string) => {
    const device = bleDevices.find(item => String(item.name).includes(name));
    if (device !== undefined) {
      return device;
    }
    return null;
  };
Run Code Online (Sandbox Code Playgroud)

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"
Run Code Online (Sandbox Code Playgroud)

die*_*edu 2

检查您正在使用的库,它会根据调用本机模块时获得的响应创建另一个设备对象,可能是这个新对象在这些字段上带有空值并替换您需要的值。因为它就像现在一样工作,您可以在这些值被删除之前将它们复制到另一个对象

\n
import pick from \'lodash/pick\';\n\nconst connectDevice = async (name: string) => {\n    let device = findDeviceWhereNameContains(name);\n    // according to the screenshot, the object still have the\n    // information you want at this point\n    \n    // taking advantage taht you have lodash already you can use pick\n    const valuesYouNeed = pick(device, [\'serviceUUIDs\', ...]);\n\n    ...\n\n    // here you merge them back with other device\'s attr that are present at this point\n    const newDevice = { ...pick(device, [\'connected\', ...]), ...valuesYouNeed };\n    setConnectedDevice(newDevice);\n    console.log(\'n\xc3\xa3o atualizado\', connectedDevice);\n    console.log(\'novo valor\', newDevice);\n  };\n
Run Code Online (Sandbox Code Playgroud)\n

但你要小心他们不会再次被替换。

\n

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

\n

由于您使用的是打字稿,您会对打字有一些抱怨,您可以从react-native-ble-plx设备类型创建一个类型,并仅选择其中的属性部分以省略方法并避免在您的状态中存储复杂的对象。

\n
import { Device } from \'react-native-ble-plx`;\n\ntype DeviceState = Pick<\n    Device,\n    | \'id\'\n    | \'name\'\n    | \'rssi\'\n    | \'mtu\'\n    | \'manufacturerData\'\n    | \'serviceData\'\n    | \'serviceUUIDs\'\n    | \'localName\'\n    | \'txPowerLevel\'\n    | \'solicitedServiceUUIDs\'\n    | \'isConnectable\'\n    | \'overflowServiceUUIDs\'\n  >\n
Run Code Online (Sandbox Code Playgroud)\n