1use serde::{Deserialize, Serialize};
8use std::net::IpAddr;
9use std::time::{Duration, SystemTime};
10
11use crate::registry::RegistrationId;
12
13pub use sonos_api::services::av_transport::state::AVTransportState;
15pub use sonos_api::services::group_management::state::GroupManagementState;
16pub use sonos_api::services::group_rendering_control::state::GroupRenderingControlState;
17pub use sonos_api::services::rendering_control::state::RenderingControlState;
18pub use sonos_api::services::zone_group_topology::state::ZoneGroupTopologyState;
19
20pub use sonos_api::services::zone_group_topology::events::{
22 NetworkInfo, SatelliteInfo, ZoneGroupInfo, ZoneGroupMemberInfo,
23};
24
25#[derive(Debug, Clone)]
27pub struct EnrichedEvent {
28 pub registration_id: RegistrationId,
30
31 pub speaker_ip: IpAddr,
33
34 pub service: sonos_api::Service,
36
37 pub event_source: EventSource,
39
40 pub timestamp: SystemTime,
42
43 pub event_data: EventData,
45}
46
47impl EnrichedEvent {
48 pub fn new(
50 registration_id: RegistrationId,
51 speaker_ip: IpAddr,
52 service: sonos_api::Service,
53 event_source: EventSource,
54 event_data: EventData,
55 ) -> Self {
56 Self {
57 registration_id,
58 speaker_ip,
59 service,
60 event_source,
61 timestamp: SystemTime::now(),
62 event_data,
63 }
64 }
65}
66
67#[derive(Debug, Clone)]
69pub enum EventSource {
70 UPnPNotification {
72 subscription_id: String,
74 },
75
76 PollingDetection {
78 poll_interval: Duration,
80 },
81}
82
83#[derive(Debug, Clone)]
89pub enum EventData {
90 AVTransport(AVTransportState),
92
93 RenderingControl(RenderingControlState),
95
96 DeviceProperties(DevicePropertiesEvent),
98
99 ZoneGroupTopology(ZoneGroupTopologyState),
101
102 GroupManagement(GroupManagementState),
104
105 GroupRenderingControl(GroupRenderingControlState),
107}
108
109impl EventData {
110 pub fn service_type(&self) -> sonos_api::Service {
112 match self {
113 EventData::AVTransport(_) => sonos_api::Service::AVTransport,
114 EventData::RenderingControl(_) => sonos_api::Service::RenderingControl,
115 EventData::DeviceProperties(_) => {
116 sonos_api::Service::ZoneGroupTopology
120 }
121 EventData::ZoneGroupTopology(_) => sonos_api::Service::ZoneGroupTopology,
122 EventData::GroupManagement(_) => sonos_api::Service::GroupManagement,
123 EventData::GroupRenderingControl(_) => sonos_api::Service::GroupRenderingControl,
124 }
125 }
126}
127
128#[derive(Debug, Clone, Serialize, Deserialize)]
132pub struct DevicePropertiesEvent {
133 pub zone_name: Option<String>,
135
136 pub zone_icon: Option<String>,
138
139 pub configuration: Option<String>,
141
142 pub capabilities: Option<String>,
144
145 pub software_version: Option<String>,
147
148 pub model_name: Option<String>,
150
151 pub display_version: Option<String>,
153
154 pub hardware_version: Option<String>,
156
157 pub additional_properties: std::collections::HashMap<String, String>,
159}
160
161#[cfg(test)]
162mod tests {
163 use super::*;
164
165 #[test]
166 fn test_enriched_event_creation() {
167 let reg_id = RegistrationId::new(1);
168 let ip: IpAddr = "192.168.1.100".parse().unwrap();
169 let service = sonos_api::Service::AVTransport;
170 let source = EventSource::UPnPNotification {
171 subscription_id: "uuid:123".to_string(),
172 };
173 let data = EventData::AVTransport(AVTransportState {
174 transport_state: Some("PLAYING".to_string()),
175 transport_status: None,
176 speed: None,
177 current_track_uri: None,
178 track_duration: None,
179 track_metadata: None,
180 rel_time: None,
181 abs_time: None,
182 rel_count: None,
183 abs_count: None,
184 play_mode: None,
185 next_track_uri: None,
186 next_track_metadata: None,
187 queue_length: None,
188 });
189
190 let event = EnrichedEvent::new(reg_id, ip, service, source, data);
191
192 assert_eq!(event.registration_id, reg_id);
193 assert_eq!(event.speaker_ip, ip);
194 assert_eq!(event.service, service);
195 }
196
197 #[test]
198 fn test_event_data_service_type() {
199 let av_event = EventData::AVTransport(AVTransportState {
200 transport_state: Some("PLAYING".to_string()),
201 transport_status: None,
202 speed: None,
203 current_track_uri: None,
204 track_duration: None,
205 track_metadata: None,
206 rel_time: None,
207 abs_time: None,
208 rel_count: None,
209 abs_count: None,
210 play_mode: None,
211 next_track_uri: None,
212 next_track_metadata: None,
213 queue_length: None,
214 });
215 assert_eq!(av_event.service_type(), sonos_api::Service::AVTransport);
216
217 let rc_event = EventData::RenderingControl(RenderingControlState {
218 master_volume: Some("50".to_string()),
219 master_mute: Some("false".to_string()),
220 lf_volume: None,
221 rf_volume: None,
222 lf_mute: None,
223 rf_mute: None,
224 bass: None,
225 treble: None,
226 loudness: None,
227 balance: None,
228 other_channels: std::collections::HashMap::new(),
229 });
230 assert_eq!(
231 rc_event.service_type(),
232 sonos_api::Service::RenderingControl
233 );
234
235 let gm_event = EventData::GroupManagement(GroupManagementState {
236 group_coordinator_is_local: Some(true),
237 local_group_uuid: None,
238 reset_volume_after: None,
239 virtual_line_in_group_id: None,
240 volume_av_transport_uri: None,
241 });
242 assert_eq!(gm_event.service_type(), sonos_api::Service::GroupManagement);
243
244 let grc_event = EventData::GroupRenderingControl(GroupRenderingControlState {
245 group_volume: Some(14),
246 group_mute: Some(false),
247 group_volume_changeable: Some(true),
248 });
249 assert_eq!(
250 grc_event.service_type(),
251 sonos_api::Service::GroupRenderingControl
252 );
253 }
254}