1111
1212_LOGGER = logging .getLogger (__name__ )
1313class PowersensorMessageDispatcher :
14- def __init__ (self , hass : HomeAssistant , vhh : VirtualHousehold ):
14+ def __init__ (self , hass : HomeAssistant , vhh : VirtualHousehold , debounce_timeout : float = 60 ):
1515 self ._hass = hass
1616 self ._vhh = vhh
1717 self .plugs = dict ()
1818 self ._known_plugs = set ()
1919 self ._known_plug_names = dict ()
2020 self .sensors = dict ()
2121 self .on_start_sensor_queue = dict ()
22+ self ._pending_removals = {}
23+ self ._debounce_seconds = debounce_timeout
2224 self ._unsubscribe_from_signals = [
2325 async_dispatcher_connect (self ._hass ,
2426 f"{ DOMAIN } _sensor_added_to_homeassistant" ,
@@ -31,7 +33,7 @@ def __init__(self, hass: HomeAssistant, vhh: VirtualHousehold):
3133 self ._plug_updated ),
3234 async_dispatcher_connect (self ._hass ,
3335 f"{ DOMAIN } _zeroconf_remove_plug" ,
34- self ._plug_remove ),
36+ self ._schedule_plug_removal ),
3537 async_dispatcher_connect (self ._hass ,
3638 f"{ DOMAIN } _plug_added_to_homeassistant" ,
3739 self ._acknowledge_plug_added_to_homeassistant ),
@@ -127,6 +129,11 @@ def add_api(self, network_info):
127129
128130 async def handle_message (self , event : str , message : dict ):
129131 mac = message ['mac' ]
132+ task = self ._pending_removals .pop (mac , None )
133+ if task :
134+ task .cancel ()
135+ _LOGGER .info (f"Cancelled pending removal for { mac } by new message received from plug." )
136+
130137 if mac not in self .plugs .keys ():
131138 if mac not in self .sensors :
132139 role = None
@@ -165,11 +172,17 @@ async def _acknowledge_plug_added_to_homeassistant(self, mac_address, host, port
165172 async def _plug_added (self , info ):
166173 _LOGGER .debug (f" Request to add plug received: { info } " )
167174 network_info = dict ()
168- network_info ['mac' ] = info ['properties' ][b'id' ].decode ('utf-8' )
175+ mac = info ['properties' ][b'id' ].decode ('utf-8' )
176+ network_info ['mac' ] = mac
169177 network_info ['host' ] = info ['addresses' ][0 ]
170178 network_info ['port' ] = info ['port' ]
171179 network_info ['name' ] = info ['name' ]
172180
181+ task = self ._pending_removals .pop (mac , None )
182+ if task :
183+ task .cancel ()
184+ _LOGGER .info (f"Cancelled pending removal for { mac } by request to add api." )
185+
173186 if self ._safe_to_process_plug_queue :
174187 await self .enqueue_plug_for_adding (network_info )
175188 await self .process_plug_queue ()
@@ -182,7 +195,10 @@ async def _plug_updated(self, info):
182195 host = info ['addresses' ][0 ]
183196 port = info ['port' ]
184197 name = info ['name' ]
185-
198+ task = self ._pending_removals .pop (mac , None )
199+ if task :
200+ task .cancel ()
201+ _LOGGER .info (f"Cancelled pending removal for { mac } by request to update api." )
186202 if mac in self .plugs :
187203 current_api : PlugApi = self .plugs [mac ]
188204 if current_api ._listener ._ip == host and current_api ._listener ._port == port :
@@ -202,14 +218,32 @@ async def _plug_updated(self, info):
202218 await self .enqueue_plug_for_adding (network_info )
203219 await self .process_plug_queue ()
204220
205- async def _plug_remove (self ,name , info ):
221+ async def _schedule_plug_removal (self , name , info ):
206222 _LOGGER .debug (f" Request to delete plug received: { info } " )
207223 if name in self ._known_plug_names :
208224 mac = self ._known_plug_names [name ]
209225 if mac in self .plugs :
210- await self .plugs [mac ].disconnect ()
211- del self .plugs [mac ]
212- del self ._known_plug_names [name ]
226+ if mac in self ._pending_removals :
227+ # removal for this service is already pending
228+ return
229+
230+ _LOGGER .info (f"Scheduling removal for { name } " )
231+ self ._pending_removals [name ] = asyncio .create_task (self ._delayed_plug_remove (name ,mac ))
213232 else :
214233 _LOGGER .warning (f"Received request to delete api for gateway with name [{ name } ], but this name"
215234 f"is not associated with an existing PlugAPI. Ignoring..." )
235+
236+ async def _delayed_plug_remove (self , name , mac ):
237+ """Actually process the removal after delay."""
238+ try :
239+ await asyncio .sleep (self ._debounce_seconds )
240+ _LOGGER .info (f"Request to remove plug { mac } still pending after timeout. Processing remove request..." )
241+ await self .plugs [mac ].disconnect ()
242+ del self .plugs [mac ]
243+ del self ._known_plug_names [name ]
244+ except asyncio .CancelledError :
245+ # Task was cancelled because service came back
246+ _LOGGER .info (f"Request to remove plug { mac } was canceled by request to update, add plug or new message." )
247+
248+ # Either way were done with this task
249+ self ._pending_removals .pop (name , None )
0 commit comments