@@ -32,6 +32,11 @@ pub enum HueLiveEvent {
3232 #[ serde( rename = "updatedAt" ) ]
3333 updated_at : String ,
3434 } ,
35+ MotionEnabled {
36+ #[ serde( rename = "deviceId" ) ]
37+ device_id : String ,
38+ enabled : bool ,
39+ } ,
3540 Connectivity {
3641 #[ serde( rename = "deviceId" ) ]
3742 device_id : String ,
@@ -100,7 +105,7 @@ async fn stream_events(state: &Arc<AppState>) -> Result<(), Box<dyn std::error::
100105 continue ;
101106 }
102107 for resource in envelope. data {
103- if let Some ( event) = parse_resource_update ( & resource) {
108+ for event in parse_resource_update ( & resource) {
104109 let _ = state. hue_events_tx . send ( event) ;
105110 }
106111 }
@@ -117,52 +122,103 @@ struct EventEnvelope {
117122 data : Vec < serde_json:: Value > ,
118123}
119124
120- fn parse_resource_update ( resource : & serde_json:: Value ) -> Option < HueLiveEvent > {
121- let rtype = resource. get ( "type" ) ?. as_str ( ) ?;
125+ fn parse_resource_update ( resource : & serde_json:: Value ) -> Vec < HueLiveEvent > {
126+ let Some ( rtype) = resource. get ( "type" ) . and_then ( |v| v. as_str ( ) ) else {
127+ return Vec :: new ( ) ;
128+ } ;
122129 match rtype {
123- "grouped_light" => {
124- let on = resource. get ( "on" ) ?. get ( "on" ) ?. as_bool ( ) ?;
125- let id = resource. get ( "id" ) ?. as_str ( ) ?. to_string ( ) ;
126- Some ( HueLiveEvent :: GroupedLight { id, on } )
127- }
128- "temperature" => {
129- let temp_obj = resource. get ( "temperature" ) ?;
130- let temperature = temp_obj
131- . get ( "temperature_report" )
132- . and_then ( |r| r. get ( "temperature" ) )
133- . or_else ( || temp_obj. get ( "temperature" ) ) ?
134- . as_f64 ( ) ?;
135- let id = resource. get ( "id" ) ?. as_str ( ) ?. to_string ( ) ;
136- Some ( HueLiveEvent :: Temperature { id, temperature } )
137- }
138- "device_power" => {
139- let battery = resource
140- . get ( "power_state" ) ?
141- . get ( "battery_level" ) ?
142- . as_u64 ( ) ? as u8 ;
143- let device_id = resource. get ( "owner" ) ?. get ( "rid" ) ?. as_str ( ) ?. to_string ( ) ;
144- Some ( HueLiveEvent :: DevicePower { device_id, battery } )
145- }
146- "motion" => {
147- let report = resource. get ( "motion" ) ?. get ( "motion_report" ) ?;
148- let motion = report. get ( "motion" ) ?. as_bool ( ) ?;
149- let updated_at = report. get ( "changed" ) ?. as_str ( ) ?. to_string ( ) ;
150- let device_id = resource. get ( "owner" ) ?. get ( "rid" ) ?. as_str ( ) ?. to_string ( ) ;
151- Some ( HueLiveEvent :: Motion {
152- device_id,
153- motion,
154- updated_at,
130+ "grouped_light" => resource
131+ . get ( "on" )
132+ . and_then ( |o| o. get ( "on" ) )
133+ . and_then ( |o| o. as_bool ( ) )
134+ . zip ( resource. get ( "id" ) . and_then ( |v| v. as_str ( ) ) )
135+ . map ( |( on, id) | {
136+ vec ! [ HueLiveEvent :: GroupedLight {
137+ id: id. to_string( ) ,
138+ on,
139+ } ]
155140 } )
156- }
157- "zigbee_connectivity" => {
158- let status = resource. get ( "status" ) ?. as_str ( ) ?;
159- let device_id = resource. get ( "owner" ) ?. get ( "rid" ) ?. as_str ( ) ?. to_string ( ) ;
160- Some ( HueLiveEvent :: Connectivity {
161- device_id,
162- connected : status == "connected" ,
141+ . unwrap_or_default ( ) ,
142+ "temperature" => resource
143+ . get ( "temperature" )
144+ . and_then ( |temp_obj| {
145+ temp_obj
146+ . get ( "temperature_report" )
147+ . and_then ( |r| r. get ( "temperature" ) )
148+ . or_else ( || temp_obj. get ( "temperature" ) )
149+ . and_then ( |t| t. as_f64 ( ) )
163150 } )
151+ . zip ( resource. get ( "id" ) . and_then ( |v| v. as_str ( ) ) )
152+ . map ( |( temperature, id) | {
153+ vec ! [ HueLiveEvent :: Temperature {
154+ id: id. to_string( ) ,
155+ temperature,
156+ } ]
157+ } )
158+ . unwrap_or_default ( ) ,
159+ "device_power" => resource
160+ . get ( "power_state" )
161+ . and_then ( |s| s. get ( "battery_level" ) )
162+ . and_then ( |b| b. as_u64 ( ) )
163+ . zip (
164+ resource
165+ . get ( "owner" )
166+ . and_then ( |o| o. get ( "rid" ) )
167+ . and_then ( |r| r. as_str ( ) ) ,
168+ )
169+ . map ( |( battery, device_id) | {
170+ vec ! [ HueLiveEvent :: DevicePower {
171+ device_id: device_id. to_string( ) ,
172+ battery: battery as u8 ,
173+ } ]
174+ } )
175+ . unwrap_or_default ( ) ,
176+ "motion" => {
177+ let Some ( device_id) = resource
178+ . get ( "owner" )
179+ . and_then ( |o| o. get ( "rid" ) )
180+ . and_then ( |r| r. as_str ( ) )
181+ else {
182+ return Vec :: new ( ) ;
183+ } ;
184+ let mut events = Vec :: new ( ) ;
185+ if let Some ( enabled) = resource. get ( "enabled" ) . and_then ( |e| e. as_bool ( ) ) {
186+ events. push ( HueLiveEvent :: MotionEnabled {
187+ device_id : device_id. to_string ( ) ,
188+ enabled,
189+ } ) ;
190+ }
191+ if let Some ( report) = resource. get ( "motion" ) . and_then ( |m| m. get ( "motion_report" ) ) {
192+ if let ( Some ( motion) , Some ( updated_at) ) = (
193+ report. get ( "motion" ) . and_then ( |m| m. as_bool ( ) ) ,
194+ report. get ( "changed" ) . and_then ( |c| c. as_str ( ) ) ,
195+ ) {
196+ events. push ( HueLiveEvent :: Motion {
197+ device_id : device_id. to_string ( ) ,
198+ motion,
199+ updated_at : updated_at. to_string ( ) ,
200+ } ) ;
201+ }
202+ }
203+ events
164204 }
165- _ => None ,
205+ "zigbee_connectivity" => resource
206+ . get ( "status" )
207+ . and_then ( |s| s. as_str ( ) )
208+ . zip (
209+ resource
210+ . get ( "owner" )
211+ . and_then ( |o| o. get ( "rid" ) )
212+ . and_then ( |r| r. as_str ( ) ) ,
213+ )
214+ . map ( |( status, device_id) | {
215+ vec ! [ HueLiveEvent :: Connectivity {
216+ device_id: device_id. to_string( ) ,
217+ connected: status == "connected" ,
218+ } ]
219+ } )
220+ . unwrap_or_default ( ) ,
221+ _ => Vec :: new ( ) ,
166222 }
167223}
168224
0 commit comments