Skip to main content

homecore_hap/
accessory.rs

1//! HAP service type and characteristic enum catalogues.
2//!
3//! Mirrors the HAP-1.1 service/characteristic namespace used by Apple Home
4//! and the `hap` crate (https://crates.io/crates/hap). Keeping these as
5//! plain Rust enums in P1 avoids the heavy `hap` dep until P2.
6
7use serde::{Deserialize, Serialize};
8
9/// HAP service types exposed by the RuView bridge.
10///
11/// Derived from HomeKit Accessory Protocol Specification §8 (service
12/// definitions) and cross-checked against HA's `homekit` integration
13/// service catalog.
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
15pub enum HapAccessoryType {
16    /// HAP `Lightbulb` service — maps `light.*` entities.
17    Lightbulb,
18    /// HAP `Switch` service — maps generic boolean `switch.*` entities.
19    Switch,
20    /// HAP `OccupancySensor` — maps presence / occupancy binary sensors.
21    OccupancySensor,
22    /// HAP `MotionSensor` — maps motion binary sensors + RuView motion.
23    MotionSensor,
24    /// HAP `TemperatureSensor` — maps `sensor.*temperature*` entities.
25    TemperatureSensor,
26    /// HAP `HumiditySensor` — maps `sensor.*humidity*` entities.
27    HumiditySensor,
28    /// HAP `LeakSensor` — maps abnormal event sensors; used for fall detection
29    /// following HA's homekit_controller convention (HAP §11.42).
30    LeakSensor,
31    /// HAP `ContactSensor` — maps door / window binary sensors.
32    ContactSensor,
33    /// HAP `Door` service — maps `cover.*door*` entities.
34    Door,
35    /// HAP `LockMechanism` service — maps `lock.*` entities.
36    Lock,
37    /// HAP `SecuritySystem` service — maps alarm / security panel entities.
38    SecuritySystem,
39}
40
41impl HapAccessoryType {
42    /// All defined variants — used in tests and for UI enumeration.
43    pub const ALL: &'static [HapAccessoryType] = &[
44        HapAccessoryType::Lightbulb,
45        HapAccessoryType::Switch,
46        HapAccessoryType::OccupancySensor,
47        HapAccessoryType::MotionSensor,
48        HapAccessoryType::TemperatureSensor,
49        HapAccessoryType::HumiditySensor,
50        HapAccessoryType::LeakSensor,
51        HapAccessoryType::ContactSensor,
52        HapAccessoryType::Door,
53        HapAccessoryType::Lock,
54        HapAccessoryType::SecuritySystem,
55    ];
56}
57
58/// HAP characteristic identifiers that the bridge reads or writes.
59///
60/// Each variant corresponds to one HAP characteristic UUID as specified in
61/// HomeKit Accessory Protocol Specification §9.
62#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
63pub enum HapCharacteristic {
64    /// `On` (bool) — Lightbulb / Switch power state.
65    On,
66    /// `Brightness` (uint8, 0–100) — Lightbulb brightness percentage.
67    Brightness,
68    /// `CurrentTemperature` (float, °C) — TemperatureSensor reading.
69    CurrentTemperature,
70    /// `CurrentRelativeHumidity` (float, %) — HumiditySensor reading.
71    CurrentRelativeHumidity,
72    /// `OccupancyDetected` (uint8, 0=not detected, 1=detected).
73    OccupancyDetected,
74    /// `MotionDetected` (bool).
75    MotionDetected,
76    /// `LeakDetected` (uint8, 0=no leak, 1=leak detected). Re-used for falls.
77    LeakDetected,
78    /// `ContactSensorState` (uint8, 0=in contact, 1=not in contact).
79    ContactSensorState,
80    /// `CurrentDoorState` (uint8, HAP §9.30).
81    CurrentDoorState,
82    /// `LockCurrentState` (uint8, HAP §9.56).
83    LockCurrentState,
84    /// `SecuritySystemCurrentState` (uint8, HAP §9.97).
85    SecuritySystemCurrentState,
86}
87
88/// Typed value carried by a HAP characteristic update.
89#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
90pub enum HapCharacteristicValue {
91    Bool(bool),
92    UInt8(u8),
93    Float(f64),
94}
95
96#[cfg(test)]
97mod tests {
98    use super::*;
99
100    #[test]
101    fn all_11_accessory_types_defined() {
102        assert_eq!(HapAccessoryType::ALL.len(), 11);
103        // Spot-check each variant is present.
104        assert!(HapAccessoryType::ALL.contains(&HapAccessoryType::Lightbulb));
105        assert!(HapAccessoryType::ALL.contains(&HapAccessoryType::Switch));
106        assert!(HapAccessoryType::ALL.contains(&HapAccessoryType::OccupancySensor));
107        assert!(HapAccessoryType::ALL.contains(&HapAccessoryType::MotionSensor));
108        assert!(HapAccessoryType::ALL.contains(&HapAccessoryType::TemperatureSensor));
109        assert!(HapAccessoryType::ALL.contains(&HapAccessoryType::HumiditySensor));
110        assert!(HapAccessoryType::ALL.contains(&HapAccessoryType::LeakSensor));
111        assert!(HapAccessoryType::ALL.contains(&HapAccessoryType::ContactSensor));
112        assert!(HapAccessoryType::ALL.contains(&HapAccessoryType::Door));
113        assert!(HapAccessoryType::ALL.contains(&HapAccessoryType::Lock));
114        assert!(HapAccessoryType::ALL.contains(&HapAccessoryType::SecuritySystem));
115    }
116
117    #[test]
118    fn characteristic_value_roundtrip_serde() {
119        let v = HapCharacteristicValue::Float(22.5);
120        let json = serde_json::to_string(&v).unwrap();
121        let back: HapCharacteristicValue = serde_json::from_str(&json).unwrap();
122        assert_eq!(v, back);
123    }
124}