diff --git a/src/hue/api/mod.rs b/src/hue/api/mod.rs index 9efd1718..47635eb1 100644 --- a/src/hue/api/mod.rs +++ b/src/hue/api/mod.rs @@ -14,7 +14,7 @@ pub use light::{ DimmingUpdate, GamutType, Light, LightColor, LightUpdate, MirekSchema, On, }; pub use resource::{RType, ResourceLink, ResourceRecord}; -pub use room::{Room, RoomArchetype, RoomMetadata}; +pub use room::{Room, RoomArchetype, RoomMetadata, RoomMetadataUpdate, RoomUpdate}; pub use scene::{ Scene, SceneAction, SceneActionElement, SceneMetadata, SceneRecall, SceneStatus, SceneStatusUpdate, SceneUpdate, diff --git a/src/hue/api/room.rs b/src/hue/api/room.rs index 6080d73d..f6312ae0 100644 --- a/src/hue/api/room.rs +++ b/src/hue/api/room.rs @@ -1,14 +1,22 @@ +use std::ops::{AddAssign, Sub}; + use serde::{Deserialize, Serialize}; use crate::hue::api::{RType, ResourceLink}; -#[derive(Debug, Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] pub struct RoomMetadata { pub name: String, pub archetype: RoomArchetype, } -#[derive(Debug, Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone, Default)] +pub struct RoomMetadataUpdate { + pub name: Option, + pub archetype: Option, +} + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] pub struct Room { pub children: Vec, pub metadata: RoomMetadata, @@ -16,6 +24,12 @@ pub struct Room { pub services: Vec, } +#[derive(Debug, Serialize, Deserialize, Clone, Default)] +pub struct RoomUpdate { + pub children: Option>, + pub metadata: Option, +} + impl Room { #[must_use] pub fn grouped_light_service(&self) -> Option<&ResourceLink> { @@ -25,7 +39,25 @@ impl Room { } } -#[derive(Copy, Debug, Serialize, Deserialize, Clone)] +impl RoomUpdate { + #[must_use] + pub fn new() -> Self { + Self::default() + } + + #[must_use] + pub fn with_metadata(self, metadata: RoomMetadata) -> Self { + Self { + metadata: Some(RoomMetadataUpdate { + name: Some(metadata.name), + archetype: Some(metadata.archetype), + }), + ..self + } + } +} + +#[derive(Copy, Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] #[serde(rename_all = "snake_case")] pub enum RoomArchetype { LivingRoom, @@ -79,3 +111,54 @@ impl RoomMetadata { } } } + +impl AddAssign for RoomMetadata { + fn add_assign(&mut self, upd: RoomMetadataUpdate) { + if let Some(name) = upd.name { + self.name = name; + } + if let Some(archetype) = upd.archetype { + self.archetype = archetype; + } + } +} + +#[allow(clippy::if_not_else)] +impl Sub<&RoomMetadata> for &RoomMetadata { + type Output = RoomMetadataUpdate; + + fn sub(self, rhs: &RoomMetadata) -> Self::Output { + let mut upd = Self::Output::default(); + + if self != rhs { + if self.name != rhs.name { + upd.name = Some(rhs.name.clone()); + } + if self.archetype != rhs.archetype { + upd.archetype = Some(rhs.archetype); + } + } + + upd + } +} + +#[allow(clippy::if_not_else)] +impl Sub<&Room> for &Room { + type Output = RoomUpdate; + + fn sub(self, rhs: &Room) -> Self::Output { + let mut upd = Self::Output::default(); + + if self != rhs { + if self.children != rhs.children { + upd.children = Some(rhs.children.clone()); + } + if self.metadata != rhs.metadata { + upd.metadata = Some(&self.metadata - &rhs.metadata); + } + } + + upd + } +} diff --git a/src/hue/api/update.rs b/src/hue/api/update.rs index 584d59e8..4d3ad74b 100644 --- a/src/hue/api/update.rs +++ b/src/hue/api/update.rs @@ -1,7 +1,9 @@ use serde::{Deserialize, Serialize}; use uuid::Uuid; -use crate::hue::api::{DeviceUpdate, GroupedLightUpdate, LightUpdate, RType, SceneUpdate}; +use crate::hue::api::{ + DeviceUpdate, GroupedLightUpdate, LightUpdate, RType, RoomUpdate, SceneUpdate, +}; #[derive(Debug, Serialize, Deserialize, Clone)] #[serde(tag = "type", rename_all = "snake_case")] @@ -19,7 +21,7 @@ pub enum Update { Light(LightUpdate), /* Matter(MatterUpdate), */ /* PublicImage(PublicImageUpdate), */ - /* Room(RoomUpdate), */ + Room(RoomUpdate), Scene(SceneUpdate), /* SmartScene(SmartSceneUpdate), */ /* ZigbeeConnectivity(ZigbeeConnectivityUpdate), */ @@ -34,6 +36,7 @@ impl Update { Self::GroupedLight(_) => RType::GroupedLight, Self::Device(_) => RType::Device, Self::Light(_) => RType::Light, + Self::Room(_) => RType::Room, Self::Scene(_) => RType::Scene, } } @@ -41,7 +44,7 @@ impl Update { #[must_use] pub fn id_v1_scope(&self, id: u32, uuid: &Uuid) -> Option { match self { - Self::GroupedLight(_) => Some(format!("/groups/{id}")), + Self::Room(_) | Self::GroupedLight(_) => Some(format!("/groups/{id}")), Self::Device(_) => Some(format!("/device/{id}")), Self::Light(_) => Some(format!("/lights/{id}")), Self::Scene(_) => Some(format!("/scenes/{uuid}")), diff --git a/src/resource.rs b/src/resource.rs index 6f672641..f14a0827 100644 --- a/src/resource.rs +++ b/src/resource.rs @@ -10,8 +10,8 @@ use uuid::Uuid; use crate::error::{ApiError, ApiResult}; use crate::hue::api::{ Bridge, BridgeHome, Device, DeviceArchetype, DeviceProductData, DeviceUpdate, Metadata, RType, - Resource, ResourceLink, ResourceRecord, TimeZone, ZigbeeConnectivity, ZigbeeConnectivityStatus, - ZigbeeDeviceDiscovery, + Resource, ResourceLink, ResourceRecord, RoomUpdate, TimeZone, ZigbeeConnectivity, + ZigbeeConnectivityStatus, ZigbeeDeviceDiscovery, }; use crate::hue::api::{GroupedLightUpdate, LightUpdate, SceneUpdate, Update}; use crate::hue::event::EventBlock; @@ -104,7 +104,11 @@ impl Resources { Ok(Some(Update::Device(upd))) } - Resource::Room(_) => Ok(None), + Resource::Room(room) => { + let upd = RoomUpdate::new().with_metadata(room.metadata.clone()); + + Ok(Some(Update::Room(upd))) + } obj => Err(ApiError::UpdateUnsupported(obj.rtype())), } }