Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support device UUID returned by macOS in place of MAC #27

Merged
merged 1 commit into from
Jan 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion healthpi-bt/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ btleplug = { version = "0.11.5", optional = true }
futures = "0.3.21"
mockall = "0.11.3"
serde = { version = "1.0.152", features = ["derive"] }
uuid = "1.1.2"
uuid = { version = "1.1.2", features = ["serde"] }

[features]
default = ["btleplug"]
Expand Down
19 changes: 16 additions & 3 deletions healthpi-bt/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ use async_trait::async_trait;
use futures::Stream;
use uuid::Uuid;

use super::macaddress::MacAddress;

#[derive(Debug)]
pub enum DeviceError {
ConnectionFailure(String),
Expand Down Expand Up @@ -35,14 +33,29 @@ pub trait BleCharacteristic: Send + Sync + fmt::Debug {
async fn read(&self) -> Result<Vec<u8>, DeviceError>;
}

#[derive(Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
pub struct DeviceId(String);

impl DeviceId {
pub fn new(device_id: String) -> Self {
Self(device_id)
}
}

impl fmt::Display for DeviceId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}

#[mockall::automock]
#[async_trait]
pub trait BleDevice: Send + Sync {
async fn connect(&self) -> Result<(), DeviceError>;
async fn disconnect(&self) -> Result<(), DeviceError>;

fn in_range(&self) -> bool;
fn mac_address(&self) -> MacAddress;
fn id(&self) -> DeviceId;
fn name(&self) -> String;

async fn get_characteristic(
Expand Down
13 changes: 9 additions & 4 deletions healthpi-bt/src/btleplug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ use futures::future;
use futures::{lock::Mutex, Stream, StreamExt};
use uuid::Uuid;

use crate::api::DeviceId;

use super::api::{BleCharacteristic, BleCharacteristicEvent, BleDevice, BleSession, DeviceError};
use super::macaddress::MacAddress;

impl From<ValueNotification> for BleCharacteristicEvent {
fn from(value: ValueNotification) -> Self {
Expand Down Expand Up @@ -134,15 +135,19 @@ impl BleDevice for BleDeviceImpl {
self.properties.rssi.is_some()
}

fn mac_address(&self) -> MacAddress {
self.properties.address.into_inner().into()
fn id(&self) -> DeviceId {
if cfg!(target_os = "macos") {
DeviceId::new(self.peripheral.id().to_string())
} else {
DeviceId::new(self.properties.address.to_string())
}
}

fn name(&self) -> String {
self.properties
.local_name
.clone()
.unwrap_or(self.mac_address().to_string())
.unwrap_or(self.id().to_string())
}

async fn get_characteristic(
Expand Down
2 changes: 1 addition & 1 deletion healthpi-bt/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ mod btleplug;
mod macaddress;

pub use api::{
BleCharacteristic, BleCharacteristicEvent, BleDevice, BleSession, DeviceError,
BleCharacteristic, BleCharacteristicEvent, BleDevice, BleSession, DeviceError, DeviceId,
MockBleCharacteristic, MockBleDevice, MockBleSession,
};
#[cfg(feature = "bluez")]
Expand Down
2 changes: 1 addition & 1 deletion healthpi-db/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ edition = "2021"
[dependencies]
healthpi-bt = { path = "../healthpi-bt" }
chrono = { version = "0.4.19", features = ["serde"] }
sqlx = { version = "0.6", features = [ "runtime-tokio-rustls", "sqlite" ] }
sqlx = { version = "0.6", features = ["runtime-tokio-rustls", "sqlite"] }
dotenv = "0.15.0"
log = "0.4.17"
num = "0.4"
Expand Down
4 changes: 2 additions & 2 deletions healthpi-db/src/measurement.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use chrono::NaiveDateTime;
use healthpi_bt::MacAddress;
use healthpi_bt::DeviceId;
use num::FromPrimitive;
use num_derive::FromPrimitive;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -92,7 +92,7 @@ impl TryFrom<(usize, f64)> for Value {

#[derive(Clone, Debug, Hash, PartialEq, Deserialize, Serialize)]
pub enum Source {
Device(MacAddress),
Device(DeviceId),
Unknown(String),
}

Expand Down
2 changes: 1 addition & 1 deletion healthpi-loader/src/devices/contour.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ impl ElitePlus {
timestamp,
vec![Value::Glucose(glucose as i32)],
event.value,
Source::Device(self.ble_device.mac_address()),
Source::Device(self.ble_device.id()),
),
))
}
Expand Down
27 changes: 12 additions & 15 deletions healthpi-loader/src/devices/device.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
use std::collections::HashMap;
use std::io::{BufRead, BufReader};
use std::str::FromStr;
use std::{collections::HashSet, error::Error, fs::File};

use async_trait::async_trait;
use chrono::{DateTime, Local, Utc};
use healthpi_bt::{BleDevice, MacAddress};
use healthpi_bt::{BleDevice, DeviceId};
use log::{debug, info, warn};

use healthpi_db::measurement::Record;
Expand All @@ -21,19 +20,19 @@ pub trait Device {
}

struct BackoffTable {
expiry_timestamps: HashMap<MacAddress, DateTime<Utc>>,
expiry_timestamps: HashMap<DeviceId, DateTime<Utc>>,
}

impl BackoffTable {
fn new() -> Self {
Self {
expiry_timestamps: HashMap::<MacAddress, DateTime<Utc>>::new(),
expiry_timestamps: HashMap::<DeviceId, DateTime<Utc>>::new(),
}
}

fn check(&self, device: &dyn BleDevice) -> bool {
self.expiry_timestamps
.get(&device.mac_address())
.get(&device.id())
.filter(|expiry| expiry > &&chrono::Utc::now())
.is_some()
}
Expand All @@ -42,8 +41,7 @@ impl BackoffTable {
let backoff_expiry = chrono::Utc::now()
.checked_add_signed(chrono::Duration::minutes(5))
.unwrap();
self.expiry_timestamps
.insert(device.mac_address(), backoff_expiry);
self.expiry_timestamps.insert(device.id(), backoff_expiry);
backoff_expiry
}
}
Expand All @@ -55,13 +53,13 @@ pub trait Factory: Send + Sync {
}

pub struct FactoryImpl {
paired_devices: HashSet<MacAddress>,
paired_devices: HashSet<DeviceId>,
backoff_table: BackoffTable,
}

impl FactoryImpl {
#[allow(dead_code)]
pub fn new(paired_devices: HashSet<MacAddress>) -> Self {
pub fn new(paired_devices: HashSet<DeviceId>) -> Self {
Self {
paired_devices,
backoff_table: BackoffTable::new(),
Expand All @@ -70,11 +68,10 @@ impl FactoryImpl {

pub fn from_file(path: &str) -> std::io::Result<Self> {
let file = File::open(path)?;
let paired_devices: HashSet<MacAddress> = BufReader::new(file)
let paired_devices: HashSet<DeviceId> = BufReader::new(file)
.lines()
.map_while(|l| l.ok())
.map(|s| MacAddress::from_str(&s))
.filter_map(|l| l.ok())
.map(DeviceId::new)
.collect();

info!("Loaded {} paired devices from file", paired_devices.len());
Expand All @@ -85,7 +82,7 @@ impl FactoryImpl {

impl Factory for FactoryImpl {
fn make_device(&self, ble_device: Box<dyn BleDevice>) -> Option<Box<dyn Device>> {
if !ble_device.in_range() || !self.paired_devices.contains(&ble_device.mac_address()) {
if !ble_device.in_range() || !self.paired_devices.contains(&ble_device.id()) {
None
} else if self.backoff_table.check(&*ble_device) {
debug!(
Expand All @@ -101,8 +98,8 @@ impl Factory for FactoryImpl {
Some(Box::new(soehnle::SystoMC400::new(ble_device)))
} else {
warn!(
"Device with MAC={} is not of any supported types",
ble_device.mac_address()
"Device with ID={} is not of any supported types",
ble_device.id()
);
None
}
Expand Down
Loading
Loading