1use crate::{
2 api::HueAPIError,
3 command::{
4 merge_commands, BasicCommand, GeofenceClientCommand, GeolocationCommand, MotionCommand,
5 },
6 service::{Bridge, ResourceIdentifier, ResourceType, SetStatus},
7};
8use serde::{Deserialize, Serialize};
9
10#[derive(Debug)]
12pub struct Contact<'a> {
13 bridge: &'a Bridge,
14 data: ContactData,
15}
16
17impl<'a> Contact<'a> {
18 pub fn new(bridge: &'a Bridge, data: ContactData) -> Self {
19 Contact { bridge, data }
20 }
21
22 pub fn data(&self) -> &ContactData {
23 &self.data
24 }
25
26 pub fn id(&self) -> &str {
27 &self.data.id
28 }
29
30 pub fn rid(&self) -> ResourceIdentifier {
31 self.data.rid()
32 }
33
34 pub async fn send(
35 &self,
36 commands: &[BasicCommand],
37 ) -> Result<Vec<ResourceIdentifier>, HueAPIError> {
38 let payload = merge_commands(commands);
39 self.bridge.api.put_contact(self.id(), &payload).await
40 }
41}
42
43#[derive(Clone, Debug, Deserialize)]
45pub struct ContactData {
46 pub id: String,
48 pub id_v1: Option<String>,
50 pub owner: ResourceIdentifier,
52 pub enabled: bool,
54 pub contact_report: Option<ContactReport>,
55}
56
57impl ContactData {
58 pub fn rid(&self) -> ResourceIdentifier {
59 ResourceIdentifier {
60 rid: self.id.to_owned(),
61 rtype: ResourceType::Contact,
62 }
63 }
64}
65
66#[derive(Clone, Debug, Deserialize)]
67pub struct ContactReport {
68 pub changed: String,
70 pub state: ContactStatus,
71}
72
73#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq)]
74#[serde(rename_all = "snake_case")]
75pub enum ContactStatus {
76 Contact,
77 NoContact,
78}
79
80#[derive(Debug)]
82pub struct Motion<'a> {
83 bridge: &'a Bridge,
84 data: MotionData,
85}
86
87impl<'a> Motion<'a> {
88 pub fn new(bridge: &'a Bridge, data: MotionData) -> Self {
89 Motion { bridge, data }
90 }
91
92 pub fn data(&self) -> &MotionData {
93 &self.data
94 }
95
96 pub fn id(&self) -> &str {
97 &self.data.id
98 }
99
100 pub fn rid(&self) -> ResourceIdentifier {
101 ResourceIdentifier {
102 rid: self.id().to_owned(),
103 rtype: ResourceType::Motion,
104 }
105 }
106
107 pub async fn send(
108 &self,
109 commands: &[MotionCommand],
110 ) -> Result<Vec<ResourceIdentifier>, HueAPIError> {
111 let payload = merge_commands(commands);
112 self.bridge.api.put_motion(self.id(), &payload).await
113 }
114}
115
116#[derive(Debug)]
117pub struct CameraMotion<'a> {
118 bridge: &'a Bridge,
119 data: MotionData,
120}
121
122impl<'a> CameraMotion<'a> {
124 pub fn new(bridge: &'a Bridge, data: MotionData) -> Self {
125 CameraMotion { bridge, data }
126 }
127
128 pub fn data(&self) -> &MotionData {
129 &self.data
130 }
131
132 pub fn id(&self) -> &str {
133 &self.data.id
134 }
135
136 pub fn rid(&self) -> ResourceIdentifier {
137 ResourceIdentifier {
138 rid: self.id().to_owned(),
139 rtype: ResourceType::CameraMotion,
140 }
141 }
142
143 pub async fn send(
144 &self,
145 commands: &[MotionCommand],
146 ) -> Result<Vec<ResourceIdentifier>, HueAPIError> {
147 let payload = merge_commands(commands);
148 self.bridge.api.put_camera_motion(self.id(), &payload).await
149 }
150}
151
152#[derive(Clone, Debug, Deserialize)]
154pub struct MotionData {
155 pub id: String,
157 pub id_v1: Option<String>,
159 pub owner: ResourceIdentifier,
161 pub enabled: bool,
163 pub motion: MotionState,
164 pub sensitivity: Option<Sensitivity>,
165}
166
167#[derive(Clone, Debug, Deserialize)]
168pub struct MotionState {
169 #[deprecated]
171 pub motion_valid: bool,
172 pub motion_report: Option<MotionReport>,
173}
174
175#[derive(Clone, Debug, Deserialize)]
176pub struct MotionReport {
177 pub changed: String,
179 pub motion: bool,
181}
182
183#[derive(Clone, Debug, Deserialize)]
184pub struct Sensitivity {
185 pub status: SetStatus,
186 pub sensitivity: usize,
188 pub sensitivity_max: Option<usize>,
190}
191
192#[derive(Debug)]
194pub struct Temperature<'a> {
195 bridge: &'a Bridge,
196 data: TemperatureData,
197}
198
199impl<'a> Temperature<'a> {
200 pub fn new(bridge: &'a Bridge, data: TemperatureData) -> Self {
201 Temperature { bridge, data }
202 }
203
204 pub fn data(&self) -> &TemperatureData {
205 &self.data
206 }
207
208 pub fn id(&self) -> &str {
209 &self.data.id
210 }
211
212 pub fn rid(&self) -> ResourceIdentifier {
213 self.data.rid()
214 }
215
216 pub async fn send(
217 &self,
218 commands: &[BasicCommand],
219 ) -> Result<Vec<ResourceIdentifier>, HueAPIError> {
220 let payload = merge_commands(commands);
221 self.bridge.api.put_temperature(self.id(), &payload).await
222 }
223}
224
225#[derive(Clone, Debug, Deserialize)]
227pub struct TemperatureData {
228 pub id: String,
230 pub id_v1: Option<String>,
232 pub owner: ResourceIdentifier,
234 pub enabled: bool,
236 pub temperature: TemperatureState,
237}
238
239impl TemperatureData {
240 pub fn rid(&self) -> ResourceIdentifier {
241 ResourceIdentifier {
242 rid: self.id.to_owned(),
243 rtype: ResourceType::Temperature,
244 }
245 }
246}
247
248#[derive(Clone, Debug, Deserialize)]
249pub struct TemperatureState {
250 #[deprecated]
251 pub temperature: f32,
252 #[deprecated]
253 pub temperature_valid: bool,
254 pub temperature_report: Option<TemperatureReport>,
255}
256
257#[derive(Clone, Debug, Deserialize)]
258pub struct TemperatureReport {
259 pub changed: String,
261 pub temperature: f32,
262}
263
264#[derive(Debug)]
266pub struct LightLevel<'a> {
267 bridge: &'a Bridge,
268 data: LightLevelData,
269}
270
271impl<'a> LightLevel<'a> {
272 pub fn new(bridge: &'a Bridge, data: LightLevelData) -> Self {
273 LightLevel { bridge, data }
274 }
275
276 pub fn data(&self) -> &LightLevelData {
277 &self.data
278 }
279
280 pub fn id(&self) -> &str {
281 &self.data.id
282 }
283
284 pub fn rid(&self) -> ResourceIdentifier {
285 self.data.rid()
286 }
287
288 pub async fn send(
289 &self,
290 commands: &[BasicCommand],
291 ) -> Result<Vec<ResourceIdentifier>, HueAPIError> {
292 let payload = merge_commands(commands);
293 self.bridge.api.put_light_level(self.id(), &payload).await
294 }
295}
296
297#[derive(Clone, Debug, Deserialize)]
299pub struct LightLevelData {
300 pub id: String,
302 pub id_v1: Option<String>,
304 pub owner: ResourceIdentifier,
306 pub enabled: bool,
308 pub light: LightLevelState,
309}
310
311impl LightLevelData {
312 pub fn rid(&self) -> ResourceIdentifier {
313 ResourceIdentifier {
314 rid: self.id.to_owned(),
315 rtype: ResourceType::LightLevel,
316 }
317 }
318}
319
320#[derive(Clone, Debug, Deserialize)]
321pub struct LightLevelState {
322 #[deprecated]
323 pub light_level: usize,
324 #[deprecated]
325 pub light_level_valid: bool,
326 pub light_level_report: Option<LightLevelReport>,
327}
328
329#[derive(Clone, Debug, Deserialize)]
330pub struct LightLevelReport {
331 pub changed: String,
333 pub light_level: usize,
338}
339
340#[derive(Debug)]
342pub struct Geolocation<'a> {
343 bridge: &'a Bridge,
344 data: GeolocationData,
345}
346
347impl<'a> Geolocation<'a> {
348 pub fn new(bridge: &'a Bridge, data: GeolocationData) -> Self {
349 Geolocation { bridge, data }
350 }
351
352 pub fn data(&self) -> &GeolocationData {
353 &self.data
354 }
355
356 pub fn id(&self) -> &str {
357 &self.data.id
358 }
359
360 pub fn rid(&self) -> ResourceIdentifier {
361 self.data.rid()
362 }
363
364 pub async fn send(
365 &self,
366 commands: &[GeolocationCommand],
367 ) -> Result<Vec<ResourceIdentifier>, HueAPIError> {
368 let payload = merge_commands(commands);
369 self.bridge.api.put_geolocation(self.id(), &payload).await
370 }
371}
372
373#[derive(Clone, Debug, Deserialize)]
375pub struct GeolocationData {
376 pub id: String,
378 pub id_v1: Option<String>,
380 pub is_configured: bool,
382 pub sun_today: Option<SunToday>,
384}
385
386impl GeolocationData {
387 pub fn rid(&self) -> ResourceIdentifier {
388 ResourceIdentifier {
389 rid: self.id.to_owned(),
390 rtype: ResourceType::Geolocation,
391 }
392 }
393}
394
395#[derive(Clone, Debug, Deserialize)]
396pub struct SunToday {
397 pub sunset_time: String,
398 pub day_type: DayType,
399}
400
401#[derive(Clone, Debug, Deserialize)]
402#[serde(rename_all = "snake_case")]
403pub enum DayType {
404 NormalDay,
405 PolarDay,
406 PolarNight,
407 #[serde(other)]
408 Unknown,
409}
410
411#[derive(Debug)]
413pub struct GeofenceClient<'a> {
414 bridge: &'a Bridge,
415 data: GeofenceClientData,
416}
417
418impl<'a> GeofenceClient<'a> {
419 pub fn new(bridge: &'a Bridge, data: GeofenceClientData) -> Self {
420 GeofenceClient { bridge, data }
421 }
422
423 pub fn data(&self) -> &GeofenceClientData {
424 &self.data
425 }
426
427 pub fn id(&self) -> &str {
428 &self.data.id
429 }
430
431 pub fn rid(&self) -> ResourceIdentifier {
432 self.data.rid()
433 }
434
435 pub fn builder(name: impl Into<String>) -> GeofenceClientBuilder {
436 GeofenceClientBuilder::new(name)
437 }
438
439 pub async fn send(
440 &self,
441 commands: &[GeofenceClientCommand],
442 ) -> Result<Vec<ResourceIdentifier>, HueAPIError> {
443 let payload = merge_commands(commands);
444 self.bridge
445 .api
446 .put_geofence_client(self.id(), &payload)
447 .await
448 }
449}
450
451#[derive(Clone, Debug, Deserialize)]
453pub struct GeofenceClientData {
454 pub id: String,
456 pub id_v1: Option<String>,
458 pub name: String,
459}
460
461impl GeofenceClientData {
462 pub fn rid(&self) -> ResourceIdentifier {
463 ResourceIdentifier {
464 rid: self.id.to_owned(),
465 rtype: ResourceType::GeofenceClient,
466 }
467 }
468}
469
470#[derive(Serialize)]
471pub struct GeofenceClientBuilder {
472 is_at_home: bool,
473 name: String,
474}
475
476impl GeofenceClientBuilder {
477 pub fn new(name: impl Into<String>) -> Self {
478 GeofenceClientBuilder {
479 is_at_home: true,
480 name: name.into(),
481 }
482 }
483
484 pub fn is_at_home(mut self, b: bool) -> Self {
485 self.is_at_home = b;
486 self
487 }
488}
489
490#[derive(Debug)]
492pub struct Tamper {
493 data: TamperData,
494}
495
496impl Tamper {
497 pub fn new(data: TamperData) -> Self {
498 Tamper { data }
499 }
500
501 pub fn data(&self) -> &TamperData {
502 &self.data
503 }
504
505 pub fn id(&self) -> &str {
506 &self.data.id
507 }
508
509 pub fn rid(&self) -> ResourceIdentifier {
510 self.data.rid()
511 }
512}
513
514#[derive(Clone, Debug, Deserialize)]
516pub struct TamperData {
517 pub id: String,
519 pub id_v1: Option<String>,
521 pub owner: ResourceIdentifier,
523 pub tamper_reports: Vec<TamperReport>,
524}
525
526impl TamperData {
527 pub fn rid(&self) -> ResourceIdentifier {
528 ResourceIdentifier {
529 rid: self.id.to_owned(),
530 rtype: ResourceType::Tamper,
531 }
532 }
533}
534
535#[derive(Clone, Debug, Deserialize)]
536pub struct TamperReport {
537 pub changed: String,
539 pub source: String,
541 pub state: TamperStatus,
543}
544
545#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq)]
546#[serde(rename_all = "snake_case")]
547pub enum TamperStatus {
548 Tampered,
549 NotTampered,
550}