use std::fmt;
use async_trait::async_trait;
use erased_serde::serialize_trait_object;
use futures::future::BoxFuture;
use serde::{
ser::{SerializeStruct, Serializer},
Deserialize,
Serialize,
};
use serde_json::json;
use crate::{event::Event, pointer, HapType, Result};
mod generated;
pub use generated::*;
#[derive(Default)]
pub struct Characteristic<T: fmt::Debug + Default + Clone + Serialize + Send + Sync> {
id: u64,
accessory_id: u64,
hap_type: HapType,
format: Format,
perms: Vec<Perm>,
description: Option<String>,
event_notifications: Option<bool>,
value: T,
unit: Option<Unit>,
max_value: Option<T>,
min_value: Option<T>,
step_value: Option<T>,
max_len: Option<u16>,
max_data_len: Option<u32>,
valid_values: Option<Vec<T>>,
valid_values_range: Option<[T; 2]>,
on_read: Option<Box<dyn OnReadFn<T>>>,
on_update: Option<Box<dyn OnUpdateFn<T>>>,
on_read_async: Option<Box<dyn OnReadFuture<T>>>,
on_update_async: Option<Box<dyn OnUpdateFuture<T>>>,
event_emitter: Option<pointer::EventEmitter>,
}
impl<T: fmt::Debug + Default + Clone + Serialize + Send + Sync> fmt::Debug for Characteristic<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Characteristic")
.field("id", &self.id)
.field("accessory_id", &self.accessory_id)
.field("hap_type", &self.hap_type)
.field("format", &self.format)
.field("perms", &self.perms)
.field("description", &self.description)
.field("event_notifications", &self.event_notifications)
.field("value", &self.value)
.field("unit", &self.unit)
.field("max_value", &self.max_value)
.field("min_value", &self.min_value)
.field("step_value", &self.step_value)
.field("max_len", &self.max_len)
.field("max_data_len", &self.max_data_len)
.field("valid_values", &self.valid_values)
.field("valid_values_range", &self.valid_values_range)
.finish()
}
}
impl<T: fmt::Debug + Default + Clone + Serialize + Send + Sync> Characteristic<T>
where
for<'de> T: Deserialize<'de>,
{
pub fn get_id(&self) -> u64 { self.id }
pub fn get_type(&self) -> HapType { self.hap_type }
pub fn get_format(&self) -> Format { self.format }
pub fn get_perms(&self) -> Vec<Perm> { self.perms.clone() }
pub fn set_description(&mut self, description: Option<String>) { self.description = description; }
pub fn get_event_notifications(&self) -> Option<bool> { self.event_notifications }
pub fn set_event_notifications(&mut self, event_notifications: Option<bool>) {
self.event_notifications = event_notifications;
}
pub async fn get_value(&mut self) -> Result<T> {
let mut val = None;
if let Some(ref on_read) = self.on_read {
val = on_read();
}
if let Some(ref on_read_async) = self.on_read_async {
val = on_read_async().await;
}
if let Some(v) = val {
self.set_value(v).await?;
}
Ok(self.value.clone())
}
pub async fn set_value(&mut self, val: T) -> Result<()> {
let old_val = self.value.clone();
if let Some(ref on_update) = self.on_update {
on_update(&old_val, &val);
}
if let Some(ref on_update_async) = self.on_update_async {
on_update_async(old_val, val.clone()).await;
}
if self.event_notifications == Some(true) {
if let Some(ref event_emitter) = self.event_emitter {
event_emitter
.lock()
.await
.emit(&Event::CharacteristicValueChanged {
aid: self.accessory_id,
iid: self.id,
value: json!(&val),
})
.await;
}
}
self.value = val;
Ok(())
}
pub fn get_unit(&self) -> Option<Unit> { self.unit }
pub fn get_max_value(&self) -> Option<T> { self.max_value.clone() }
pub fn set_max_value(&mut self, val: Option<T>) { self.max_value = val; }
pub fn get_min_value(&self) -> Option<T> { self.min_value.clone() }
pub fn set_min_value(&mut self, val: Option<T>) { self.min_value = val; }
pub fn get_step_value(&self) -> Option<T> { self.step_value.clone() }
pub fn set_step_value(&mut self, val: Option<T>) { self.step_value = val; }
pub fn get_max_len(&self) -> Option<u16> { self.max_len }
pub fn on_read(&mut self, f: Option<impl OnReadFn<T>>) {
self.on_read = f.map(|f| Box::new(f) as Box<dyn OnReadFn<T>>);
}
pub fn on_update(&mut self, f: Option<impl OnUpdateFn<T>>) {
self.on_update = f.map(|f| Box::new(f) as Box<dyn OnUpdateFn<T>>);
}
pub fn on_read_async(&mut self, f: Option<impl OnReadFuture<T>>) {
self.on_read_async = f.map(|f| Box::new(f) as Box<dyn OnReadFuture<T>>);
}
pub fn on_update_async(&mut self, f: Option<impl OnUpdateFuture<T>>) {
self.on_update_async = f.map(|f| Box::new(f) as Box<dyn OnUpdateFuture<T>>);
}
pub(crate) fn set_event_emitter(&mut self, event_emitter: Option<pointer::EventEmitter>) {
self.event_emitter = event_emitter;
}
}
impl<T: fmt::Debug + Default + Clone + Serialize + Send + Sync> Serialize for Characteristic<T> {
fn serialize<S: Serializer>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> {
let mut state = serializer.serialize_struct("Characteristic", 15)?;
state.serialize_field("iid", &self.id)?;
state.serialize_field("type", &self.hap_type)?;
state.serialize_field("format", &self.format)?;
state.serialize_field("perms", &self.perms)?;
if let Some(ref description) = self.description {
state.serialize_field("description", description)?;
}
if let Some(ref event_notifications) = self.event_notifications {
state.serialize_field("ev", event_notifications)?;
}
if self.perms.contains(&Perm::PairedRead) {
state.serialize_field("value", &self.value)?;
}
if let Some(ref unit) = self.unit {
state.serialize_field("unit", unit)?;
}
if let Some(ref max_value) = self.max_value {
state.serialize_field("maxValue", max_value)?;
}
if let Some(ref min_value) = self.min_value {
state.serialize_field("minValue", min_value)?;
}
if let Some(ref step_value) = self.step_value {
state.serialize_field("minStep", step_value)?;
}
if let Some(ref max_len) = self.max_len {
state.serialize_field("maxLen", max_len)?;
}
if let Some(ref max_data_len) = self.max_data_len {
state.serialize_field("maxDataLen", max_data_len)?;
}
if let Some(ref valid_values) = self.valid_values {
state.serialize_field("valid-values", valid_values)?;
}
if let Some(ref valid_values_range) = self.valid_values_range {
state.serialize_field("valid-values-range", valid_values_range)?;
}
state.end()
}
}
#[derive(Debug, Copy, Clone, Serialize, PartialEq)]
pub enum Perm {
#[serde(rename = "pr")]
PairedRead,
#[serde(rename = "pw")]
PairedWrite,
#[serde(rename = "ev")]
Events,
#[serde(rename = "aa")]
AdditionalAuthorization,
#[serde(rename = "tw")]
TimedWrite,
#[serde(rename = "hd")]
Hidden,
}
#[derive(Debug, Copy, Clone, Serialize)]
pub enum Unit {
#[serde(rename = "percentage")]
Percentage,
#[serde(rename = "arcdegrees")]
ArcDegrees,
#[serde(rename = "celsius")]
Celsius,
#[serde(rename = "lux")]
Lux,
#[serde(rename = "seconds")]
Seconds,
}
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
pub enum Format {
#[serde(rename = "string")]
String,
#[serde(rename = "bool")]
Bool,
#[serde(rename = "float")]
Float,
#[serde(rename = "uint8")]
UInt8,
#[serde(rename = "uint16")]
UInt16,
#[serde(rename = "uint32")]
UInt32,
#[serde(rename = "uint64")]
UInt64,
#[serde(rename = "int32")]
Int32,
#[serde(rename = "tlv8")]
Tlv8,
#[serde(rename = "data")]
Data,
}
impl Default for Format {
fn default() -> Format { Format::String }
}
#[async_trait]
pub trait HapCharacteristic: HapCharacteristicSetup + erased_serde::Serialize + Send + Sync {
fn get_id(&self) -> u64;
fn get_type(&self) -> HapType;
fn get_format(&self) -> Format;
fn get_perms(&self) -> Vec<Perm>;
fn get_event_notifications(&self) -> Option<bool>;
fn set_event_notifications(&mut self, event_notifications: Option<bool>);
async fn get_value(&mut self) -> Result<serde_json::Value>;
async fn set_value(&mut self, value: serde_json::Value) -> Result<()>;
fn get_unit(&self) -> Option<Unit>;
fn get_max_value(&self) -> Option<serde_json::Value>;
fn get_min_value(&self) -> Option<serde_json::Value>;
fn get_step_value(&self) -> Option<serde_json::Value>;
fn get_max_len(&self) -> Option<u16>;
}
serialize_trait_object!(HapCharacteristic);
pub trait HapCharacteristicSetup {
fn set_event_emitter(&mut self, event_emitter: Option<pointer::EventEmitter>);
}
pub trait OnReadFn<T: Default + Clone + Serialize + Send + Sync>: Fn() -> Option<T> + 'static + Send + Sync {}
impl<F, T: Default + Clone + Serialize + Send + Sync> OnReadFn<T> for F where
F: Fn() -> Option<T> + 'static + Send + Sync
{
}
pub trait OnUpdateFn<T: Default + Clone + Serialize + Send + Sync>: Fn(&T, &T) + 'static + Send + Sync {}
impl<F, T: Default + Clone + Serialize + Send + Sync> OnUpdateFn<T> for F where F: Fn(&T, &T) + 'static + Send + Sync {}
pub trait OnReadFuture<T: Default + Clone + Serialize + Send + Sync>:
Fn() -> BoxFuture<'static, Option<T>> + 'static + Send + Sync
{
}
impl<F, T: Default + Clone + Serialize + Send + Sync> OnReadFuture<T> for F where
F: Fn() -> BoxFuture<'static, Option<T>> + 'static + Send + Sync
{
}
pub trait OnUpdateFuture<T: Default + Clone + Serialize + Send + Sync>:
Fn(T, T) -> BoxFuture<'static, ()> + 'static + Send + Sync
{
}
impl<F, T: Default + Clone + Serialize + Send + Sync> OnUpdateFuture<T> for F where
F: Fn(T, T) -> BoxFuture<'static, ()> + 'static + Send + Sync
{
}
pub trait CharacteristicCallbacks<T: fmt::Debug + Default + Clone + Serialize + Send + Sync> {
fn on_read(&mut self, f: Option<impl OnReadFn<T>>);
fn on_update(&mut self, f: Option<impl OnUpdateFn<T>>);
}
pub trait AsyncCharacteristicCallbacks<T: fmt::Debug + Default + Clone + Serialize + Send + Sync> {
fn on_read_async(&mut self, f: Option<impl OnReadFuture<T>>);
fn on_update_async(&mut self, f: Option<impl OnUpdateFuture<T>>);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_json_serialization() {
let characteristic = Characteristic::<u16> {
id: 1,
accessory_id: 1,
hap_type: HapType::CurrentTiltAngle,
format: Format::UInt16,
perms: vec![Perm::PairedRead, Perm::Events],
description: Some("Acme Tilt Angle".into()),
event_notifications: Some(true),
value: 123,
unit: Some(Unit::ArcDegrees),
max_value: Some(360),
min_value: Some(0),
step_value: Some(1),
max_len: None,
max_data_len: None,
valid_values: None,
valid_values_range: Some([0, 360]),
on_read: None,
on_update: None,
on_read_async: None,
on_update_async: None,
event_emitter: None,
};
let json = serde_json::to_string(&characteristic).unwrap();
assert_eq!(json, "{\"iid\":1,\"type\":\"C1\",\"format\":\"uint16\",\"perms\":[\"pr\",\"ev\"],\"description\":\"Acme Tilt Angle\",\"ev\":true,\"value\":123,\"unit\":\"arcdegrees\",\"maxValue\":360,\"minValue\":0,\"minStep\":1,\"valid-values-range\":[0,360]}".to_string());
}
}