use bluer::{AdapterEvent, Device}; use bluer::gatt::remote::Characteristic; use futures::{pin_mut, StreamExt}; use std::time::Duration; use tokio::time::sleep; const SERVICE_UUID: bluer::Uuid = bluer::Uuid::from_u128(0xadaf0900c33242a893bd25e905756cb8); const PIXEL_DATA_UUID: bluer::Uuid = bluer::Uuid::from_u128(0xadaf0903c33242a893bd25e905756cb8); #[tokio::main(flavor = "current_thread")] async fn main() -> bluer::Result<()> { let session = bluer::Session::new().await?; let adapter_names = session.adapter_names().await?; let adapter_name = adapter_names.first().expect("no Bluetooth adapter found"); let adapter = session.adapter(adapter_name)?; adapter.set_powered(true).await?; let discover = adapter.discover_devices().await?; pin_mut!(discover); while let Some(evt) = discover.next().await { match evt { AdapterEvent::DeviceAdded(addr) => { let device = adapter.device(addr)?; match find_neopixel_service(&device).await { Ok(Some(char)) => { println!("found characteristic"); match send_seq(&char).await { // this loop should never stop _ => () } } Ok(None) => { println!("characteristic not found") } Err(err) => { println!("device error : {}", &err); let _ = adapter.remove_device(device.address()).await; } } } AdapterEvent::DeviceRemoved(addr) => { println!("Device removed {}", addr); } _ => (), } } Ok(()) } async fn send_seq(char: &Characteristic) -> bluer::Result<()> { println!(" Characteristic flags : {:?}, ", char.flags().await?); let mut base_data: Vec = vec![0x00, 0x00, 0x01]; let mut off_data: Vec = vec![0x00, 0x00, 0x01]; for _ in 0..10 { base_data.append(&mut vec![0xff, 0x00, 0x00]); off_data.append(&mut vec![0x00, 0x00, 0x00]); } loop { char.write(&*base_data).await?; sleep(Duration::from_secs(1)).await; char.write(&*off_data).await?; sleep(Duration::from_secs(1)).await; } } async fn connect(device: &Device, retries: u8) -> bluer::Result<()> { if device.is_connected().await? { return Ok(()) } for i in 0..retries { match device.connect().await { Ok(()) => return Ok(()), Err(_) => { println!("connection error ({}), retry…", i); } } } Err(bluer::Error { kind: bluer::ErrorKind::ConnectionAttemptFailed, message: "all attempts fail".parse().unwrap(), }) } async fn find_neopixel_service(device: &Device) -> bluer::Result> { let addr = device.address(); let uuids = device.uuids().await?.unwrap_or_default(); if uuids.contains(&SERVICE_UUID) { println!("service neopixel found for device {}", &addr); match connect(device, 3).await { Ok(()) => { println!("successefully connected"); } Err(err) => { println!("unable to connect, trying new device, {}", err); return Err(err) } } for service in device.services().await? { if SERVICE_UUID == service.uuid().await? { for char in service.characteristics().await? { if PIXEL_DATA_UUID == char.uuid().await? { return Ok(Some(char)); } } } } } Ok(None) }