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}