yeelight 0.4.1

Rust CLI and API bindings for yeelight WiFi Light Inter-Operation
Documentation
use yeelight::{BulbError, FlowExpresion, FlowTuple, Response};

use std::time::Duration;

use structopt::clap::arg_enum;

arg_enum! {
    #[derive(Debug, Clone)]
    pub enum Preset {
        Candle,
        Reading,
        NightReading,
        CosyHome,
        Romantic,
        Birthday,
        DateNight,
        Teatime,
        PcMode,
        Concentration,
        Movie,
        Night,
        Notify,
        Notify2,

        PulseRed,
        PulseBlue,
        PulseGreen,

        Red,
        Green,
        Blue,

        Police,
        Police2,
        Disco,
        Temp,
    }
}

enum PresetValue {
    RGB(u32, u8),
    HSV(u16, u8, u8),
    CT(u16, u8),
    Flow(yeelight::FlowExpresion, u8, yeelight::CfAction),
}

pub async fn apply(bulb: yeelight::Bulb, preset: Preset) -> Result<Option<Response>, BulbError> {
    use Preset::*;
    let red = 0xFF_00_00;
    let green = 0x00_FF_00;
    let blue = 0x00_00_FF;
    match preset {
        Candle => send(bulb, candle()).await,
        Reading => send(bulb, reading()).await,
        NightReading => send(bulb, night_reading()).await,
        CosyHome => send(bulb, cosy_home()).await,
        Romantic => send(bulb, romantic()).await,
        Birthday => send(bulb, birthday()).await,
        DateNight => send(bulb, date_night()).await,
        Teatime => send(bulb, teatime()).await,
        PcMode => send(bulb, pc_mode()).await,
        Concentration => send(bulb, concentration()).await,
        Movie => send(bulb, movie()).await,
        Night => send(bulb, night()).await,
        Notify => send(bulb, notify()).await,
        Notify2 => send(bulb, notify2()).await,

        Red => send(bulb, PresetValue::RGB(red, 100)).await,
        Green => send(bulb, PresetValue::RGB(green, 100)).await,
        Blue => send(bulb, PresetValue::RGB(blue, 100)).await,

        PulseRed => send(bulb, pulse(red, 100, 250)).await,
        PulseGreen => send(bulb, pulse(green, 100, 250)).await,
        PulseBlue => send(bulb, pulse(blue, 100, 250)).await,
        Police => send(bulb, police(100)).await,
        Police2 => send(bulb, police2(100)).await,
        Disco => send(bulb, disco(120)).await,
        Temp => send(bulb, temp(2600, 5000, 100)).await,
    }
}

async fn send(
    mut bulb: yeelight::Bulb,
    preset: PresetValue,
) -> Result<Option<Response>, BulbError> {
    match preset {
        PresetValue::Flow(expression, count, action) => {
            bulb.start_cf(count, action, expression).await
        }
        PresetValue::RGB(color, bright) => {
            bulb.set_scene(yeelight::Class::Color, color.into(), bright.into(), 0)
                .await
        }
        PresetValue::HSV(hue, sat, bright) => {
            bulb.set_scene(yeelight::Class::HSV, hue.into(), sat.into(), bright.into())
                .await
        }
        PresetValue::CT(ct, bright) => {
            bulb.set_scene(yeelight::Class::CT, ct.into(), bright.into(), 0)
                .await
        }
    }
}

fn disco(bpm: u64) -> PresetValue {
    let duration = Duration::from_millis(1000 / bpm);
    let expr = FlowExpresion(vec![
        FlowTuple::rgb(duration, 0xFF_00_00, 100),
        FlowTuple::rgb(duration, 0xFF_00_00, 1),
        FlowTuple::rgb(duration, 0x80_FF_00, 100),
        FlowTuple::rgb(duration, 0x80_FF_00, 1),
        FlowTuple::rgb(duration, 0x00_FF_FF, 100),
        FlowTuple::rgb(duration, 0x00_FF_FF, 1),
        FlowTuple::rgb(duration, 0x80_00_FF, 100),
        FlowTuple::rgb(duration, 0x80_00_FF, 1),
    ]);
    PresetValue::Flow(expr, 0, yeelight::CfAction::Stay)
}

fn temp(a: u32, b: u32, brightness: i8) -> PresetValue {
    let duration = Duration::from_millis(40_000);
    let expr = FlowExpresion(vec![
        FlowTuple::ct(duration, a, brightness),
        FlowTuple::ct(duration, b, brightness),
    ]);
    PresetValue::Flow(expr, 0, yeelight::CfAction::Stay)
}

fn pulse(rgb: u32, brightness: i8, duration: u64) -> PresetValue {
    let duration = Duration::from_millis(duration);
    let expr = FlowExpresion(vec![
        FlowTuple::rgb(duration, rgb, brightness),
        FlowTuple::rgb(duration, rgb, 1),
    ]);
    PresetValue::Flow(expr, 2, yeelight::CfAction::Recover)
}

fn police(brightness: i8) -> PresetValue {
    let duration = Duration::from_millis(300);
    let (red, blue) = (0xFF_00_00, 0x00_00_FF);
    let expr = FlowExpresion(vec![
        FlowTuple::rgb(duration, red, brightness),
        FlowTuple::rgb(duration, blue, brightness),
    ]);
    PresetValue::Flow(expr, 0, yeelight::CfAction::Stay)
}

fn police2(brightness: i8) -> PresetValue {
    let duration = Duration::from_millis(300);
    let (red, blue) = (0xFF_00_00, 0x00_00_FF);
    let expr = FlowExpresion(vec![
        FlowTuple::rgb(duration, red, brightness),
        FlowTuple::rgb(duration, red, 1),
        FlowTuple::rgb(duration, red, brightness),
        FlowTuple::sleep(duration),
        FlowTuple::rgb(duration, blue, brightness),
        FlowTuple::rgb(duration, blue, 1),
        FlowTuple::rgb(duration, blue, brightness),
        FlowTuple::sleep(duration),
    ]);
    PresetValue::Flow(expr, 0, yeelight::CfAction::Stay)
}

fn candle() -> PresetValue {
    let ct = 2700;
    let expr = FlowExpresion(vec![
        FlowTuple::ct(Duration::from_millis(800), ct, 50),
        FlowTuple::ct(Duration::from_millis(800), ct, 30),
        FlowTuple::ct(Duration::from_millis(1200), ct, 80),
        FlowTuple::ct(Duration::from_millis(800), ct, 60),
        FlowTuple::ct(Duration::from_millis(1200), ct, 90),
        FlowTuple::ct(Duration::from_millis(2400), ct, 50),
        FlowTuple::ct(Duration::from_millis(1200), ct, 80),
        FlowTuple::ct(Duration::from_millis(800), ct, 60),
        FlowTuple::ct(Duration::from_millis(400), ct, 70),
    ]);
    PresetValue::Flow(expr, 0, yeelight::CfAction::Stay)
}
fn reading() -> PresetValue {
    PresetValue::CT(3500, 100)
}
fn night_reading() -> PresetValue {
    PresetValue::CT(4000, 40)
}

fn cosy_home() -> PresetValue {
    PresetValue::CT(2700, 80)
}

fn romantic() -> PresetValue {
    let expr = FlowExpresion(vec![
        FlowTuple::rgb(Duration::from_millis(4000), 0x59_15_6D, 1),
        FlowTuple::rgb(Duration::from_millis(4000), 0x66_14_2A, 1),
    ]);
    PresetValue::Flow(expr, 0, yeelight::CfAction::Stay)
}

fn birthday() -> PresetValue {
    let expr = FlowExpresion(vec![
        FlowTuple::rgb(Duration::from_millis(1996), 0xDC_50_19, 80),
        FlowTuple::rgb(Duration::from_millis(1996), 0xDC_78_1E, 80),
        FlowTuple::rgb(Duration::from_millis(1996), 0xAA_32_14, 80),
    ]);
    PresetValue::Flow(expr, 0, yeelight::CfAction::Stay)
}

fn date_night() -> PresetValue {
    PresetValue::HSV(24, 100, 50)
}

fn teatime() -> PresetValue {
    PresetValue::CT(3000, 50)
}

fn pc_mode() -> PresetValue {
    PresetValue::CT(2700, 30)
}
fn concentration() -> PresetValue {
    PresetValue::CT(5000, 100)
}

fn movie() -> PresetValue {
    PresetValue::HSV(240, 60, 50)
}

fn night() -> PresetValue {
    PresetValue::HSV(36, 100, 1)
}

fn notify() -> PresetValue {
    let duration = Duration::from_millis(300);
    let temp = 5000;
    let expr = FlowExpresion(vec![
        FlowTuple::ct(duration, temp, 100),
        FlowTuple::ct(duration, temp, 1),
        FlowTuple::ct(duration, temp, 100),
        FlowTuple::ct(duration, temp, 1),
        FlowTuple::ct(duration, temp, 100),
        FlowTuple::ct(duration, temp, 1),
    ]);
    let len = &expr.0.len();
    PresetValue::Flow(expr, *len as u8, yeelight::CfAction::Recover)
}

fn notify2() -> PresetValue {
    let duration = Duration::from_millis(200);
    let temp = 5000;
    let expr = FlowExpresion(vec![
        FlowTuple::ct(duration, temp, 100),
        FlowTuple::ct(duration, temp, 1),
        FlowTuple::ct(duration, temp, 100),
        FlowTuple::ct(duration, temp, 1),
    ]);
    let len = &expr.0.len();
    PresetValue::Flow(expr, *len as u8, yeelight::CfAction::Recover)
}