Skip to content

Commit 7fa9c4d

Browse files
committed
refactor: device instance log identifier
Improve log messages with friendly device name to easily associate log messages with multiple device instances.
1 parent 805253a commit 7fa9c4d

File tree

2 files changed

+64
-43
lines changed

2 files changed

+64
-43
lines changed

intg-androidtv/driver.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,17 +122,22 @@ async def media_player_cmd_handler(
122122
:param params: optional command parameters
123123
:return:
124124
"""
125-
_LOG.info("Got %s command request: %s %s", entity.id, cmd_id, params)
126-
127125
# Simple mapping at the moment: one entity per device (with the same id)
128126
atv_id = entity.id
129127

130128
if atv_id not in _configured_android_tvs:
131-
_LOG.warning("No Android TV device found for entity: %s", entity.id)
129+
_LOG.warning(
130+
"Cannot execute command %s %s: no Android TV device found for entity %s",
131+
cmd_id,
132+
params if params else "",
133+
entity.id,
134+
)
132135
return ucapi.StatusCodes.SERVICE_UNAVAILABLE
133136

134137
android_tv = _configured_android_tvs[atv_id]
135138

139+
_LOG.info("[%s] command: %s %s", android_tv.log_id, cmd_id, params if params else "")
140+
136141
if cmd_id == media_player.Commands.ON:
137142
return await android_tv.turn_on()
138143
if cmd_id == media_player.Commands.OFF:
@@ -174,7 +179,7 @@ async def handle_android_tv_address_change(atv_id: str, address: str) -> None:
174179
"""Update device configuration with changed IP address."""
175180
device = config.devices.get(atv_id)
176181
if device and device.address != address:
177-
_LOG.info("Updating IP address %s of configured ATV %s", address, atv_id)
182+
_LOG.info("Updating IP address %s of configured device %s", address, atv_id)
178183
device.address = address
179184
config.devices.update(device)
180185

@@ -186,7 +191,7 @@ async def handle_android_tv_update(atv_id: str, update: dict[str, Any]) -> None:
186191
:param atv_id: AndroidTV identifier
187192
:param update: dictionary containing the updated properties
188193
"""
189-
_LOG.debug("[%s] ATV update: %s", atv_id, update)
194+
_LOG.debug("[%s] device update: %s", atv_id, update)
190195

191196
attributes = {}
192197
# Simple mapping at the moment: one entity per device (with the same id)
@@ -251,7 +256,7 @@ def _add_configured_android_tv(device: config.AtvDevice, connect: bool = True) -
251256

252257
_configured_android_tvs[device.id] = android_tv
253258
_LOG.info(
254-
"Configured Android TV device '%s' (%s) with profile: %s %s",
259+
"[%s] Configured Android TV device %s with profile: %s %s",
255260
device.name,
256261
device.id,
257262
profile.manufacturer,

intg-androidtv/tv.py

Lines changed: 53 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
from pyee import AsyncIOEventEmitter
2727
from ucapi import media_player
2828

29-
LOG = logging.getLogger(__name__)
29+
_LOG = logging.getLogger(__name__)
3030

3131
BACKOFF_MAX = 30
3232
MIN_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

Comments
 (0)