hap_model/
characteristics.rs1use crate::error::{ModelError, Result};
4use crate::format::{CharFormat, CharValue};
5use serde::Deserialize;
6use std::fmt::Write as _;
7
8#[derive(Debug, Clone, PartialEq)]
10pub struct CharRead {
11 pub aid: u64,
13 pub iid: u64,
15 pub value: Option<CharValue>,
17 pub status: Option<i64>,
19}
20
21pub fn build_read_request(ids: &[(u64, u64)]) -> String {
33 let mut path = String::from("/characteristics?id=");
34 for (i, (aid, iid)) in ids.iter().enumerate() {
35 if i > 0 {
36 path.push(',');
37 }
38 let _ = write!(path, "{aid}.{iid}");
40 }
41 path
42}
43
44#[derive(Debug, Deserialize)]
47struct WireReadResponse {
48 characteristics: Vec<WireReadEntry>,
49}
50
51#[derive(Debug, Deserialize)]
52struct WireReadEntry {
53 aid: u64,
54 iid: u64,
55 #[serde(default)]
56 value: Option<serde_json::Value>,
57 #[serde(default)]
58 status: Option<i64>,
59 #[serde(default)]
60 format: Option<CharFormat>,
61}
62
63pub fn parse_read_response(json: &[u8]) -> Result<Vec<((u64, u64), CharValue)>> {
77 let wire: WireReadResponse = serde_json::from_slice(json)?;
78 let mut out = Vec::with_capacity(wire.characteristics.len());
79 for e in wire.characteristics {
80 if let Some(s) = e.status {
81 if s != 0 {
82 return Err(ModelError::CharacteristicStatus {
83 aid: e.aid,
84 iid: e.iid,
85 status: s,
86 });
87 }
88 }
89 let Some(raw) = e.value else { continue };
90 let value = match e.format {
91 Some(fmt) => fmt.value_from_json(&raw)?,
92 None => infer_value(&raw)?,
93 };
94 out.push(((e.aid, e.iid), value));
95 }
96 Ok(out)
97}
98
99fn infer_value(v: &serde_json::Value) -> Result<CharValue> {
101 use serde_json::Value as J;
102 match v {
103 J::Bool(b) => Ok(CharValue::Bool(*b)),
104 J::String(s) => Ok(CharValue::Str(s.clone())),
105 J::Number(n) => {
106 if let Some(u) = n.as_u64() {
107 Ok(CharValue::Uint(u))
108 } else if let Some(i) = n.as_i64() {
109 Ok(CharValue::Int(i))
110 } else if let Some(f) = n.as_f64() {
111 Ok(CharValue::Float(f))
112 } else {
113 Err(ModelError::ValueType {
114 format: "unknown",
115 detail: format!("uninterpretable number {n}"),
116 })
117 }
118 }
119 other => Err(ModelError::ValueType {
120 format: "unknown",
121 detail: format!("got JSON {other}"),
122 }),
123 }
124}
125
126pub fn build_write_request(writes: &[((u64, u64), CharValue)]) -> Vec<u8> {
131 let entries: Vec<serde_json::Value> = writes
132 .iter()
133 .map(|((aid, iid), v)| serde_json::json!({ "aid": aid, "iid": iid, "value": v.to_json() }))
134 .collect();
135 let body = serde_json::json!({ "characteristics": entries });
136 serde_json::to_vec(&body).unwrap_or_default()
138}
139
140pub fn build_subscribe_request(ids: &[(u64, u64)], enable: bool) -> Vec<u8> {
143 let entries: Vec<serde_json::Value> = ids
144 .iter()
145 .map(|(aid, iid)| serde_json::json!({ "aid": aid, "iid": iid, "ev": enable }))
146 .collect();
147 let body = serde_json::json!({ "characteristics": entries });
148 serde_json::to_vec(&body).unwrap_or_default()
149}
150
151pub fn build_prepare_request(ttl_ms: u64, pid: u64) -> Vec<u8> {
156 let body = serde_json::json!({ "ttl": ttl_ms, "pid": pid });
157 serde_json::to_vec(&body).unwrap_or_default()
158}
159
160pub fn build_timed_write_request(writes: &[((u64, u64), CharValue)], pid: u64) -> Vec<u8> {
163 let entries: Vec<serde_json::Value> = writes
164 .iter()
165 .map(|((aid, iid), v)| {
166 serde_json::json!({ "aid": aid, "iid": iid, "value": v.to_json(), "pid": pid })
167 })
168 .collect();
169 serde_json::to_vec(&serde_json::json!({ "characteristics": entries })).unwrap_or_default()
170}
171
172pub fn build_write_request_with_response(writes: &[((u64, u64), CharValue)]) -> Vec<u8> {
175 let entries: Vec<serde_json::Value> = writes
176 .iter()
177 .map(|((aid, iid), v)| {
178 serde_json::json!({ "aid": aid, "iid": iid, "value": v.to_json(), "r": true })
179 })
180 .collect();
181 serde_json::to_vec(&serde_json::json!({ "characteristics": entries })).unwrap_or_default()
182}