连接蓝牙模块后丢失数据
Losing data after connecting the bluetooth module
Objective
连接后,我正尝试从蓝牙设备return获取数据,因为要使用读写功能,需要一些数据。
示例数据 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);
};
切换连接设备(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"
检查您正在使用的库,它 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 那些值在被擦除之前传给另一个对象
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'
>
Objective
连接后,我正尝试从蓝牙设备return获取数据,因为要使用读写功能,需要一些数据。
示例数据 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);
};
切换连接设备(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"
检查您正在使用的库,它 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 那些值在被擦除之前传给另一个对象
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'
>