Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Losing data after connecting the bluetooth module

Objective

I am trying to return data from the BlueTooth device after connected because to use the read and write function, need some data. Example data name, overflowServiceUUIDs, solicitedServiceUUIDs, mtu, rssi... and many others. Because if I want to read or write I need some attributes. I am using the library react-native-ble-plx.

What is happening?

After the device connected I lost some values.

Important

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.

The sequence functions

toggleScanDevices()

Will push all devices to the bleDevices state.

  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);
      }
    }
  };

connectDevice(name)

  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(name)

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

Inside the connectDevice function I have a let device that receive the value about the findDeviceWhereNameContains, if I log this variable device I receive many data very important, but I'm not connected yet. So when I verify about the if (!isConnected) here I will connect, and after this, inside out this if when I log the device again I lost some values.

The log before connect

The data before the connection

The log after connect

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"
like image 765
Vagner Wentz Avatar asked Sep 08 '20 18:09

Vagner Wentz


People also ask

Why will my phone not stay connected to Bluetooth?

Battery Optimization Or Power Saving Settings Android phones have a Battery Optimization feature that saves your battery from the background apps and running programs. If the setting is enabled, the Bluetooth connection will be disconnected. Go to the Settings app and open up the Battery section.

How does Bluetooth module works?

The Bluetooth technology manages the communication channel of the wireless part. The Bluetooth modules can transmit and receives the data wirelessly by using two devices. The Bluetooth module can receive and transmits the data from a host system with the help of the host controller interface (HCI).


1 Answers

Checking the lib you're using, it creates another device object from the reponse it gets when calling the native module, it could be the case this new object comes with null values on those fields and replaces the values you need. Because it's just as it works by now, you could copy those values to another object before they get erased

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);
  };

But you have wary they don't get replaced again.

If you think this is a faulty behaviour of react-native-ble-plx you could open a PR with the changes in the Device constructor to avoid this happening.

Since you're using typescript, you'll have some complaints about typings, you could create a type from react-native-ble-plx device type and pick only the attributes part of it to omit methods and avoid storing complex object in your state.

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

type DeviceState = Pick<
    Device,
    | 'id'
    | 'name'
    | 'rssi'
    | 'mtu'
    | 'manufacturerData'
    | 'serviceData'
    | 'serviceUUIDs'
    | 'localName'
    | 'txPowerLevel'
    | 'solicitedServiceUUIDs'
    | 'isConnectable'
    | 'overflowServiceUUIDs'
  >
like image 94
diedu Avatar answered Oct 12 '22 17:10

diedu