hyperion/models/
devices.rs

1use ambassador::{delegatable_trait, Delegate};
2use derive_more::From;
3use serde_derive::{Deserialize, Serialize};
4use strum_macros::IntoStaticStr;
5use validator::Validate;
6
7use super::{default_false, ColorOrder};
8
9#[delegatable_trait]
10pub trait DeviceConfig: Sync + Send {
11    fn hardware_led_count(&self) -> usize;
12
13    fn rewrite_time(&self) -> Option<std::time::Duration> {
14        None
15    }
16
17    fn latch_time(&self) -> std::time::Duration {
18        Default::default()
19    }
20}
21
22macro_rules! impl_device_config {
23    ($t:ty) => {
24        impl DeviceConfig for $t {
25            fn hardware_led_count(&self) -> usize {
26                self.hardware_led_count as _
27            }
28
29            fn rewrite_time(&self) -> Option<std::time::Duration> {
30                if self.rewrite_time == 0 {
31                    None
32                } else {
33                    Some(std::time::Duration::from_millis(self.rewrite_time as _))
34                }
35            }
36
37            fn latch_time(&self) -> std::time::Duration {
38                std::time::Duration::from_millis(self.latch_time as _)
39            }
40        }
41    };
42}
43
44#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
45#[serde(rename_all = "lowercase")]
46#[derive(Default)]
47pub enum DummyDeviceMode {
48    #[default]
49    Text,
50    Ansi,
51}
52
53#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Validate)]
54#[serde(default, rename_all = "camelCase", deny_unknown_fields)]
55pub struct Dummy {
56    #[validate(range(min = 1))]
57    pub hardware_led_count: u32,
58    pub rewrite_time: u32,
59    pub latch_time: u32,
60    pub mode: DummyDeviceMode,
61}
62
63impl_device_config!(Dummy);
64
65impl Default for Dummy {
66    fn default() -> Self {
67        Self {
68            hardware_led_count: 1,
69            rewrite_time: 0,
70            latch_time: 0,
71            mode: Default::default(),
72        }
73    }
74}
75
76fn default_ws_spi_rate() -> i32 {
77    3000000
78}
79
80fn default_ws_spi_rewrite_time() -> u32 {
81    1000
82}
83
84#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Validate)]
85#[serde(rename_all = "camelCase", deny_unknown_fields)]
86pub struct Ws2812Spi {
87    #[serde(default = "Default::default")]
88    pub color_order: ColorOrder,
89    #[validate(range(min = 1))]
90    pub hardware_led_count: u32,
91    #[serde(default = "default_false")]
92    pub invert: bool,
93    #[serde(default = "Default::default")]
94    pub latch_time: u32,
95    pub output: String,
96    #[serde(default = "default_ws_spi_rate")]
97    pub rate: i32,
98    #[serde(default = "default_ws_spi_rewrite_time")]
99    pub rewrite_time: u32,
100}
101
102impl_device_config!(Ws2812Spi);
103
104#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Validate)]
105#[serde(rename_all = "camelCase", deny_unknown_fields)]
106pub struct PhilipsHue {
107    pub black_lights_timeout: i32,
108    pub brightness_factor: f32,
109    pub brightness_max: f32,
110    pub brightness_min: f32,
111    pub brightness_threshold: f32,
112    #[serde(rename = "clientkey")]
113    pub client_key: String,
114    pub color_order: ColorOrder,
115    pub debug_level: String,
116    pub debug_streamer: bool,
117    pub group_id: i32,
118    #[validate(range(min = 1))]
119    pub hardware_led_count: u32,
120    pub light_ids: Vec<String>,
121    pub output: String,
122    pub restore_original_state: bool,
123    #[serde(rename = "sslHSTimeoutMax")]
124    pub ssl_hs_timeout_max: i32,
125    #[serde(rename = "sslHSTimeoutMin")]
126    pub ssl_hs_timeout_min: i32,
127    pub ssl_read_timeout: i32,
128    pub switch_off_on_black: bool,
129    #[serde(rename = "transitiontime")]
130    pub transition_time: f32,
131    #[serde(rename = "useEntertainmentAPI")]
132    pub use_entertainment_api: bool,
133    pub username: String,
134    pub verbose: bool,
135}
136
137impl DeviceConfig for PhilipsHue {
138    fn hardware_led_count(&self) -> usize {
139        self.hardware_led_count as _
140    }
141}
142
143fn default_file_rewrite_time() -> u32 {
144    1000
145}
146
147#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Validate)]
148#[serde(rename_all = "camelCase", deny_unknown_fields)]
149pub struct File {
150    #[serde(default = "Default::default")]
151    pub color_order: ColorOrder,
152    #[validate(range(min = 1))]
153    pub hardware_led_count: u32,
154    #[serde(default = "Default::default")]
155    pub latch_time: u32,
156    pub output: String,
157    #[serde(default = "default_file_rewrite_time")]
158    pub rewrite_time: u32,
159    #[serde(default = "Default::default")]
160    pub print_time_stamp: bool,
161}
162
163impl DeviceConfig for File {
164    fn hardware_led_count(&self) -> usize {
165        self.hardware_led_count as _
166    }
167}
168
169#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, IntoStaticStr, Delegate, From)]
170#[serde(rename_all = "lowercase", tag = "type", deny_unknown_fields)]
171#[delegate(DeviceConfig)]
172pub enum Device {
173    Dummy(Dummy),
174    Ws2812Spi(Ws2812Spi),
175    PhilipsHue(PhilipsHue),
176    File(File),
177}
178
179impl Default for Device {
180    fn default() -> Self {
181        Self::Dummy(Dummy::default())
182    }
183}
184
185impl Validate for Device {
186    fn validate(&self) -> Result<(), validator::ValidationErrors> {
187        match self {
188            Device::Dummy(device) => device.validate(),
189            Device::Ws2812Spi(device) => device.validate(),
190            Device::PhilipsHue(device) => device.validate(),
191            Device::File(device) => device.validate(),
192        }
193    }
194}