diff --git a/src/bluez/peripheral.rs b/src/bluez/peripheral.rs index 426ff30b..9582eec8 100644 --- a/src/bluez/peripheral.rs +++ b/src/bluez/peripheral.rs @@ -182,19 +182,35 @@ impl api::Peripheral for Peripheral { let services = self.session.get_services(&self.device).await?; for service in services { let characteristics = self.session.get_characteristics(&service.id).await?; - let characteristics = - join_all(characteristics.into_iter().map(|characteristic| async { - let descriptors = self - .session - .get_descriptors(&characteristic.id) - .await - .unwrap_or(Vec::new()) - .into_iter() - .map(|descriptor| (descriptor.uuid, descriptor)) - .collect(); - CharacteristicInternal::new(characteristic, descriptors) - })) - .await; + let characteristics = join_all( + characteristics + .into_iter() + .fold( + // Only consider the first characteristic of each UUID + // This "should" be unique, but of course it's not enforced + HashMap::::new(), + |mut map, characteristic| { + if !map.contains_key(&characteristic.uuid) { + map.insert(characteristic.uuid, characteristic); + } + map + }, + ) + .into_iter() + .map(|mapped_characteristic| async { + let characteristic = mapped_characteristic.1; + let descriptors = self + .session + .get_descriptors(&characteristic.id) + .await + .unwrap_or(Vec::new()) + .into_iter() + .map(|descriptor| (descriptor.uuid, descriptor)) + .collect(); + CharacteristicInternal::new(characteristic, descriptors) + }), + ) + .await; services_internal.insert( service.uuid, ServiceInternal { diff --git a/src/corebluetooth/internal.rs b/src/corebluetooth/internal.rs index 6e58a9c7..93597bc7 100644 --- a/src/corebluetooth/internal.rs +++ b/src/corebluetooth/internal.rs @@ -217,15 +217,20 @@ impl PeripheralInternal { service_uuid: Uuid, characteristics: HashMap>, ) { - let characteristics = characteristics - .into_iter() - .map(|(characteristic_uuid, characteristic)| { - ( - characteristic_uuid, - CharacteristicInternal::new(characteristic), - ) - }) - .collect(); + let characteristics = characteristics.into_iter().fold( + // Only consider the first characteristic of each UUID + // This "should" be unique, but of course it's not enforced + HashMap::::new(), + |mut map, (characteristic_uuid, characteristic)| { + if !map.contains_key(&characteristic_uuid) { + map.insert( + characteristic_uuid, + CharacteristicInternal::new(characteristic), + ); + } + map + }, + ); let service = self .services .get_mut(&service_uuid) diff --git a/src/droidplug/peripheral.rs b/src/droidplug/peripheral.rs index 14ccc2f7..9ed150fb 100644 --- a/src/droidplug/peripheral.rs +++ b/src/droidplug/peripheral.rs @@ -8,7 +8,6 @@ use crate::{ use async_trait::async_trait; use futures::stream::Stream; use jni::{ - descriptors, objects::{GlobalRef, JList, JObject}, JNIEnv, }; @@ -270,7 +269,7 @@ impl api::Peripheral for Peripheral { for service in list.iter()? { let service = JBluetoothGattService::from_env(env, service)?; - let mut characteristics = BTreeSet::new(); + let mut characteristics = BTreeSet::::new(); for characteristic in service.get_characteristics()? { let mut descriptors = BTreeSet::new(); for descriptor in characteristic.get_descriptors()? { @@ -280,18 +279,23 @@ impl api::Peripheral for Peripheral { characteristic_uuid: characteristic.get_uuid()?, }); } - characteristics.insert(Characteristic { + let char = Characteristic { service_uuid: service.get_uuid()?, uuid: characteristic.get_uuid()?, properties: characteristic.get_properties()?, descriptors: descriptors.clone(), - }); - peripheral_characteristics.push(Characteristic { - service_uuid: service.get_uuid()?, - uuid: characteristic.get_uuid()?, - properties: characteristic.get_properties()?, - descriptors: descriptors, - }); + }; + // Only consider the first characteristic of each UUID + // This "should" be unique, but of course it's not enforced + if characteristics + .iter() + .filter(|c| c.service_uuid == char.service_uuid && c.uuid == char.uuid) + .count() + == 0 + { + characteristics.insert(char.clone()); + peripheral_characteristics.push(char.clone()); + } } peripheral_services.push(Service { uuid: service.get_uuid()?, diff --git a/src/winrtble/peripheral.rs b/src/winrtble/peripheral.rs index fda061f9..bac09da4 100644 --- a/src/winrtble/peripheral.rs +++ b/src/winrtble/peripheral.rs @@ -44,6 +44,8 @@ use tokio::sync::broadcast; use uuid::Uuid; use std::sync::Weak; +use windows::core::GUID; +use windows::Devices::Bluetooth::GenericAttributeProfile::GattCharacteristic; use windows::Devices::Bluetooth::{Advertisement::*, BluetoothAddressType}; #[cfg_attr( @@ -413,8 +415,22 @@ impl ApiPeripheral for Peripheral { if !self.shared.ble_services.contains_key(&uuid) { match BLEDevice::get_characteristics(service).await { Ok(characteristics) => { - let characteristics = - characteristics.into_iter().map(|characteristic| async { + let characteristics = characteristics + .into_iter() + .fold( + // Only consider the first characteristic of each UUID + // This "should" be unique, but of course it's not enforced + HashMap::::new(), + |mut map, gatt_characteristic| { + let uuid = gatt_characteristic.Uuid().unwrap_or_default(); + if !map.contains_key(&uuid) { + map.insert(uuid, gatt_characteristic); + } + map + }, + ) + .into_iter() + .map(|(_, characteristic)| async { let c = characteristic.clone(); ( characteristic,