use crate::{
api::HueAPIError,
command::{merge_commands, ZoneCommand},
service::{Bridge, Device, Group, Light, ResourceIdentifier, ResourceType, Scene},
};
use serde::{Deserialize, Serialize};
#[derive(Debug)]
pub struct Zone<'a> {
bridge: &'a Bridge,
pub data: ZoneData,
}
impl<'a> Zone<'a> {
pub fn new(bridge: &'a Bridge, data: ZoneData) -> Self {
Zone { bridge, data }
}
pub fn data(&self) -> &ZoneData {
&self.data
}
pub fn id(&self) -> &str {
&self.data.id
}
pub fn rid(&self) -> ResourceIdentifier {
self.data.rid()
}
pub fn name(&self) -> &str {
&self.data.metadata.name
}
pub fn archetype(&self) -> ZoneArchetype {
self.data.metadata.archetype
}
pub fn devices(&self) -> Vec<Device> {
let rids = &self.data.children;
self.bridge
.devices()
.into_iter()
.filter_map(|d| {
if rids.contains(&d.rid()) {
Some(d)
} else {
None
}
})
.collect::<Vec<_>>()
}
pub fn lights(&self) -> Vec<Light> {
self.bridge
.lights()
.into_iter()
.filter(|l| self.data.children.contains(&l.data().owner))
.collect()
}
pub fn scenes(&self) -> Vec<Scene> {
self.bridge
.scenes()
.into_iter()
.filter(|s| self.rid() == s.group())
.collect()
}
pub fn group(&self) -> Option<Group> {
self.data
.services
.iter()
.find(|s| s.rtype == ResourceType::Group)
.map(|gid| {
self.bridge
.groups()
.into_iter()
.find(|g| g.rid() == *gid)
.unwrap()
})
}
pub async fn on(&self) -> Result<Vec<ResourceIdentifier>, HueAPIError> {
if let Some(group) = self.group() {
group.on().await
} else {
Ok(vec![])
}
}
pub async fn off(&self) -> Result<Vec<ResourceIdentifier>, HueAPIError> {
if let Some(group) = self.group() {
group.off().await
} else {
Ok(vec![])
}
}
pub async fn toggle(&self) -> Result<Vec<ResourceIdentifier>, HueAPIError> {
if let Some(group) = self.group() {
group.toggle().await
} else {
Ok(vec![])
}
}
pub fn builder(name: impl Into<String>, archetype: ZoneArchetype) -> ZoneBuilder {
ZoneBuilder::new(name, archetype)
}
pub async fn send(
&self,
commands: &[ZoneCommand],
) -> Result<Vec<ResourceIdentifier>, HueAPIError> {
let payload = merge_commands(commands);
self.bridge.api.put_zone(self.id(), &payload).await
}
}
#[derive(Debug, Clone)]
pub struct Room<'a> {
bridge: &'a Bridge,
pub data: ZoneData,
}
impl<'a> Room<'a> {
pub fn new(bridge: &'a Bridge, data: ZoneData) -> Self {
Room { bridge, data }
}
pub fn data(&self) -> &ZoneData {
&self.data
}
pub fn id(&self) -> &str {
&self.data.id
}
pub fn rid(&self) -> ResourceIdentifier {
ResourceIdentifier {
rid: self.id().to_owned(),
rtype: ResourceType::Room,
}
}
pub fn name(&self) -> &str {
&self.data.metadata.name
}
pub fn archetype(&self) -> ZoneArchetype {
self.data.metadata.archetype
}
pub fn devices(&self) -> Vec<Device> {
let rids = &self.data.children;
self.bridge
.devices()
.into_iter()
.filter_map(|d| {
if rids.contains(&d.rid()) {
Some(d)
} else {
None
}
})
.collect::<Vec<_>>()
}
pub fn lights(&self) -> Vec<Light> {
self.bridge
.lights()
.into_iter()
.filter(|l| self.data.children.contains(&l.data().owner))
.collect()
}
pub fn scenes(&self) -> Vec<Scene> {
self.bridge
.scenes()
.into_iter()
.filter(|s| self.rid() == s.group())
.collect()
}
pub fn group(&self) -> Option<Group> {
self.data
.services
.iter()
.find(|s| s.rtype == ResourceType::Group)
.map(|gid| {
self.bridge
.groups()
.into_iter()
.find(|g| g.rid() == *gid)
.unwrap()
})
}
pub async fn on(&self) -> Result<Vec<ResourceIdentifier>, HueAPIError> {
if let Some(group) = self.group() {
group.on().await
} else {
Ok(vec![])
}
}
pub async fn off(&self) -> Result<Vec<ResourceIdentifier>, HueAPIError> {
if let Some(group) = self.group() {
group.off().await
} else {
Ok(vec![])
}
}
pub async fn toggle(&self) -> Result<Vec<ResourceIdentifier>, HueAPIError> {
if let Some(group) = self.group() {
group.toggle().await
} else {
Ok(vec![])
}
}
pub fn builder(name: impl Into<String>, archetype: ZoneArchetype) -> ZoneBuilder {
ZoneBuilder::new(name, archetype)
}
pub async fn send(
&self,
commands: &[ZoneCommand],
) -> Result<Vec<ResourceIdentifier>, HueAPIError> {
let payload = merge_commands(commands);
self.bridge.api.put_room(self.id(), &payload).await
}
}
#[derive(Serialize)]
pub struct ZoneBuilder {
pub metadata: ZoneMetadata,
pub children: Vec<ResourceIdentifier>,
}
impl ZoneBuilder {
pub fn new(name: impl Into<String>, archetype: ZoneArchetype) -> Self {
ZoneBuilder {
metadata: ZoneMetadata {
name: name.into(),
archetype,
},
children: vec![],
}
}
pub fn children(mut self, children: Vec<ResourceIdentifier>) -> Self {
self.children = children;
self
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ZoneData {
pub id: String,
pub id_v1: Option<String>,
pub children: Vec<ResourceIdentifier>,
pub services: Vec<ResourceIdentifier>,
pub metadata: ZoneMetadata,
}
impl ZoneData {
pub fn rid(&self) -> ResourceIdentifier {
ResourceIdentifier {
rid: self.id.to_owned(),
rtype: ResourceType::Zone,
}
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ZoneMetadata {
pub name: String,
pub archetype: ZoneArchetype,
}
#[derive(Copy, Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum ZoneArchetype {
Attic,
Balcony,
Barbecue,
Bathroom,
Bedroom,
Carport,
Closet,
Computer,
Dining,
Downstairs,
Driveway,
FrontDoor,
Garage,
Garden,
GuestRoom,
Gym,
Hallway,
Home,
KidsBedroom,
Kitchen,
LaundryRoom,
LivingRoom,
Lounge,
ManCave,
Music,
Nursery,
Office,
Pool,
Porch,
Reading,
Recreation,
Staircase,
Storage,
Studio,
Terrace,
Toilet,
TopFloor,
Tv,
Upstairs,
#[serde(other)]
Other,
}
#[derive(Debug)]
pub struct Home {
data: HomeData,
}
impl Home {
pub fn new(data: HomeData) -> Self {
Home { data }
}
pub fn data(&self) -> &HomeData {
&self.data
}
pub fn id(&self) -> &str {
&self.data.id
}
pub fn rid(&self) -> ResourceIdentifier {
self.data.rid()
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct HomeData {
pub id: String,
pub id_v1: Option<String>,
pub children: Vec<ResourceIdentifier>,
pub services: Vec<ResourceIdentifier>,
}
impl HomeData {
pub fn rid(&self) -> ResourceIdentifier {
ResourceIdentifier {
rid: self.id.to_owned(),
rtype: ResourceType::BridgeHome,
}
}
}