1#![allow(clippy::too_many_arguments)]
7
8use anyhow;
9use serde_json;
10
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
15#[repr(u8)]
16pub enum ErrorState {
17 Noerror = 0,
19 Unabletostartorresume = 1,
21 Unabletocompleteoperation = 2,
23 Commandinvalidinstate = 3,
25 Failedtofindchargingdock = 64,
27 Stuck = 65,
29 Dustbinmissing = 66,
31 Dustbinfull = 67,
33 Watertankempty = 68,
35 Watertankmissing = 69,
37 Watertanklidopen = 70,
39 Mopcleaningpadmissing = 71,
41 Lowbattery = 72,
43 Cannotreachtargetarea = 73,
45 Dirtywatertankfull = 74,
47 Dirtywatertankmissing = 75,
49 Wheelsjammed = 76,
51 Brushjammed = 77,
53 Navigationsensorobscured = 78,
55}
56
57impl ErrorState {
58 pub fn from_u8(value: u8) -> Option<Self> {
60 match value {
61 0 => Some(ErrorState::Noerror),
62 1 => Some(ErrorState::Unabletostartorresume),
63 2 => Some(ErrorState::Unabletocompleteoperation),
64 3 => Some(ErrorState::Commandinvalidinstate),
65 64 => Some(ErrorState::Failedtofindchargingdock),
66 65 => Some(ErrorState::Stuck),
67 66 => Some(ErrorState::Dustbinmissing),
68 67 => Some(ErrorState::Dustbinfull),
69 68 => Some(ErrorState::Watertankempty),
70 69 => Some(ErrorState::Watertankmissing),
71 70 => Some(ErrorState::Watertanklidopen),
72 71 => Some(ErrorState::Mopcleaningpadmissing),
73 72 => Some(ErrorState::Lowbattery),
74 73 => Some(ErrorState::Cannotreachtargetarea),
75 74 => Some(ErrorState::Dirtywatertankfull),
76 75 => Some(ErrorState::Dirtywatertankmissing),
77 76 => Some(ErrorState::Wheelsjammed),
78 77 => Some(ErrorState::Brushjammed),
79 78 => Some(ErrorState::Navigationsensorobscured),
80 _ => None,
81 }
82 }
83
84 pub fn to_u8(self) -> u8 {
86 self as u8
87 }
88}
89
90impl From<ErrorState> for u8 {
91 fn from(val: ErrorState) -> Self {
92 val as u8
93 }
94}
95
96#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
97#[repr(u8)]
98pub enum OperationalState {
99 Stopped = 0,
101 Running = 1,
103 Paused = 2,
105 Error = 3,
107 Seekingcharger = 64,
109 Charging = 65,
111 Docked = 66,
113 Emptyingdustbin = 67,
115 Cleaningmop = 68,
117 Fillingwatertank = 69,
119 Updatingmaps = 70,
121}
122
123impl OperationalState {
124 pub fn from_u8(value: u8) -> Option<Self> {
126 match value {
127 0 => Some(OperationalState::Stopped),
128 1 => Some(OperationalState::Running),
129 2 => Some(OperationalState::Paused),
130 3 => Some(OperationalState::Error),
131 64 => Some(OperationalState::Seekingcharger),
132 65 => Some(OperationalState::Charging),
133 66 => Some(OperationalState::Docked),
134 67 => Some(OperationalState::Emptyingdustbin),
135 68 => Some(OperationalState::Cleaningmop),
136 69 => Some(OperationalState::Fillingwatertank),
137 70 => Some(OperationalState::Updatingmaps),
138 _ => None,
139 }
140 }
141
142 pub fn to_u8(self) -> u8 {
144 self as u8
145 }
146}
147
148impl From<OperationalState> for u8 {
149 fn from(val: OperationalState) -> Self {
150 val as u8
151 }
152}
153
154pub fn get_command_list() -> Vec<(u32, &'static str)> {
159 vec![
160 (0x00, "Pause"),
161 (0x01, "Stop"),
162 (0x02, "Start"),
163 (0x03, "Resume"),
164 (0x04, "OperationalCommandResponse"),
165 (0x80, "GoHome"),
166 ]
167}
168
169pub fn get_command_name(cmd_id: u32) -> Option<&'static str> {
170 match cmd_id {
171 0x00 => Some("Pause"),
172 0x01 => Some("Stop"),
173 0x02 => Some("Start"),
174 0x03 => Some("Resume"),
175 0x04 => Some("OperationalCommandResponse"),
176 0x80 => Some("GoHome"),
177 _ => None,
178 }
179}
180
181pub fn get_command_schema(cmd_id: u32) -> Option<Vec<crate::clusters::codec::CommandField>> {
182 match cmd_id {
183 0x00 => Some(vec![]),
184 0x01 => Some(vec![]),
185 0x02 => Some(vec![]),
186 0x03 => Some(vec![]),
187 0x04 => Some(vec![]),
188 0x80 => Some(vec![]),
189 _ => None,
190 }
191}
192
193pub fn encode_command_json(cmd_id: u32, _args: &serde_json::Value) -> anyhow::Result<Vec<u8>> {
194 match cmd_id {
195 0x00 => Ok(vec![]),
196 0x01 => Ok(vec![]),
197 0x02 => Ok(vec![]),
198 0x03 => Ok(vec![]),
199 0x04 => Ok(vec![]),
200 0x80 => Ok(vec![]),
201 _ => Err(anyhow::anyhow!("unknown command ID: 0x{:02X}", cmd_id)),
202 }
203}
204
205pub async fn pause(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<()> {
209 conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_RVC_OPERATIONAL_STATE, crate::clusters::defs::CLUSTER_RVC_OPERATIONAL_STATE_CMD_ID_PAUSE, &[]).await?;
210 Ok(())
211}
212
213pub async fn stop(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<()> {
215 conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_RVC_OPERATIONAL_STATE, crate::clusters::defs::CLUSTER_RVC_OPERATIONAL_STATE_CMD_ID_STOP, &[]).await?;
216 Ok(())
217}
218
219pub async fn start(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<()> {
221 conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_RVC_OPERATIONAL_STATE, crate::clusters::defs::CLUSTER_RVC_OPERATIONAL_STATE_CMD_ID_START, &[]).await?;
222 Ok(())
223}
224
225pub async fn resume(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<()> {
227 conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_RVC_OPERATIONAL_STATE, crate::clusters::defs::CLUSTER_RVC_OPERATIONAL_STATE_CMD_ID_RESUME, &[]).await?;
228 Ok(())
229}
230
231pub async fn operational_command_response(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<()> {
233 conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_RVC_OPERATIONAL_STATE, crate::clusters::defs::CLUSTER_RVC_OPERATIONAL_STATE_CMD_ID_OPERATIONALCOMMANDRESPONSE, &[]).await?;
234 Ok(())
235}
236
237pub async fn go_home(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<()> {
239 conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_RVC_OPERATIONAL_STATE, crate::clusters::defs::CLUSTER_RVC_OPERATIONAL_STATE_CMD_ID_GOHOME, &[]).await?;
240 Ok(())
241}
242