1use serde::{Deserialize, Serialize};
2use serde_json::json;
3use tokio_tungstenite::tungstenite::protocol::Message;
4
5use crate::error::{ObnizError, ObnizResult};
6use crate::obniz::Obniz;
7
8#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10#[serde(rename_all = "lowercase")]
11pub enum SwitchState {
12 None,
13 Push,
14 Left,
15 Right,
16}
17
18impl std::fmt::Display for SwitchState {
19 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20 match self {
21 SwitchState::None => write!(f, "none"),
22 SwitchState::Push => write!(f, "push"),
23 SwitchState::Left => write!(f, "left"),
24 SwitchState::Right => write!(f, "right"),
25 }
26 }
27}
28
29#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
31#[serde(rename_all = "lowercase")]
32pub enum SwitchAction {
33 Get,
34 Push,
35 Release,
36 Left,
37 Right,
38}
39
40#[derive(Debug, Clone, Serialize, Deserialize)]
42pub struct SwitchResponse {
43 pub state: SwitchState,
44 pub action: SwitchAction,
45}
46
47#[derive(Debug, Clone)]
49pub struct SwitchManager {
50 obniz: Obniz,
51}
52
53impl SwitchManager {
54 pub fn new(obniz: Obniz) -> Self {
55 Self { obniz }
56 }
57
58 pub async fn get_state(&self) -> ObnizResult<SwitchState> {
60 let request = json!([{"switch": "get"}]);
61 let message = Message::from(request.to_string());
62
63 let response = self
64 .obniz
65 .send_await_response(message, "switch".to_string())
66 .await
67 .map_err(|e| ObnizError::Connection(e.to_string()))?;
68
69 if let Some(array) = response.as_array() {
72 if let Some(first_item) = array.first() {
73 if let Some(switch_data) = first_item.get("switch") {
74 if let Some(state_value) = switch_data.get("state") {
75 return serde_json::from_value(state_value.clone())
76 .map_err(|e| ObnizError::JsonParse(e.to_string()));
77 }
78 }
79 }
80 }
81
82 if let Some(switch_data) = response.get("switch") {
84 if let Some(state_value) = switch_data.get("state") {
85 serde_json::from_value(state_value.clone())
86 .map_err(|e| ObnizError::JsonParse(e.to_string()))
87 } else {
88 Err(ObnizError::Generic(
89 "No state field in switch response".to_string(),
90 ))
91 }
92 } else {
93 Err(ObnizError::Generic(
94 "No switch data in response".to_string(),
95 ))
96 }
97 }
98
99 pub async fn is_pressed(&self) -> ObnizResult<bool> {
101 let state = self.get_state().await?;
102 Ok(state != SwitchState::None)
103 }
104
105 pub async fn is_pressed_direction(&self, direction: SwitchState) -> ObnizResult<bool> {
107 let state = self.get_state().await?;
108 Ok(state == direction)
109 }
110
111 pub async fn on_change<F>(&self, callback: F) -> ObnizResult<()>
113 where
114 F: Fn(SwitchState, SwitchAction) + Send + Sync + 'static,
115 {
116 self.obniz
117 .register_callback("switch".to_string(), move |response| {
118 if let Some(switch_data) = response.get("switch") {
119 if let Ok(switch_response) =
120 serde_json::from_value::<SwitchResponse>(switch_data.clone())
121 {
122 callback(switch_response.state, switch_response.action);
123 }
124 }
125 })
126 .map_err(|e| ObnizError::CallbackError(e.to_string()))?;
127
128 Ok(())
129 }
130
131 pub async fn on_push<F>(&self, callback: F) -> ObnizResult<()>
133 where
134 F: Fn() + Send + Sync + 'static,
135 {
136 self.on_change(move |state, action| {
137 if state == SwitchState::Push && action == SwitchAction::Push {
138 callback();
139 }
140 })
141 .await
142 }
143
144 pub async fn on_release<F>(&self, callback: F) -> ObnizResult<()>
146 where
147 F: Fn() + Send + Sync + 'static,
148 {
149 self.on_change(move |state, action| {
150 if state == SwitchState::None && action == SwitchAction::Release {
151 callback();
152 }
153 })
154 .await
155 }
156
157 pub async fn on_left<F>(&self, callback: F) -> ObnizResult<()>
159 where
160 F: Fn() + Send + Sync + 'static,
161 {
162 self.on_change(move |state, action| {
163 if state == SwitchState::Left && action == SwitchAction::Left {
164 callback();
165 }
166 })
167 .await
168 }
169
170 pub async fn on_right<F>(&self, callback: F) -> ObnizResult<()>
172 where
173 F: Fn() + Send + Sync + 'static,
174 {
175 self.on_change(move |state, action| {
176 if state == SwitchState::Right && action == SwitchAction::Right {
177 callback();
178 }
179 })
180 .await
181 }
182
183 pub async fn on_any_press<F>(&self, callback: F) -> ObnizResult<()>
185 where
186 F: Fn(SwitchState) + Send + Sync + 'static,
187 {
188 self.on_change(move |state, _action| {
189 if state != SwitchState::None {
190 callback(state.clone());
191 }
192 })
193 .await
194 }
195
196 pub fn remove_callback(&self) -> ObnizResult<()> {
198 self.obniz
199 .unregister_callback("switch".to_string())
200 .map_err(|e| ObnizError::CallbackError(e.to_string()))
201 }
202
203 pub async fn wait_for_state(
205 &self,
206 target_state: SwitchState,
207 timeout_ms: Option<u64>,
208 ) -> ObnizResult<()> {
209 use tokio::time::{sleep, timeout, Duration};
210
211 let check_interval = Duration::from_millis(50);
212 let max_duration = timeout_ms.map(Duration::from_millis);
213
214 let wait_future = async {
215 loop {
216 let current_state = self.get_state().await?;
217 if current_state == target_state {
218 return Ok(());
219 }
220 sleep(check_interval).await;
221 }
222 };
223
224 match max_duration {
225 Some(duration) => timeout(duration, wait_future)
226 .await
227 .map_err(|_| ObnizError::Timeout)?,
228 None => wait_future.await,
229 }
230 }
231
232 pub async fn wait_for_press(&self, timeout_ms: Option<u64>) -> ObnizResult<SwitchState> {
234 use tokio::time::{sleep, timeout, Duration};
235
236 let check_interval = Duration::from_millis(50);
237 let max_duration = timeout_ms.map(Duration::from_millis);
238
239 let wait_future = async {
240 loop {
241 let current_state = self.get_state().await?;
242 if current_state != SwitchState::None {
243 return Ok(current_state);
244 }
245 sleep(check_interval).await;
246 }
247 };
248
249 match max_duration {
250 Some(duration) => timeout(duration, wait_future)
251 .await
252 .map_err(|_| ObnizError::Timeout)?,
253 None => wait_future.await,
254 }
255 }
256
257 pub async fn wait_for_release(&self, timeout_ms: Option<u64>) -> ObnizResult<()> {
259 self.wait_for_state(SwitchState::None, timeout_ms).await
260 }
261}
262
263#[cfg(test)]
264mod tests {
265 use super::*;
266
267 #[test]
268 fn test_switch_state_serialization() {
269 use serde_json;
270
271 assert_eq!(
272 serde_json::to_string(&SwitchState::None).unwrap(),
273 "\"none\""
274 );
275 assert_eq!(
276 serde_json::to_string(&SwitchState::Push).unwrap(),
277 "\"push\""
278 );
279 assert_eq!(
280 serde_json::to_string(&SwitchState::Left).unwrap(),
281 "\"left\""
282 );
283 assert_eq!(
284 serde_json::to_string(&SwitchState::Right).unwrap(),
285 "\"right\""
286 );
287 }
288
289 #[test]
290 fn test_switch_state_deserialization() {
291 use serde_json;
292
293 assert_eq!(
294 serde_json::from_str::<SwitchState>("\"none\"").unwrap(),
295 SwitchState::None
296 );
297 assert_eq!(
298 serde_json::from_str::<SwitchState>("\"push\"").unwrap(),
299 SwitchState::Push
300 );
301 assert_eq!(
302 serde_json::from_str::<SwitchState>("\"left\"").unwrap(),
303 SwitchState::Left
304 );
305 assert_eq!(
306 serde_json::from_str::<SwitchState>("\"right\"").unwrap(),
307 SwitchState::Right
308 );
309 }
310
311 #[test]
312 fn test_switch_action_serialization() {
313 use serde_json;
314
315 assert_eq!(
316 serde_json::to_string(&SwitchAction::Get).unwrap(),
317 "\"get\""
318 );
319 assert_eq!(
320 serde_json::to_string(&SwitchAction::Push).unwrap(),
321 "\"push\""
322 );
323 assert_eq!(
324 serde_json::to_string(&SwitchAction::Release).unwrap(),
325 "\"release\""
326 );
327 assert_eq!(
328 serde_json::to_string(&SwitchAction::Left).unwrap(),
329 "\"left\""
330 );
331 assert_eq!(
332 serde_json::to_string(&SwitchAction::Right).unwrap(),
333 "\"right\""
334 );
335 }
336
337 #[test]
338 fn test_switch_response_serialization() {
339 use serde_json;
340
341 let response = SwitchResponse {
342 state: SwitchState::Push,
343 action: SwitchAction::Push,
344 };
345
346 let serialized = serde_json::to_string(&response).unwrap();
347 assert!(serialized.contains("\"state\":\"push\""));
348 assert!(serialized.contains("\"action\":\"push\""));
349 }
350
351 #[test]
352 fn test_switch_response_deserialization() {
353 use serde_json;
354
355 let json_str = r#"{"state": "left", "action": "left"}"#;
356 let response: SwitchResponse = serde_json::from_str(json_str).unwrap();
357
358 assert_eq!(response.state, SwitchState::Left);
359 assert_eq!(response.action, SwitchAction::Left);
360 }
361
362 #[test]
363 fn test_switch_state_display() {
364 assert_eq!(format!("{}", SwitchState::None), "none");
365 assert_eq!(format!("{}", SwitchState::Push), "push");
366 assert_eq!(format!("{}", SwitchState::Left), "left");
367 assert_eq!(format!("{}", SwitchState::Right), "right");
368 }
369
370 #[test]
371 fn test_switch_state_equality() {
372 assert_eq!(SwitchState::None, SwitchState::None);
373 assert_eq!(SwitchState::Push, SwitchState::Push);
374 assert_ne!(SwitchState::None, SwitchState::Push);
375 assert_ne!(SwitchState::Left, SwitchState::Right);
376 }
377}