ascom_alpaca/api/
switch.rs1use super::Device;
2use crate::{ASCOMError, ASCOMResult};
3use macro_rules_attribute::apply;
4
5#[apply(rpc_trait)]
7pub trait Switch: Device + Send + Sync {
8 #[http("maxswitch", method = Get)]
12 async fn max_switch(&self) -> ASCOMResult<i32>;
13
14 #[http("canasync", method = Get)]
18 async fn can_async(&self, #[http("Id")] id: i32) -> ASCOMResult<bool> {
19 Ok(false)
20 }
21
22 #[http("canwrite", method = Get)]
26 async fn can_write(&self, #[http("Id")] id: i32) -> ASCOMResult<bool> {
27 Ok(false)
28 }
29
30 #[http("getswitch", method = Get )]
32 async fn get_switch(&self, #[http("Id")] id: i32) -> ASCOMResult<bool>;
33
34 #[http("getswitchdescription", method = Get)]
38 async fn get_switch_description(&self, #[http("Id")] id: i32) -> ASCOMResult<String>;
39
40 #[http("getswitchname", method = Get)]
44 async fn get_switch_name(&self, #[http("Id")] id: i32) -> ASCOMResult<String>;
45
46 #[http("getswitchvalue", method = Get )]
50 async fn get_switch_value(&self, #[http("Id")] id: i32) -> ASCOMResult<f64>;
51
52 #[http("minswitchvalue", method = Get)]
56 async fn min_switch_value(&self, #[http("Id")] id: i32) -> ASCOMResult<f64>;
57
58 #[http("maxswitchvalue", method = Get)]
62 async fn max_switch_value(&self, #[http("Id")] id: i32) -> ASCOMResult<f64>;
63
64 #[http("setasync", method = Put)]
68 async fn set_async(
69 &self,
70 #[http("Id")] id: i32,
71 #[http("State")] state: bool,
72 ) -> ASCOMResult<()> {
73 Err(ASCOMError::NOT_IMPLEMENTED)
74 }
75
76 #[http("setasyncvalue", method = Put)]
80 async fn set_async_value(
81 &self,
82
83 #[http("Id")] id: i32,
84
85 #[http("Value")] value: f64,
86 ) -> ASCOMResult<()> {
87 Err(ASCOMError::NOT_IMPLEMENTED)
88 }
89
90 #[http("setswitch", method = Put)]
92 async fn set_switch(
93 &self,
94 #[http("Id")] id: i32,
95 #[http("State")] state: bool,
96 ) -> ASCOMResult<()> {
97 Err(ASCOMError::NOT_IMPLEMENTED)
98 }
99
100 #[http("setswitchname", method = Put)]
102 async fn set_switch_name(
103 &self,
104
105 #[http("Id")] id: i32,
106
107 #[http("Name")] name: String,
108 ) -> ASCOMResult<()> {
109 Err(ASCOMError::NOT_IMPLEMENTED)
110 }
111
112 #[http("setswitchvalue", method = Put)]
114 async fn set_switch_value(
115 &self,
116
117 #[http("Id")] id: i32,
118
119 #[http("Value")] value: f64,
120 ) -> ASCOMResult<()> {
121 Err(ASCOMError::NOT_IMPLEMENTED)
122 }
123
124 #[http("statechangecomplete", method = Get )]
128 async fn state_change_complete(&self, #[http("Id")] id: i32) -> ASCOMResult<bool>;
129
130 #[http("switchstep", method = Get)]
134 async fn switch_step(&self, #[http("Id")] id: i32) -> ASCOMResult<f64>;
135
136 #[http("interfaceversion", method = Get)]
140 async fn interface_version(&self) -> ASCOMResult<i32> {
141 Ok(3_i32)
142 }
143}
144
145#[derive(Default, Debug, Clone, Copy)]
147pub struct SwitchDeviceState {
148 pub get_switch: Option<bool>,
150 pub get_switch_value: Option<f64>,
152 pub state_change_complete: Option<bool>,
154}
155
156impl SwitchDeviceState {
157 async fn new(switch: &(impl ?Sized + Switch), id: i32) -> Self {
158 Self {
159 get_switch: switch.get_switch(id).await.ok(),
160 get_switch_value: switch.get_switch_value(id).await.ok(),
161 state_change_complete: switch.state_change_complete(id).await.ok(),
162 }
163 }
164}
165
166#[derive(Default, Debug, Clone)]
168pub struct DeviceState {
169 pub switch_devices: Vec<SwitchDeviceState>,
171}
172
173impl DeviceState {
174 async fn new(switch: &(impl ?Sized + Switch)) -> Self {
175 Self {
176 switch_devices: match switch.max_switch().await {
177 Ok(n) => {
178 futures::future::join_all(
179 (0_i32..n).map(|id| SwitchDeviceState::new(switch, id)),
180 )
181 .await
182 }
183 Err(err) => {
184 tracing::error!(%err, "Failed to get max switch");
185 Vec::new()
186 }
187 },
188 }
189 }
190}
191
192#[cfg(feature = "server")]
193impl serde::Serialize for DeviceState {
194 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
195 use serde::ser::SerializeMap;
196
197 let mut map = serializer.serialize_map(None)?;
198 for (i, device) in self.switch_devices.iter().enumerate() {
199 if let Some(value) = &device.get_switch {
200 map.serialize_entry(&format!("GetSwitch{i}"), value)?;
201 }
202 if let Some(value) = &device.get_switch_value {
203 map.serialize_entry(&format!("GetSwitchValue{i}"), value)?;
204 }
205 if let Some(value) = &device.state_change_complete {
206 map.serialize_entry(&format!("StateChangeComplete{i}"), value)?;
207 }
208 }
209 map.end()
210 }
211}
212
213#[cfg(feature = "client")]
214impl<'de> serde::Deserialize<'de> for DeviceState {
215 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
216 use serde::de;
217
218 struct Visitor;
219
220 impl<'de> de::Visitor<'de> for Visitor {
221 type Value = DeviceState;
222
223 fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
224 formatter.write_str("device state object")
225 }
226
227 fn visit_map<A: de::MapAccess<'de>>(self, mut map: A) -> Result<Self::Value, A::Error> {
228 let mut state = DeviceState::default();
229
230 while let Some(name) = map.next_key::<&'de str>()? {
231 let index_start = name.find(|c: char| c.is_ascii_digit()).ok_or_else(|| {
233 de::Error::custom(format!("could not find switch device index in {name:?}"))
234 })?;
235 let (name, index) = name.split_at(index_start);
236 let index = index.parse::<usize>().map_err(|err| {
237 de::Error::custom(format_args!(
238 "could not parse switch device index {index:?}: {err}"
239 ))
240 })?;
241 if index >= state.switch_devices.len() {
244 state
245 .switch_devices
246 .resize_with(index + 1, SwitchDeviceState::default);
247 }
248 let switch_device = &mut state.switch_devices[index];
249 match name {
250 "GetSwitch" => {
251 switch_device.get_switch = Some(map.next_value()?);
252 }
253 "GetSwitchValue" => {
254 switch_device.get_switch_value = Some(map.next_value()?);
255 }
256 "StateChangeComplete" => {
257 switch_device.state_change_complete = Some(map.next_value()?);
258 }
259 other => {
260 return Err(de::Error::unknown_field(
261 other,
262 &["GetSwitch", "GetSwitchValue", "StateChangeComplete"],
263 ));
264 }
265 }
266 }
267
268 Ok(state)
269 }
270 }
271
272 deserializer.deserialize_map(Visitor)
273 }
274}