1use std::{
2 convert::TryFrom,
3 fmt::Debug,
4 io::{Error, Read, Write},
5 net::TcpStream,
6 sync::Mutex,
7 time::Duration,
8};
9
10use crate::{bulb::Bulb, lightmode::HSV, rgb::RGB};
11use rand::{prelude::ThreadRng, RngCore};
12use serde::Deserialize;
13
14pub struct BulbConnection<T: Read + Write, R: RngCore> {
15 pub bulb: Bulb,
16 pub connection: Mutex<T>,
17 pub rng: R,
18}
19
20#[derive(Debug)]
21pub enum MethodCallError {
22 BadRequest,
23 UnsupportedMethod,
24 IOError(std::io::Error),
25 ParseError,
26 SynchronizationError,
27 ErrorResponse(ErrorResponse),
28}
29
30pub trait MethodCallResponse<'a>: Deserialize<'a> + Debug {
31 fn id(&self) -> i16;
32}
33
34#[derive(Debug, Deserialize)]
35pub struct ErrorResponse {
36 id: i16,
37 error: BulbErrorResponse,
38}
39
40#[derive(Debug, Deserialize)]
41pub struct BulbErrorResponse {
42 code: i32,
43 message: String,
44}
45
46#[derive(Debug, Deserialize, Clone)]
47pub struct StringVecResponse {
48 pub id: i16,
49 pub result: Vec<String>,
50}
51
52#[derive(Debug, Deserialize, Clone)]
53pub struct CronResult {
54 #[serde(rename(serialize = "type", deserialize = "type"))]
55 pub cron_type: i32,
56 pub delay: u16,
57 pub mix: i32,
58}
59
60#[derive(Debug, Deserialize, Clone)]
61pub struct CronResponse {
62 pub id: i16,
63 pub result: Vec<CronResult>,
64}
65
66impl TryFrom<CronResult> for Cron {
67 type Error = String;
68
69 fn try_from(value: CronResult) -> Result<Self, Self::Error> {
70 if value.cron_type != 0 {
71 return Err("Unsupported cron type.".to_string());
72 }
73 Ok(Cron {
74 cron_type: CronType::PowerOff,
75 minutes: value.delay,
76 })
77 }
78}
79
80impl<'a> MethodCallResponse<'a> for CronResponse {
81 fn id(&self) -> i16 {
82 self.id
83 }
84}
85
86impl<'a> MethodCallResponse<'a> for StringVecResponse {
87 fn id(&self) -> i16 {
88 self.id
89 }
90}
91
92pub type TcpConnection = BulbConnection<TcpStream, ThreadRng>;
93
94impl TcpConnection {
95 pub fn new(bulb: Bulb) -> Result<Self, Error> {
96 return TcpStream::connect(&bulb.ip_address).map(|connection| BulbConnection {
97 bulb: bulb,
98 connection: Mutex::new(connection),
99 rng: rand::thread_rng(),
100 });
101 }
102}
103
104pub enum MusicMode<'a> {
105 On(&'a str, usize),
106 Off,
107}
108
109pub enum AdjustableProp {
110 Brightness,
111 Ct,
112 Color,
113}
114
115impl From<&AdjustableProp> for &str {
116 fn from(a: &AdjustableProp) -> Self {
117 match a {
118 AdjustableProp::Brightness => "bright",
119 AdjustableProp::Ct => "ct",
120 AdjustableProp::Color => "color",
121 }
122 }
123}
124
125pub enum AdjustAction {
126 Increase,
127 Decrease,
128 Circle,
129}
130
131impl From<&AdjustAction> for &str {
132 fn from(a: &AdjustAction) -> Self {
133 match a {
134 AdjustAction::Increase => "increase",
135 AdjustAction::Decrease => "decrease",
136 AdjustAction::Circle => "circle",
137 }
138 }
139}
140
141pub enum CronType {
142 PowerOff,
143}
144
145pub enum CfAction {
146 Recover,
147 Stay,
148 TurnOff,
149}
150
151pub enum Scene<'a, 'b> {
152 Color(&'a RGB, Brightness),
153 HSV(&'a HSV, Brightness),
154 Ct(Ct, Brightness),
155 Cf(&'b ColorFlow),
156
157 AutoDelayOff(Brightness, u16),
159}
160
161pub const MIN_AUTO_DELAY_OFF_MINUTES: u8 = 1;
162
163pub struct ColorFlow {
164 pub count: u16,
165 pub action: CfAction,
166 pub sequence: Vec<FlowTuple>,
167}
168
169pub struct Cron {
170 pub cron_type: CronType,
171 pub minutes: u16,
172}
173
174pub struct FlowTuple {
175 pub duration: Duration,
176 pub mode: FlowTupleMode,
177}
178
179pub struct ColorFlowTupleMode {
180 pub color: RGB,
181 pub brightness: Brightness,
182}
183
184pub type Ct = u16;
185pub type Brightness = u8;
186
187pub struct CtFlowTupleMode {
188 pub ct: Ct,
189 pub brightness: Brightness,
190}
191
192pub enum FlowTupleMode {
193 Color(ColorFlowTupleMode),
194 Ct(CtFlowTupleMode),
195 Sleep,
196}
197
198pub const MINIMUM_CF_DURATION: Duration = Duration::from_millis(50);
199
200pub enum PowerMode {
201 Ct = 1,
202 Rgb = 2,
203 Hsv = 3,
204 ColorFlow = 4,
205 NightLight = 5,
206}
207
208pub const MAX_BRIGHTNESS: u8 = 100;
209pub const MINIMUM_TRANSITION_DURATION: Duration = Duration::from_millis(30);
210pub const CT_MIN: u16 = 1700;
211pub const CT_MAX: u16 = 6500;
212
213pub enum TransitionMode {
214 Sudden,
215 Smooth(Duration),
216}