matc/clusters/codec/
chime.rs1#![allow(clippy::too_many_arguments)]
7
8use crate::tlv;
9use anyhow;
10use serde_json;
11
12
13#[derive(Debug, serde::Serialize)]
16pub struct ChimeSound {
17 pub chime_id: Option<u8>,
18 pub name: Option<String>,
19}
20
21pub fn encode_play_chime_sound(chime_id: Option<u8>) -> anyhow::Result<Vec<u8>> {
25 let mut tlv_fields: Vec<tlv::TlvItemEnc> = Vec::new();
26 if let Some(x) = chime_id { tlv_fields.push((0, tlv::TlvItemValueEnc::UInt8(x)).into()); }
27 let tlv = tlv::TlvItemEnc {
28 tag: 0,
29 value: tlv::TlvItemValueEnc::StructInvisible(tlv_fields),
30 };
31 Ok(tlv.encode()?)
32}
33
34pub fn decode_installed_chime_sounds(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<ChimeSound>> {
38 let mut res = Vec::new();
39 if let tlv::TlvItemValue::List(v) = inp {
40 for item in v {
41 res.push(ChimeSound {
42 chime_id: item.get_int(&[0]).map(|v| v as u8),
43 name: item.get_string_owned(&[1]),
44 });
45 }
46 }
47 Ok(res)
48}
49
50pub fn decode_selected_chime(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
52 if let tlv::TlvItemValue::Int(v) = inp {
53 Ok(*v as u8)
54 } else {
55 Err(anyhow::anyhow!("Expected UInt8"))
56 }
57}
58
59pub fn decode_enabled(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
61 if let tlv::TlvItemValue::Bool(v) = inp {
62 Ok(*v)
63 } else {
64 Err(anyhow::anyhow!("Expected Bool"))
65 }
66}
67
68
69pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
81 if cluster_id != 0x0556 {
83 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0556, got {}\"}}", cluster_id);
84 }
85
86 match attribute_id {
87 0x0000 => {
88 match decode_installed_chime_sounds(tlv_value) {
89 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
90 Err(e) => format!("{{\"error\": \"{}\"}}", e),
91 }
92 }
93 0x0001 => {
94 match decode_selected_chime(tlv_value) {
95 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
96 Err(e) => format!("{{\"error\": \"{}\"}}", e),
97 }
98 }
99 0x0002 => {
100 match decode_enabled(tlv_value) {
101 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
102 Err(e) => format!("{{\"error\": \"{}\"}}", e),
103 }
104 }
105 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
106 }
107}
108
109pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
114 vec![
115 (0x0000, "InstalledChimeSounds"),
116 (0x0001, "SelectedChime"),
117 (0x0002, "Enabled"),
118 ]
119}
120
121pub fn get_command_list() -> Vec<(u32, &'static str)> {
124 vec![
125 (0x00, "PlayChimeSound"),
126 ]
127}
128
129pub fn get_command_name(cmd_id: u32) -> Option<&'static str> {
130 match cmd_id {
131 0x00 => Some("PlayChimeSound"),
132 _ => None,
133 }
134}
135
136pub fn get_command_schema(cmd_id: u32) -> Option<Vec<crate::clusters::codec::CommandField>> {
137 match cmd_id {
138 0x00 => Some(vec![
139 crate::clusters::codec::CommandField { tag: 0, name: "chime_id", kind: crate::clusters::codec::FieldKind::U8, optional: true, nullable: false },
140 ]),
141 _ => None,
142 }
143}
144
145pub fn encode_command_json(cmd_id: u32, args: &serde_json::Value) -> anyhow::Result<Vec<u8>> {
146 match cmd_id {
147 0x00 => {
148 let chime_id = crate::clusters::codec::json_util::get_opt_u8(args, "chime_id")?;
149 encode_play_chime_sound(chime_id)
150 }
151 _ => Err(anyhow::anyhow!("unknown command ID: 0x{:02X}", cmd_id)),
152 }
153}
154
155pub async fn play_chime_sound(conn: &crate::controller::Connection, endpoint: u16, chime_id: Option<u8>) -> anyhow::Result<()> {
159 conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_CHIME, crate::clusters::defs::CLUSTER_CHIME_CMD_ID_PLAYCHIMESOUND, &encode_play_chime_sound(chime_id)?).await?;
160 Ok(())
161}
162
163pub async fn read_installed_chime_sounds(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<ChimeSound>> {
165 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CHIME, crate::clusters::defs::CLUSTER_CHIME_ATTR_ID_INSTALLEDCHIMESOUNDS).await?;
166 decode_installed_chime_sounds(&tlv)
167}
168
169pub async fn read_selected_chime(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
171 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CHIME, crate::clusters::defs::CLUSTER_CHIME_ATTR_ID_SELECTEDCHIME).await?;
172 decode_selected_chime(&tlv)
173}
174
175pub async fn read_enabled(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
177 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CHIME, crate::clusters::defs::CLUSTER_CHIME_ATTR_ID_ENABLED).await?;
178 decode_enabled(&tlv)
179}
180
181#[derive(Debug, serde::Serialize)]
182pub struct ChimeStartedPlayingEvent {
183 pub chime_id: Option<u8>,
184}
185
186pub fn decode_chime_started_playing_event(inp: &tlv::TlvItemValue) -> anyhow::Result<ChimeStartedPlayingEvent> {
190 if let tlv::TlvItemValue::List(_fields) = inp {
191 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
192 Ok(ChimeStartedPlayingEvent {
193 chime_id: item.get_int(&[0]).map(|v| v as u8),
194 })
195 } else {
196 Err(anyhow::anyhow!("Expected struct fields"))
197 }
198}
199
200
201pub fn decode_event_json(cluster_id: u32, event_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
205 if cluster_id != 0x0556 {
206 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0556, got {}\"}}", cluster_id);
207 }
208
209 match event_id {
210 0x00 => {
211 match decode_chime_started_playing_event(tlv_value) {
212 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
213 Err(e) => format!("{{\"error\": \"{}\"}}", e),
214 }
215 }
216 _ => format!("{{\"error\": \"Unknown event ID: {}\"}}", event_id),
217 }
218}
219
220pub fn get_event_list() -> Vec<(u32, &'static str)> {
225 vec![
226 (0x00, "ChimeStartedPlaying"),
227 ]
228}
229