2626from pyee import AsyncIOEventEmitter
2727from ucapi import media_player
2828
29- LOG = logging .getLogger (__name__ )
29+ _LOG = logging .getLogger (__name__ )
3030
3131BACKOFF_MAX = 30
3232MIN_RECONNECT_DELAY : float = 0.5
@@ -111,19 +111,19 @@ async def init(self, max_timeout: int | None = None) -> bool:
111111 :return: True if connected or connecting, False if timeout occurred.
112112 """
113113 if self ._connecting :
114- LOG .debug ("Skipping init task: connection already running for %s " , self ._identifier )
114+ _LOG .debug ("[%s] Skipping init task: connection already running" , self .log_id )
115115 return True
116116
117117 if await self ._atv .async_generate_cert_if_missing ():
118- LOG .debug ("Generated new certificate" )
118+ _LOG .debug ("[%s] Generated new certificate" , self . log_id )
119119
120120 request_start = None
121121 success = False
122122 start = time .time ()
123123
124124 while not success :
125125 try :
126- LOG .debug ("Retrieving device information from '%s' on %s " , self ._name , self ._atv .host )
126+ _LOG .debug ("[%s] Retrieving device information from %s " , self .log_id , self ._atv .host )
127127 # Limit connection time for async_get_name_and_mac: if a previous pairing screen is still shown,
128128 # this would hang for a long time (often minutes)!
129129 request_start = time .time ()
@@ -134,10 +134,11 @@ async def init(self, max_timeout: int | None = None) -> bool:
134134 self ._reconnect_delay = MIN_RECONNECT_DELAY
135135 except (CannotConnect , ConnectionClosed , asyncio .TimeoutError ) as ex :
136136 if max_timeout and time .time () - start > max_timeout :
137- LOG .error (
138- "Abort connecting after %ss: device '%s' not reachable on %s. %s" ,
137+ _LOG .error (
138+ "[%s] Abort connecting after %ss: device %s not reachable on %s. %s" ,
139+ self .log_id ,
139140 max_timeout ,
140- self ._name ,
141+ self ._identifier ,
141142 self ._atv .host ,
142143 ex ,
143144 )
@@ -148,7 +149,7 @@ async def init(self, max_timeout: int | None = None) -> bool:
148149 self ._name = name
149150 self ._identifier = mac .replace (":" , "" )
150151
151- LOG .debug ("Android TV initialised: %s, %s " , self ._identifier , self . _name )
152+ _LOG .debug ("[%s] Android TV initialised" , self .log_id )
152153 return True
153154
154155 @property
@@ -162,6 +163,11 @@ def identifier(self) -> str:
162163 raise ValueError ("Instance not initialized, no identifier available" )
163164 return self ._identifier
164165
166+ @property
167+ def log_id (self ) -> str :
168+ """Return a log identifier."""
169+ return self ._name if self ._name else self ._identifier
170+
165171 @property
166172 def name (self ) -> str :
167173 """Return the device name."""
@@ -212,11 +218,11 @@ async def start_pairing(self) -> ucapi.StatusCodes:
212218 await self ._atv .async_start_pairing ()
213219 return ucapi .StatusCodes .OK
214220 except CannotConnect as ex :
215- LOG .error ("Failed to start pairing. Error connecting: %s" , ex )
221+ _LOG .error ("[%s] Failed to start pairing. Error connecting: %s" , self . log_id , ex )
216222 return ucapi .StatusCodes .SERVICE_UNAVAILABLE
217223 except ConnectionClosed as ex :
218224 # TODO better error code?
219- LOG .error ("Failed to start pairing. Connection closed: %s" , ex )
225+ _LOG .error ("[%s] Failed to start pairing. Connection closed: %s" , self . log_id , ex )
220226 return ucapi .StatusCodes .SERVER_ERROR
221227
222228 async def finish_pairing (self , pin : str ) -> ucapi .StatusCodes :
@@ -232,10 +238,10 @@ async def finish_pairing(self, pin: str) -> ucapi.StatusCodes:
232238 await self ._atv .async_finish_pairing (pin )
233239 return ucapi .StatusCodes .OK
234240 except InvalidAuth as ex :
235- LOG .error ("Invalid pairing code. Error: %s" , ex )
241+ _LOG .error ("[%s] Invalid pairing code. Error: %s" , self . log_id , ex )
236242 return ucapi .StatusCodes .UNAUTHORIZED
237243 except ConnectionClosed as ex :
238- LOG .error ("Initialize pair again. Error: %s" , ex )
244+ _LOG .error ("[%s] Initialize pair again. Error: %s" , self . log_id , ex )
239245 return ucapi .StatusCodes .SERVICE_UNAVAILABLE
240246
241247 async def connect (self , max_timeout : int | None = None ) -> bool :
@@ -247,11 +253,11 @@ async def connect(self, max_timeout: int | None = None) -> bool:
247253 """
248254 # if we are already connecting, simply ignore further connect calls
249255 if self ._connecting :
250- LOG .debug ("Connection task already running for %s " , self ._identifier )
256+ _LOG .debug ("[%s] Connection task already running" , self .log_id )
251257 return
252258
253259 if self ._atv .is_on is not None :
254- LOG .debug ("Android TV is already connected: %s " , self ._identifier )
260+ _LOG .debug ("[%s] Android TV is already connected" , self .log_id )
255261 # just to make sure the state is up-to-date
256262 self .events .emit (Events .CONNECTED , self ._identifier )
257263 return True
@@ -266,7 +272,7 @@ async def connect(self, max_timeout: int | None = None) -> bool:
266272
267273 while not success :
268274 try :
269- LOG .debug ("Connecting Android TV %s on %s" , self ._identifier , self ._atv .host )
275+ _LOG .debug ("[%s] Connecting Android TV %s on %s" , self . log_id , self ._identifier , self ._atv .host )
270276 self .events .emit (Events .CONNECTING , self ._identifier )
271277 request_start = time .time ()
272278 async with timeout (5.0 ):
@@ -277,22 +283,29 @@ async def connect(self, max_timeout: int | None = None) -> bool:
277283 except InvalidAuth :
278284 # TODO: In this case we need to re-authenticate
279285 # How to handle this?
280- LOG .error ("Invalid authentication for %s" , self ._identifier )
286+ _LOG .error ("[%s] Invalid authentication for %s" , self . log_id , self ._identifier )
281287 self .events .emit (Events .AUTH_ERROR , self ._identifier )
282288 break
283289 except (CannotConnect , ConnectionClosed , asyncio .TimeoutError ) as ex :
284290 if max_timeout and time .time () - start > max_timeout :
285- LOG .error (
286- "Abort connecting after %ss: device '%s' not reachable on %s. %s" ,
291+ _LOG .error (
292+ "[%s] Abort connecting after %ss: device %s not reachable on %s. %s" ,
293+ self .log_id ,
287294 max_timeout ,
288- self ._name ,
295+ self ._identifier ,
289296 self ._atv .host ,
290297 ex ,
291298 )
292299 break
293300 await self ._handle_connection_failure (time .time () - request_start , ex )
294301 except Exception as ex : # pylint: disable=broad-exception-caught
295- LOG .error ("Fatal error connecting Android TV %s on %s: %s" , self ._identifier , self ._atv .host , ex )
302+ _LOG .error (
303+ "[%s] Fatal error connecting Android TV %s on %s: %s" ,
304+ self .log_id ,
305+ self ._identifier ,
306+ self ._atv .host ,
307+ ex ,
308+ )
296309 break
297310
298311 if not success :
@@ -302,7 +315,7 @@ async def connect(self, max_timeout: int | None = None) -> bool:
302315 self ._atv .keep_reconnecting ()
303316
304317 device_info = self ._atv .device_info
305- LOG .info ("Device information: %s" , device_info )
318+ _LOG .info ("[%s] Device information: %s" , self . log_id , device_info )
306319
307320 self ._update_app_list ()
308321 self .events .emit (Events .CONNECTED , self ._identifier )
@@ -315,8 +328,9 @@ async def _handle_connection_failure(self, connect_duration: float, ex):
315328 backoff = self ._backoff () - connect_duration
316329 if backoff <= 0 :
317330 backoff = 0.1
318- LOG .error (
319- "Cannot connect to '%s' on %s, trying again in %.1fs. %s" ,
331+ _LOG .error (
332+ "[%s] Cannot connect to %s on %s, trying again in %.1fs. %s" ,
333+ self .log_id ,
320334 self ._identifier if self ._identifier else self ._name ,
321335 self ._atv .host ,
322336 backoff ,
@@ -325,19 +339,21 @@ async def _handle_connection_failure(self, connect_duration: float, ex):
325339
326340 # try resolving IP address from device name if we keep failing to connect, maybe the IP address changed
327341 if self ._connection_attempts % 10 == 0 :
328- LOG .debug ("Start resolving IP address for '%s' ..." , self ._name )
342+ _LOG .debug ("[%s] Start resolving IP address for %s ..." , self .log_id , self . _identifier )
329343 try :
330344 discovered = await discover .android_tvs ()
331345 for item in discovered :
332346 if item ["name" ] == self ._name :
333347 if self ._atv .host != item ["address" ]:
334- LOG .info ("IP address of '%s' changed: %s" , self ._name , item ["address" ])
348+ _LOG .info (
349+ "[%s] IP address of %s changed: %s" , self .log_id , self ._identifier , item ["address" ]
350+ )
335351 self ._atv .host = item ["address" ]
336352 self .events .emit (Events .IP_ADDRESS_CHANGED , self ._identifier , self ._atv .host )
337353 break
338354 except Exception as e : # pylint: disable=broad-exception-caught
339355 # extra safety, otherwise reconnection task is dead
340- LOG .error ("Discovery failed: %s" , e )
356+ _LOG .error ("[%s] Discovery failed: %s" , self . log_id , e )
341357 else :
342358 await asyncio .sleep (backoff )
343359
@@ -350,7 +366,7 @@ def disconnect(self) -> None:
350366 # Callbacks
351367 def _is_on_updated (self , is_on : bool ) -> None :
352368 """Notify that the Android TV power state is updated."""
353- LOG .info ("%s is on: %s" , self ._identifier , is_on )
369+ _LOG .info ("[%s] is on: %s" , self .log_id , is_on )
354370 update = {}
355371 if is_on :
356372 update ["state" ] = media_player .States .ON .value
@@ -360,7 +376,7 @@ def _is_on_updated(self, is_on: bool) -> None:
360376
361377 def _current_app_updated (self , current_app : str ) -> None :
362378 """Notify that the current app on Android TV is updated."""
363- LOG . info ( "%s notified that current_app: %s" , self ._identifier , current_app )
379+ _LOG . debug ( "[%s] current_app: %s" , self .log_id , current_app )
364380 update = {"source" : current_app }
365381
366382 if current_app in apps .IdMappings :
@@ -382,13 +398,13 @@ def _current_app_updated(self, current_app: str) -> None:
382398
383399 def _volume_info_updated (self , volume_info : dict [str , str | bool ]) -> None :
384400 """Notify that the Android TV volume information is updated."""
385- LOG . info ( "%s notified that volume_info: %s" , self ._identifier , volume_info )
401+ _LOG . debug ( "[%s] volume_info: %s" , self .log_id , volume_info )
386402 update = {"volume" : volume_info ["level" ], "muted" : volume_info ["muted" ]}
387403 self .events .emit (Events .UPDATE , self ._identifier , update )
388404
389405 def _is_available_updated (self , is_available : bool ):
390406 """Notify that the Android TV is ready to receive commands or is unavailable."""
391- LOG .info ("%s notified that is_available: %s" , self ._identifier , is_available )
407+ _LOG .info ("[%s] is_available: %s" , self .log_id , is_available )
392408 self .events .emit (Events .CONNECTED if is_available else Events .DISCONNECTED , self .identifier )
393409
394410 def _update_app_list (self ) -> None :
@@ -445,10 +461,10 @@ async def _send_command(self, keycode: int | str, action: KeyPress = KeyPress.SH
445461
446462 return ucapi .StatusCodes .OK
447463 except ConnectionClosed :
448- LOG .error ("Cannot send command, connection lost: %s " , self ._identifier )
464+ _LOG .error ("[%s] Cannot send command, connection lost" , self .log_id )
449465 return ucapi .StatusCodes .SERVICE_UNAVAILABLE
450466 except ValueError :
451- LOG .error ("Cannot send command, invalid key_code: %s" , keycode )
467+ _LOG .error ("[%s] Cannot send command, invalid key_code: %s" , self . log_id , keycode )
452468 return ucapi .StatusCodes .BAD_REQUEST
453469
454470 async def send_media_player_command (self , cmd_id : str ) -> ucapi .StatusCodes :
@@ -461,13 +477,13 @@ async def send_media_player_command(self, cmd_id: str) -> ucapi.StatusCodes:
461477 BAD_REQUEST if the ``cmd_id`` is unknown or not supported
462478 """
463479 if not self ._profile :
464- LOG .error ("Cannot send command %s: no device profile set" , cmd_id )
480+ _LOG .error ("[%s] Cannot send command %s: no device profile set" , self . log_id , cmd_id )
465481 return ucapi .StatusCodes .SERVER_ERROR
466482
467483 if command := self ._profile .command (cmd_id ):
468484 return await self ._send_command (command .keycode , command .action )
469485
470- LOG .error ("Cannot send command, unknown or unsupported command: %s" , cmd_id )
486+ _LOG .error ("[%s] Cannot send command, unknown or unsupported command: %s" , self . log_id , cmd_id )
471487 return ucapi .StatusCodes .BAD_REQUEST
472488
473489 async def turn_on (self ) -> ucapi .StatusCodes :
@@ -502,9 +518,9 @@ async def select_source(self, source: str) -> ucapi.StatusCodes:
502518 if source in inputs .KeyCode :
503519 return await self ._switch_input (source )
504520
505- LOG .warning (
521+ _LOG .warning (
506522 "[%s] Unknown source parameter in select_source command: %s" ,
507- self ._identifier ,
523+ self .log_id ,
508524 source ,
509525 )
510526 return ucapi .StatusCodes .BAD_REQUEST
@@ -515,7 +531,7 @@ def _launch_app(self, app: str) -> ucapi.StatusCodes:
515531 self ._atv .send_launch_app_command (apps .Apps [app ]["url" ])
516532 return ucapi .StatusCodes .OK
517533 except ConnectionClosed :
518- LOG .error ("Cannot launch app, connection lost: %s " , self ._identifier )
534+ _LOG .error ("[%s] Cannot launch app, connection lost" , self .log_id )
519535 return ucapi .StatusCodes .SERVICE_UNAVAILABLE
520536
521537 async def _switch_input (self , source : str ) -> ucapi .StatusCodes :
0 commit comments