bcms 0.1.12

Bluetooth Client Manager Service for IoT device management
Documentation
use crate::{Error, Result};
use bluer::{Address, Session};
use std::str::FromStr;
use tracing::{error, info, warn};

/// Bluetooth pairing manager using bluer for actual Bluetooth operations
pub struct BluetoothPairing {
    session: Session,
}

impl BluetoothPairing {
    /// Create a new BluetoothPairing instance
    pub async fn new() -> Result<Self> {
        let session = Session::new().await
            .map_err(|e| Error::General(format!("Failed to create Bluetooth session: {}", e)))?;
        
        Ok(Self { session })
    }

    /// Pair with a device using actual Bluetooth pairing
    pub async fn pair_device(&self, address: &str) -> Result<bool> {
        info!("Starting Bluetooth pairing with device: {}", address);
        
        // Parse the address
        let addr = Address::from_str(address)
            .map_err(|e| Error::General(format!("Invalid Bluetooth address {}: {}", address, e)))?;

        // Get the default adapter
        let adapter = self.session.default_adapter().await
            .map_err(|e| Error::General(format!("Failed to get default Bluetooth adapter: {}", e)))?;

        // Get the device
        let device = adapter.device(addr)
            .map_err(|e| Error::General(format!("Failed to get device {}: {}", address, e)))?;

        // Check if already paired
        if device.is_paired().await
            .map_err(|e| Error::General(format!("Failed to check pairing status: {}", e)))? {
            info!("Device {} is already paired", address);
            return Ok(true);
        }

        // Attempt to pair
        match device.pair().await {
            Ok(()) => {
                info!("Successfully paired with device: {}", address);
                Ok(true)
            }
            Err(e) => {
                error!("Failed to pair with device {}: {}", address, e);
                // Don't return error, just return false for unsuccessful pairing
                Ok(false)
            }
        }
    }

    /// Remove Bluetooth pairing/bond with a device
    pub async fn unpair_device(&self, address: &str) -> Result<bool> {
        info!("Removing Bluetooth pairing with device: {}", address);
        
        // Parse the address
        let addr = Address::from_str(address)
            .map_err(|e| Error::General(format!("Invalid Bluetooth address {}: {}", address, e)))?;

        // Get the default adapter
        let adapter = self.session.default_adapter().await
            .map_err(|e| Error::General(format!("Failed to get default Bluetooth adapter: {}", e)))?;

        // Get the device
        let device = adapter.device(addr)
            .map_err(|e| Error::General(format!("Failed to get device {}: {}", address, e)))?;

        // Check if actually paired
        if !device.is_paired().await
            .map_err(|e| Error::General(format!("Failed to check pairing status: {}", e)))? {
            warn!("Device {} is not paired", address);
            return Ok(false);
        }

        // Remove the device (unpair)
        match adapter.remove_device(addr).await {
            Ok(()) => {
                info!("Successfully unpaired device: {}", address);
                Ok(true)
            }
            Err(e) => {
                error!("Failed to unpair device {}: {}", address, e);
                // Don't return error, just return false for unsuccessful unpairing
                Ok(false)
            }
        }
    }

    /// Check if a device is actually paired via Bluetooth
    pub async fn is_device_paired(&self, address: &str) -> Result<bool> {
        // Parse the address
        let addr = Address::from_str(address)
            .map_err(|e| Error::General(format!("Invalid Bluetooth address {}: {}", address, e)))?;

        // Get the default adapter
        let adapter = self.session.default_adapter().await
            .map_err(|e| Error::General(format!("Failed to get default Bluetooth adapter: {}", e)))?;

        // Get the device
        let device = adapter.device(addr)
            .map_err(|e| Error::General(format!("Failed to get device {}: {}", address, e)))?;

        // Check pairing status
        device.is_paired().await
            .map_err(|e| Error::General(format!("Failed to check pairing status for {}: {}", address, e)))
    }

    /// Check if a device is currently connected
    pub async fn is_device_connected(&self, address: &str) -> Result<bool> {
        // Parse the address
        let addr = Address::from_str(address)
            .map_err(|e| Error::General(format!("Invalid Bluetooth address {}: {}", address, e)))?;

        // Get the default adapter
        let adapter = self.session.default_adapter().await
            .map_err(|e| Error::General(format!("Failed to get default Bluetooth adapter: {}", e)))?;

        // Get the device
        let device = adapter.device(addr)
            .map_err(|e| Error::General(format!("Failed to get device {}: {}", address, e)))?;

        // Check connection status
        device.is_connected().await
            .map_err(|e| Error::General(format!("Failed to check connection status for {}: {}", address, e)))
    }
}