@@ -9,24 +9,31 @@ use home_assistant_rest::Client;
99use log:: { error, info} ;
1010use std:: collections:: HashMap ;
1111use std:: sync:: atomic:: { AtomicBool , Ordering } ;
12+ use futures_util:: future:: try_join_all;
1213
1314pub struct HaApi {
14- client : Client ,
1515 ha_configuration : HaConfiguration ,
1616}
1717
1818impl HaApi {
1919 pub fn new ( ha_configuration : HaConfiguration ) -> anyhow:: Result < Self > {
20- let client = Client :: new ( & * ha_configuration. url , & * ha_configuration. long_live_token ) ?;
2120 Ok ( Self {
22- client,
2321 ha_configuration,
2422 } )
2523 }
2624
27- /* friendly_name is needed as API calls wipe the configured name */
28- async fn update_ha ( & self , state : & AtomicBool , ha_entity : & HaEntity ) -> anyhow:: Result < ( ) > {
29- let api_status = self . client . get_api_status ( ) . await . unwrap ( ) ;
25+ // friendly_name is needed as API calls wipe the configured name
26+ async fn update_ha ( & self , state : & AtomicBool , prev_state : & AtomicBool , ha_entity : & HaEntity , force_update : bool ) -> anyhow:: Result < ( ) > {
27+ let state_bool = state. load ( Ordering :: Relaxed ) ;
28+ let prev_state_bool = prev_state. load ( Ordering :: Relaxed ) ;
29+
30+ // we exit early if nothing has changed, and we are not forcing an update
31+ if state_bool == prev_state_bool && !force_update {
32+ return Ok ( ( ) ) ;
33+ }
34+
35+ let client = Client :: new ( & * self . ha_configuration . url , & * self . ha_configuration . long_live_token ) ?;
36+ let api_status = client. get_api_status ( ) . await . unwrap ( ) ;
3037
3138 if api_status. message != "API running." {
3239 error ! ( "Home Assistant API cannot be reached" ) ;
@@ -39,8 +46,6 @@ impl HaApi {
3946 ha_entity. friendly_name . to_string ( ) ,
4047 ) ;
4148
42- let state_bool = state. load ( Ordering :: Relaxed ) ;
43-
4449 let icon = if state_bool {
4550 & ha_entity. icons . on
4651 } else {
@@ -58,67 +63,81 @@ impl HaApi {
5863
5964 info ! ( "Updating HA entity ({}) to '{}'" , & ha_entity. id, & state_str) ;
6065
61- let post_states_res = self . client . post_states ( params) . await ;
66+ let post_states_res = client. post_states ( params) . await ;
6267
6368 if post_states_res. is_err ( ) {
6469 error ! ( "{}" , post_states_res. unwrap_err( ) ) ;
6570 } ;
6671
72+ prev_state. store ( state_bool, Ordering :: Relaxed ) ;
73+
6774 Ok ( ( ) )
6875 }
6976}
7077
7178#[ async_trait]
7279impl Listener for HaApi {
73- async fn notify_changed ( & self , teams_states : & TeamsStates ) -> anyhow:: Result < ( ) > {
80+ async fn notify_changed ( & self , teams_states : & TeamsStates , force_update : bool ) -> anyhow:: Result < ( ) > {
7481 // Reflection would be nice here... Tried with bevy_reflect but ran into an issue with AtomicBool
75- self . update_ha (
82+ let mut futures = Vec :: new ( ) ;
83+
84+ futures. push ( self . update_ha (
7685 & teams_states. is_in_meeting ,
86+ & teams_states. prev_is_in_meeting ,
7787 & self . ha_configuration . entities . is_in_meeting ,
78- )
79- . await ? ;
88+ force_update ,
89+ ) ) ;
8090
81- self . update_ha (
91+ futures . push ( self . update_ha (
8292 & teams_states. is_video_on ,
93+ & teams_states. prev_is_video_on ,
8394 & self . ha_configuration . entities . is_video_on ,
84- )
85- . await ? ;
86-
87- self . update_ha (
95+ force_update ,
96+ ) ) ;
97+
98+ futures . push ( self . update_ha (
8899 & teams_states. is_muted ,
100+ & teams_states. prev_is_muted ,
89101 & self . ha_configuration . entities . is_muted ,
90- )
91- . await ? ;
102+ force_update ,
103+ ) ) ;
92104
93- self . update_ha (
105+ futures . push ( self . update_ha (
94106 & teams_states. is_hand_raised ,
107+ & teams_states. prev_is_hand_raised ,
95108 & self . ha_configuration . entities . is_hand_raised ,
96- )
97- . await ? ;
109+ force_update ,
110+ ) ) ;
98111
99- self . update_ha (
112+ futures . push ( self . update_ha (
100113 & teams_states. is_recording_on ,
114+ & teams_states. prev_is_recording_on ,
101115 & self . ha_configuration . entities . is_recording_on ,
102- )
103- . await ? ;
116+ force_update ,
117+ ) ) ;
104118
105- self . update_ha (
119+ futures . push ( self . update_ha (
106120 & teams_states. is_background_blurred ,
121+ & teams_states. prev_is_background_blurred ,
107122 & self . ha_configuration . entities . is_background_blurred ,
108- )
109- . await ? ;
123+ force_update ,
124+ ) ) ;
110125
111- self . update_ha (
126+ futures . push ( self . update_ha (
112127 & teams_states. is_sharing ,
128+ & teams_states. prev_is_sharing ,
113129 & self . ha_configuration . entities . is_sharing ,
114- )
115- . await ? ;
130+ force_update ,
131+ ) ) ;
116132
117- self . update_ha (
133+ futures . push ( self . update_ha (
118134 & teams_states. has_unread_messages ,
135+ & teams_states. prev_has_unread_messages ,
119136 & self . ha_configuration . entities . has_unread_messages ,
120- )
121- . await ?;
137+ force_update,
138+ ) ) ;
139+
140+ try_join_all ( futures) . await ?;
122141
123142 Ok ( ( ) )
124143 }
0 commit comments