curl_smile 0.0.5

A simplified rust API for Keepsmile lights
Documentation
use crate::core::{DeviceCompiler, LightState};
use btleplug::api::{Peripheral, WriteType, bleuuid::uuid_from_u16};
use std::time::Duration;
use tokio::time;
use uuid::Uuid;

#[derive(Debug, Clone, Copy)]
pub enum DeviceKind {
    KS03Old,
    KS03New,
}

impl DeviceKind {
    pub fn from_name(name: &str) -> Option<Self> {
        if name.starts_with("KS03-") {
            Some(Self::KS03Old)
        } else if name.starts_with("KS03~") {
            Some(Self::KS03New)
        } else {
            None
        }
    }
}

pub struct DeviceProfile {
    pub write_service: Uuid,
    pub write_characteristic: Uuid,
    pub notify_service: Uuid,
    pub notify_characteristic: Uuid,
    pub read_service: Uuid,
    pub read_characteristic: Uuid,
}

impl DeviceProfile {
    pub fn from_kind(kind: DeviceKind) -> Self {
        match kind {
            DeviceKind::KS03New => Self {
                write_service: uuid_from_u16(0xAFD0),
                write_characteristic: uuid_from_u16(0xAFD1),
                notify_service: uuid_from_u16(0xAFD0),
                notify_characteristic: uuid_from_u16(0xAFD2),
                read_service: uuid_from_u16(0xAFD0),
                read_characteristic: uuid_from_u16(0xAFD3),
            },
            DeviceKind::KS03Old => Self {
                write_service: uuid_from_u16(0xFFF0),
                write_characteristic: uuid_from_u16(0xFFF3),
                notify_service: uuid_from_u16(0xFFF0),
                notify_characteristic: uuid_from_u16(0xFFF3),
                read_service: uuid_from_u16(0xFFF0),
                read_characteristic: uuid_from_u16(0xFFF3),
            },
        }
    }
}

pub struct SupportedDevice {
    pub name: String,
    pub kind: DeviceKind,
    pub peripheral: btleplug::platform::Peripheral,
    pub device_profile: DeviceProfile,
}

impl SupportedDevice {
    pub async fn send_commands(&self, state: &LightState) -> anyhow::Result<()> {
        let cmds = self.kind.compile(state);

        self.peripheral.discover_services().await?;

        let chars = self.peripheral.characteristics();
        let cmd_char = chars
            .iter()
            .find(|ch| ch.uuid == self.device_profile.write_characteristic)
            .expect("Unable to find write characteristic");

        for cmd in cmds {
            self.peripheral
                .write(cmd_char, &cmd.bytes, WriteType::WithoutResponse)
                .await?;
            time::sleep(Duration::from_millis(200)).await;
        }

        Ok(())
    }
}