denki 0.1.2

CLI for controlling TP-Link smart home devices — denki (電気) means electricity in Japanese
Documentation
use super::registry::DeviceKind;
use anyhow::Result;

// Command capability guards — pure functions, called before any network I/O.

pub fn can_control_power(kind: &DeviceKind) -> Result<()> {
    match kind {
        DeviceKind::Bulb
        | DeviceKind::LightStrip
        | DeviceKind::Plug
        | DeviceKind::Dimmer
        | DeviceKind::Strip => Ok(()),
        other => Err(crate::error::error(
            "unsupported_operation",
            format!("{other} does not support power control"),
        )),
    }
}

pub fn can_dim(kind: &DeviceKind) -> Result<()> {
    match kind {
        DeviceKind::Bulb | DeviceKind::LightStrip | DeviceKind::Dimmer => Ok(()),
        other => Err(crate::error::error(
            "unsupported_operation",
            format!("`dim` is only supported on bulbs and HS220 dimmers, not {other}"),
        )),
    }
}

fn require_bulb(kind: &DeviceKind, cmd: &str, models: &str) -> Result<()> {
    match kind {
        DeviceKind::Bulb => Ok(()),
        other => Err(crate::error::error(
            "unsupported_operation",
            format!("`{cmd}` is only supported on {models}, not {other}"),
        )),
    }
}

fn require_relay_device(kind: &DeviceKind, cmd: &str) -> Result<()> {
    match kind {
        DeviceKind::Plug | DeviceKind::Dimmer | DeviceKind::Strip => Ok(()),
        other => Err(crate::error::error(
            "unsupported_operation",
            format!(
                "`{cmd}` is only supported on plugs, dimmers, and strips \
             (e.g. KP115, HS220, HS300), not {other}"
            ),
        )),
    }
}

pub fn can_set_color_temp(kind: &DeviceKind) -> Result<()> {
    match kind {
        DeviceKind::Bulb | DeviceKind::LightStrip => Ok(()),
        other => Err(crate::error::error(
            "unsupported_operation",
            format!("`color-temp` is only supported on color lights, not {other}"),
        )),
    }
}

pub fn can_set_color(kind: &DeviceKind) -> Result<()> {
    match kind {
        DeviceKind::Bulb | DeviceKind::LightStrip => Ok(()),
        other => Err(crate::error::error(
            "unsupported_operation",
            format!("`color` is only supported on color lights, not {other}"),
        )),
    }
}

pub fn can_get_specs(kind: &DeviceKind) -> Result<()> {
    require_bulb(kind, "specs", "bulbs")
}

pub fn can_get_presets(kind: &DeviceKind) -> Result<()> {
    require_bulb(kind, "presets", "bulbs")
}

pub fn can_get_effects(kind: &DeviceKind) -> Result<()> {
    match kind {
        DeviceKind::LightStrip => Ok(()),
        other => Err(crate::error::error(
            "unsupported_operation",
            format!("`effects` is only supported on light strips, not {other}"),
        )),
    }
}

pub fn can_get_schedules(kind: &DeviceKind) -> Result<()> {
    require_relay_device(kind, "schedules")
}

pub fn can_control_led(kind: &DeviceKind) -> Result<()> {
    require_relay_device(kind, "led")
}

pub fn can_get_clock(kind: &DeviceKind) -> Result<()> {
    require_relay_device(kind, "clock")
}