1use crate::errors;
2use crate::types;
3use serde::{Deserialize, Serialize};
4use std::convert::TryFrom;
5use std::sync::{Arc, RwLock, Weak};
6
7#[derive(Debug)]
8pub struct Rest {
9 ha_client: Arc<RwLock<crate::HomeAssistantAPI>>,
10}
11
12impl Rest {
13 pub async fn check(self) -> Result<String, errors::Error> {
14 let mut read_lock = self.ha_client.read().unwrap();
15 if read_lock.token.need_refresh() {
16 drop(read_lock);
17 let mut write_lock = self.ha_client.write().unwrap();
18 write_lock.refresh_oauth_token().await?;
19 read_lock = self.ha_client.read().unwrap();
20 }
21
22 let endpoint = format!("{}/api/config", read_lock.instance_url);
23 let request = reqwest::Client::new()
24 .get(endpoint.as_str())
25 .header(
26 "Authorization",
27 format!("Bearer {}", read_lock.token.as_string()?),
28 )
29 .header("content-type", "application/json");
30
31 drop(read_lock);
32 let response = request.send().await?;
33
34 #[derive(Serialize, Deserialize, Debug)]
35 struct Response {
36 message: String,
37 }
38
39 let resp_json: Response = response.json().await?;
40
41 Ok(resp_json.message)
42
43 }
45
46 pub async fn config(self) -> Result<types::Configuration, errors::Error> {
47 let mut read_lock = self.ha_client.read().unwrap();
48 if read_lock.token.need_refresh() {
49 drop(read_lock);
50 let mut write_lock = self.ha_client.write().unwrap();
51 write_lock.refresh_oauth_token().await?;
52 read_lock = self.ha_client.read().unwrap();
53 }
54
55 let endpoint = format!("{}/api/config", read_lock.instance_url);
56 let request = reqwest::Client::new()
57 .get(endpoint.as_str())
58 .header(
59 "Authorization",
60 format!("Bearer {}", read_lock.token.as_string()?),
61 )
62 .header("content-type", "application/json");
63
64 drop(read_lock);
65 let response = request.send().await?;
66
67 let resp_json: types::Configuration = response.json().await?;
68
69 Ok(resp_json)
70 }
71
72 pub async fn discovery_info(self) -> Result<types::DiscoveryInfo, errors::Error> {
73 let mut read_lock = self.ha_client.read().unwrap();
74 if read_lock.token.need_refresh() {
75 drop(read_lock);
76 let mut write_lock = self.ha_client.write().unwrap();
77 write_lock.refresh_oauth_token().await?;
78 read_lock = self.ha_client.read().unwrap();
79 }
80
81 let endpoint = format!("{}/api/discovery_info", read_lock.instance_url);
82 let request = reqwest::Client::new()
83 .get(endpoint.as_str())
84 .header(
85 "Authorization",
86 format!("Bearer {}", read_lock.token.as_string()?),
87 )
88 .header("content-type", "application/json");
89
90 drop(read_lock);
91 let response = request.send().await?;
92
93 let resp_json: types::DiscoveryInfo = response.json().await?;
94
95 Ok(resp_json)
96 }
97
98 pub async fn events(self) -> Result<Vec<types::EventObject>, errors::Error> {
99 let mut read_lock = self.ha_client.read().unwrap();
100 if read_lock.token.need_refresh() {
101 drop(read_lock);
102 let mut write_lock = self.ha_client.write().unwrap();
103 write_lock.refresh_oauth_token().await?;
104 read_lock = self.ha_client.read().unwrap();
105 }
106
107 let endpoint = format!("{}/api/events", read_lock.instance_url);
108 let request = reqwest::Client::new()
109 .get(endpoint.as_str())
110 .header(
111 "Authorization",
112 format!("Bearer {}", read_lock.token.as_string()?),
113 )
114 .header("content-type", "application/json");
115
116 drop(read_lock);
117 let response = request.send().await?;
118
119 let resp_json: Vec<types::EventObject> = response.json().await?;
120
121 Ok(resp_json)
122 }
123
124 pub async fn services(self) -> Result<Vec<types::ServiceObject>, errors::Error> {
125 let mut read_lock = self.ha_client.read().unwrap();
126 if read_lock.token.need_refresh() {
127 drop(read_lock);
128 let mut write_lock = self.ha_client.write().unwrap();
129 write_lock.refresh_oauth_token().await?;
130 read_lock = self.ha_client.read().unwrap();
131 }
132
133 let endpoint = format!("{}/api/services", read_lock.instance_url);
134 let request = reqwest::Client::new()
135 .get(endpoint.as_str())
136 .header(
137 "Authorization",
138 format!("Bearer {}", read_lock.token.as_string()?),
139 )
140 .header("content-type", "application/json");
141
142 drop(read_lock);
143 let response = request.send().await?;
144
145 let resp_json: Vec<types::ServiceObject> = response.json().await?;
146
147 Ok(resp_json)
148 }
149
150 pub async fn history_period(
151 self,
152 timestamp: Option<chrono::DateTime<chrono::Utc>>,
153 filter_entity_id: Option<String>,
154 end_time: Option<chrono::DateTime<chrono::Utc>>,
155 significant_changes_only: Option<bool>,
156 ) -> Result<Vec<types::StateObject>, errors::Error> {
157 let mut read_lock = self.ha_client.read().unwrap();
158 if read_lock.token.need_refresh() {
159 drop(read_lock);
160 let mut write_lock = self.ha_client.write().unwrap();
161 write_lock.refresh_oauth_token().await?;
162 read_lock = self.ha_client.read().unwrap();
163 }
164
165 let mut endpoint = format!("{}/api/history/period", read_lock.instance_url);
166
167 if let Some(timestamp) = timestamp {
168 let formatted_timestamp = timestamp.format("%Y-%m-%dT%H:%M:%S%:z").to_string();
169 endpoint = endpoint + &formatted_timestamp;
170 }
171
172 let mut request = reqwest::Client::new()
173 .get(endpoint.as_str())
174 .header(
175 "Authorization",
176 format!("Bearer {}", read_lock.token.as_string()?),
177 )
178 .header("content-type", "application/json");
179
180 drop(read_lock);
181
182 if let Some(filter_entity_id) = filter_entity_id {
183 request = request.query(&[("filter_entity_id", filter_entity_id)]);
184 }
185
186 if let Some(end_time) = end_time {
187 let formatted_timestamp = end_time.format("%Y-%m-%dT%H:%M:%S%:z").to_string();
188 request = request.query(&[("end_time", formatted_timestamp)]);
189 }
190
191 if significant_changes_only.is_some() {
192 request = request.query(&[("significant_changes_only")]);
193 }
194
195 let response = request.send().await?;
196
197 let resp_json: Vec<types::StateObject> = response.json().await?;
198
199 Ok(resp_json)
200 }
201
202 pub async fn history_period_minimal(
203 self,
204 timestamp: Option<chrono::DateTime<chrono::Utc>>,
205 filter_entity_id: Option<String>,
206 end_time: Option<chrono::DateTime<chrono::Utc>>,
207 significant_changes_only: Option<bool>,
208 ) -> Result<Vec<types::StateObject>, errors::Error> {
209 let mut read_lock = self.ha_client.read().unwrap();
210 if read_lock.token.need_refresh() {
211 drop(read_lock);
212 let mut write_lock = self.ha_client.write().unwrap();
213 write_lock.refresh_oauth_token().await?;
214 read_lock = self.ha_client.read().unwrap();
215 }
216
217 let mut endpoint = format!("{}/api/history/period", read_lock.instance_url);
218
219 if let Some(timestamp) = timestamp {
220 let formatted_timestamp = timestamp.format("%Y-%m-%dT%H:%M:%S%:z").to_string();
221 endpoint = endpoint + &formatted_timestamp;
222 }
223
224 let mut request = reqwest::Client::new()
225 .get(endpoint.as_str())
226 .header(
227 "Authorization",
228 format!("Bearer {}", read_lock.token.as_string()?),
229 )
230 .header("content-type", "application/json");
231
232 drop(read_lock);
233
234 if let Some(filter_entity_id) = filter_entity_id {
235 request = request.query(&[("filter_entity_id", filter_entity_id)]);
236 }
237
238 if let Some(end_time) = end_time {
239 let formatted_timestamp = end_time.format("%Y-%m-%dT%H:%M:%S%:z").to_string();
240 request = request.query(&[("end_time", formatted_timestamp)]);
241 }
242
243 if significant_changes_only.is_some() {
244 request = request.query(&[("significant_changes_only")]);
245 }
246
247 request = request.query(&[("minimal_response")]);
248
249 let response = request.send().await?;
250
251 let resp_json: Vec<types::StateObject> = response.json().await?;
252
253 Ok(resp_json)
254 }
255
256 pub async fn logbook(
257 self,
258 timestamp: Option<chrono::DateTime<chrono::Utc>>,
259 entity: String,
260 end_time: Option<chrono::DateTime<chrono::Utc>>,
261 ) -> Result<Vec<types::LogbookEntry>, errors::Error> {
262 let mut read_lock = self.ha_client.read().unwrap();
263 if read_lock.token.need_refresh() {
264 drop(read_lock);
265 let mut write_lock = self.ha_client.write().unwrap();
266 write_lock.refresh_oauth_token().await?;
267 read_lock = self.ha_client.read().unwrap();
268 }
269
270 let mut endpoint = format!("{}/api/logbook", read_lock.instance_url);
271
272 if let Some(timestamp) = timestamp {
273 let formatted_timestamp = timestamp.format("%Y-%m-%dT%H:%M:%S%:z").to_string();
274 endpoint = endpoint + &formatted_timestamp;
275 }
276
277 let mut request = reqwest::Client::new()
278 .get(endpoint.as_str())
279 .header(
280 "Authorization",
281 format!("Bearer {}", read_lock.token.as_string()?),
282 )
283 .header("content-type", "application/json");
284
285 drop(read_lock);
286
287 request = request.query(&[("entity", entity)]);
288
289 if let Some(end_time) = end_time {
290 let formatted_timestamp = end_time.format("%Y-%m-%dT%H:%M:%S%:z").to_string();
291 request = request.query(&[("end_time", formatted_timestamp)]);
292 }
293
294 let response = request.send().await?;
295
296 let resp_json: Vec<types::LogbookEntry> = response.json().await?;
297
298 Ok(resp_json)
299 }
300
301 pub async fn states(self) -> Result<Vec<types::StateObject>, errors::Error> {
302 let mut read_lock = self.ha_client.read().unwrap();
303 if read_lock.token.need_refresh() {
304 drop(read_lock);
305 let mut write_lock = self.ha_client.write().unwrap();
306 write_lock.refresh_oauth_token().await?;
307 read_lock = self.ha_client.read().unwrap();
308 }
309
310 let endpoint = format!("{}/api/states", read_lock.instance_url);
311 let request = reqwest::Client::new()
312 .get(endpoint.as_str())
313 .header(
314 "Authorization",
315 format!("Bearer {}", read_lock.token.as_string()?),
316 )
317 .header("content-type", "application/json");
318
319 drop(read_lock);
320 let response = request.send().await?;
321
322 let resp_json: Vec<types::StateObject> = response.json().await?;
323
324 Ok(resp_json)
325 }
326
327 pub async fn state_of(
328 self,
329 entity_id: String,
330 ) -> Result<Vec<types::StateObject>, errors::Error> {
331 let mut read_lock = self.ha_client.read().unwrap();
332 if read_lock.token.need_refresh() {
333 drop(read_lock);
334 let mut write_lock = self.ha_client.write().unwrap();
335 write_lock.refresh_oauth_token().await?;
336 read_lock = self.ha_client.read().unwrap();
337 }
338
339 let endpoint = format!("{}/api/states/{}", read_lock.instance_url, entity_id);
340 let request = reqwest::Client::new()
341 .get(endpoint.as_str())
342 .header(
343 "Authorization",
344 format!("Bearer {}", read_lock.token.as_string()?),
345 )
346 .header("content-type", "application/json");
347
348 drop(read_lock);
349 let response = request.send().await?;
350 let resp_json: Vec<types::StateObject> = response.json().await?;
351
352 Ok(resp_json)
353 }
354
355 pub async fn error_log(self) -> Result<String, errors::Error> {
356 let mut read_lock = self.ha_client.read().unwrap();
357 if read_lock.token.need_refresh() {
358 drop(read_lock);
359 let mut write_lock = self.ha_client.write().unwrap();
360 write_lock.refresh_oauth_token().await?;
361 read_lock = self.ha_client.read().unwrap();
362 }
363
364 let endpoint = format!("{}/api/error_log", read_lock.instance_url);
365 let request = reqwest::Client::new()
366 .get(endpoint.as_str())
367 .header(
368 "Authorization",
369 format!("Bearer {}", read_lock.token.as_string()?),
370 )
371 .header("content-type", "application/json");
372
373 drop(read_lock);
374 let response = request.send().await?;
375
376 let resp: String = response.text().await?;
377
378 Ok(resp)
379 }
380
381 pub async fn camera_proxy(self, camera_entity_id: String) -> Result<(), errors::Error> {
382 let mut read_lock = self.ha_client.read().unwrap();
383 if read_lock.token.need_refresh() {
384 drop(read_lock);
385 let mut write_lock = self.ha_client.write().unwrap();
386 write_lock.refresh_oauth_token().await?;
387 read_lock = self.ha_client.read().unwrap();
388 }
389
390 let endpoint = format!(
391 "{}/api/camera_proxy/{}",
392 read_lock.instance_url, camera_entity_id
393 );
394 let request = reqwest::Client::new()
395 .get(endpoint.as_str())
396 .header(
397 "Authorization",
398 format!("Bearer {}", read_lock.token.as_string()?),
399 )
400 .header("content-type", "application/json");
401
402 drop(read_lock);
403 let _response = request.send().await?;
404
405 Ok(())
406 }
407
408 pub async fn state_change(
409 self,
410 entity_id: String,
411 state_data: Option<impl serde::Serialize>,
412 ) -> Result<types::StateObject, errors::Error> {
413 let mut read_lock = self.ha_client.read().unwrap();
414 if read_lock.token.need_refresh() {
415 drop(read_lock);
416 let mut write_lock = self.ha_client.write().unwrap();
417 write_lock.refresh_oauth_token().await?;
418 read_lock = self.ha_client.read().unwrap();
419 }
420
421 let endpoint = format!("{}/api/states/{}", read_lock.instance_url, entity_id);
422 let mut request = reqwest::Client::new()
423 .post(endpoint.as_str())
424 .header(
425 "Authorization",
426 format!("Bearer {}", read_lock.token.as_string()?),
427 )
428 .header("content-type", "application/json");
429
430 drop(read_lock);
431
432 if let Some(data) = state_data {
433 request = request.json(&data);
434 }
435
436 let response = request.send().await?;
437
438 let resp_json: types::StateObject = response.json().await?;
439
440 Ok(resp_json)
441 }
442
443 pub async fn event_fire(
444 self,
445 event_type: String,
446 event_data: Option<impl serde::Serialize>,
447 ) -> Result<String, errors::Error> {
448 let mut read_lock = self.ha_client.read().unwrap();
449 if read_lock.token.need_refresh() {
450 drop(read_lock);
451 let mut write_lock = self.ha_client.write().unwrap();
452 write_lock.refresh_oauth_token().await?;
453 read_lock = self.ha_client.read().unwrap();
454 }
455
456 let endpoint = format!("{}/api/events/{}", read_lock.instance_url, event_type);
457 let mut request = reqwest::Client::new()
458 .post(endpoint.as_str())
459 .header(
460 "Authorization",
461 format!("Bearer {}", read_lock.token.as_string()?),
462 )
463 .header("content-type", "application/json");
464
465 drop(read_lock);
466
467 if let Some(data) = event_data {
468 request = request.json(&data);
469 }
470
471 let response = request.send().await?;
472
473 #[derive(Serialize, Deserialize, Debug)]
474 struct Response {
475 message: String,
476 }
477
478 let resp_json: Response = response.json().await?;
479
480 Ok(resp_json.message)
481 }
482
483 pub async fn service_call<T>(
484 self,
485 domain: String,
486 service: String,
487 service_data: Option<impl serde::Serialize>,
488 ) -> Result<Vec<types::StateObject>, errors::Error> {
489 let mut read_lock = self.ha_client.read().unwrap();
490 if read_lock.token.need_refresh() {
491 drop(read_lock);
492 let mut write_lock = self.ha_client.write().unwrap();
493 write_lock.refresh_oauth_token().await?;
494 read_lock = self.ha_client.read().unwrap();
495 }
496
497 let endpoint = format!(
498 "{}/api/services/{}/{}",
499 read_lock.instance_url, domain, service
500 );
501 let mut request = reqwest::Client::new()
502 .post(endpoint.as_str())
503 .header(
504 "Authorization",
505 format!("Bearer {}", read_lock.token.as_string()?),
506 )
507 .header("content-type", "application/json");
508
509 drop(read_lock);
510
511 if let Some(data) = service_data {
512 request = request.json(&data);
513 }
514
515 let response = request.send().await?;
516
517 let resp_json: Vec<types::StateObject> = response.json().await?;
518
519 Ok(resp_json)
520 }
521
522 pub async fn template_render(self, template: String) -> Result<String, errors::Error> {
523 let mut read_lock = self.ha_client.read().unwrap();
524 if read_lock.token.need_refresh() {
525 drop(read_lock);
526 let mut write_lock = self.ha_client.write().unwrap();
527 write_lock.refresh_oauth_token().await?;
528 read_lock = self.ha_client.read().unwrap();
529 }
530
531 let endpoint = format!("{}/api/template", read_lock.instance_url);
532
533 #[derive(Serialize, Deserialize, Debug)]
534 struct Template {
535 template: String,
536 }
537
538 let template_struct = Template { template };
539 let request = reqwest::Client::new()
540 .post(endpoint.as_str())
541 .header(
542 "Authorization",
543 format!("Bearer {}", read_lock.token.as_string()?),
544 )
545 .header("content-type", "application/json");
546
547 drop(read_lock);
548
549 let response = request.json(&template_struct).send().await?;
550
551 let resp: String = response.text().await?;
552
553 Ok(resp)
554 }
555
556 pub async fn check_config(self) -> Result<types::CheckConfig, errors::Error> {
557 let mut read_lock = self.ha_client.read().unwrap();
558 if read_lock.token.need_refresh() {
559 drop(read_lock);
560 let mut write_lock = self.ha_client.write().unwrap();
561 write_lock.refresh_oauth_token().await?;
562 read_lock = self.ha_client.read().unwrap();
563 }
564
565 let endpoint = format!("{}/api/config/core/check_config", read_lock.instance_url);
566 let response = reqwest::Client::new()
567 .post(endpoint.as_str())
568 .header(
569 "Authorization",
570 format!("Bearer {}", read_lock.token.as_string()?),
571 )
572 .header("content-type", "application/json")
573 .send()
574 .await?;
575
576 drop(read_lock);
577
578 let resp_json: types::CheckConfig = response.json().await?;
579
580 Ok(resp_json)
581 }
582}
583
584impl TryFrom<Weak<RwLock<crate::HomeAssistantAPI>>> for Rest {
585 type Error = errors::Error;
586
587 fn try_from(weak: Weak<RwLock<crate::HomeAssistantAPI>>) -> Result<Self, Self::Error> {
588 match weak.upgrade() {
589 Some(ptr) => Ok(Self { ha_client: ptr }),
590 None => Err(errors::Error::HaApi(String::from(
591 "Can't create Rest Client weak ptr returned none",
592 ))),
593 }
594 }
595}
596
597impl From<Arc<RwLock<crate::HomeAssistantAPI>>> for Rest {
598 fn from(ptr: Arc<RwLock<crate::HomeAssistantAPI>>) -> Self {
599 Self { ha_client: ptr }
600 }
601}