lighthouse_manager/
lighthouse.rs1use serde::{Deserialize, Serialize};
2use std::fmt;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
6pub enum LighthouseVersion {
7 V1, V2, }
10
11impl fmt::Display for LighthouseVersion {
12 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
13 match self {
14 LighthouseVersion::V1 => write!(f, "V1 (HTC BS)"),
15 LighthouseVersion::V2 => write!(f, "V2 (LHB)"),
16 }
17 }
18}
19
20#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
22pub struct Lighthouse {
23 pub name: String,
25
26 pub address: String,
28
29 #[serde(skip_serializing_if = "Option::is_none")]
32 pub id: Option<String>,
33
34 #[serde(default)]
37 pub managed: bool,
38}
39
40impl Lighthouse {
41 #[must_use]
45 pub fn version(&self) -> LighthouseVersion {
46 if self.name.starts_with("LHB-") {
47 LighthouseVersion::V2
48 } else {
49 LighthouseVersion::V1
50 }
51 }
52
53 #[must_use]
55 pub fn power_characteristic(&self) -> &'static str {
56 match self.version() {
57 LighthouseVersion::V1 => "0000cb01-0000-1000-8000-00805f9b34fb",
58 LighthouseVersion::V2 => "00001525-1212-efde-1523-785feabcd124",
59 }
60 }
61
62 #[must_use]
64 pub fn identify_characteristic(&self) -> Option<&'static str> {
65 match self.version() {
66 LighthouseVersion::V2 => Some("00008421-1212-efde-1523-785feabcd124"),
67 LighthouseVersion::V1 => None, }
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75
76 #[test]
77 fn test_v1_version_detection() {
78 let lh = Lighthouse {
79 name: "HTC BS-AABBCCDD".into(),
80 address: "AA:BB:CC:DD:EE:FF".into(),
81 id: None,
82 managed: false,
83 };
84 assert_eq!(lh.version(), LighthouseVersion::V1);
85 }
86
87 #[test]
88 fn test_v2_version_detection() {
89 let lh = Lighthouse {
90 name: "LHB-0A1B2C3D".into(),
91 address: "11:22:33:44:55:66".into(),
92 id: None,
93 managed: false,
94 };
95 assert_eq!(lh.version(), LighthouseVersion::V2);
96 }
97
98 #[test]
99 fn test_serde_roundtrip() {
100 let lh = Lighthouse {
101 name: "LHB-0A1B2C3D".into(),
102 address: "AA:BB:CC:DD:EE:FF".into(),
103 id: None,
104 managed: true,
105 };
106 let json = serde_json::to_string(&lh).unwrap();
107 let restored: Lighthouse = serde_json::from_str(&json).unwrap();
108 assert_eq!(restored, lh);
109
110 let v1_lh = Lighthouse {
111 name: "HTC BS-AABBCCDD".into(),
112 address: "11:22:33:44:55:66".into(),
113 id: Some("AABBCCDD".into()),
114 managed: true,
115 };
116 let v1_json = serde_json::to_string(&v1_lh).unwrap();
117 assert!(v1_json.contains("\"id\":\"AABBCCDD\""));
118 let restored_v1: Lighthouse = serde_json::from_str(&v1_json).unwrap();
119 assert_eq!(restored_v1, v1_lh);
120 }
121
122 #[test]
123 fn test_database_roundtrip() {
124 use crate::storage;
125 let lh1 = Lighthouse {
126 name: "HTC BS-AABBCCDD".into(),
127 address: "AA:BB:CC:DD:EE:FF".into(),
128 id: Some("AABBCCDD".into()),
129 managed: true,
130 };
131 let lh2 = Lighthouse {
132 name: "LHB-0A1B2C3D".into(),
133 address: "11:22:33:44:55:66".into(),
134 id: None,
135 managed: true,
136 };
137 let settings = storage::AppSettings {
138 version: 1,
139 lighthouses: vec![lh1.clone(), lh2.clone()],
140 ..Default::default()
141 };
142 let json = serde_json::to_string_pretty(&settings).unwrap();
143 let restored: storage::AppSettings = serde_json::from_str(&json).unwrap();
144 assert_eq!(restored.lighthouses, settings.lighthouses);
145 }
146}