fix: make sure all device_names logged are in quotes

pull/106/head
Jeff Culverhouse 2 months ago
parent 41ec32af47
commit b0100f0931

@ -27,10 +27,10 @@ class AmcrestMixin:
device_id = device.get("serial_number", "unknown")
exception_type = type(result).__name__
try:
device_display_name = self.get_device_name(device_id)
device_display_name = f"'{self.get_device_name(device_id)}'"
except KeyError:
device_display_name = device_id
self.logger.error(f"error during build_component for device '{device_name}' ({device_display_name}): " f"{exception_type}: {result}", exc_info=True)
device_display_name = f"({device_id})"
self.logger.error(f"error during build_component for device '{device_name}' {device_display_name}: " f"{exception_type}: {result}", exc_info=True)
elif result and isinstance(result, str):
seen_devices.add(result)
@ -38,7 +38,7 @@ class AmcrestMixin:
missing_devices = set(self.devices.keys()) - seen_devices
for device_id in missing_devices:
await self.publish_device_availability(device_id, online=False)
self.logger.warning(f"device {self.get_device_name(device_id)} not seen in Amcrest API list — marked offline")
self.logger.warning(f"device '{self.get_device_name(device_id)}' not seen in Amcrest API list — marked offline")
# Handle first discovery completion
if not self.discovery_complete:
@ -279,7 +279,7 @@ class AmcrestMixin:
)
if not self.is_discovered(device_id):
self.logger.info(f'added new camera: "{camera["device_name"]}" {camera["vendor"]} {camera["device_type"]}] ({self.get_device_name(device_id)})')
self.logger.info(f'added new camera: "{camera["device_name"]}" {camera["vendor"]} {camera["device_type"]}] (\'{self.get_device_name(device_id)}\')')
await self.publish_device_discovery(device_id)
await self.publish_device_availability(device_id, online=True)

@ -151,20 +151,20 @@ class AmcrestAPIMixin:
def reboot_device(self: Amcrest2Mqtt, device_id: str) -> None:
if device_id not in self.amcrest_devices:
self.logger.warning(f"device not found for {self.get_device_name(device_id)}")
self.logger.warning(f"device not found for '{self.get_device_name(device_id)}'")
return None
device = self.amcrest_devices[device_id]
if not device["camera"]:
self.logger.warning(f"camera not found for {self.get_device_name(device_id)}")
self.logger.warning(f"camera not found for '{self.get_device_name(device_id)}'")
return None
response = device["camera"].reboot().strip()
self.logger.debug(f"sent reboot signal to {self.get_device_name(device_id)}, {response}")
self.logger.debug(f"sent reboot signal to '{self.get_device_name(device_id)}', {response}")
if response == "OK":
self.upsert_state(device_id, internal={"reboot": datetime.now()})
self.logger.info(f"rebooted {self.get_device_name(device_id)}")
self.logger.info(f"rebooted '{self.get_device_name(device_id)}'")
return
self.logger.error(f"failed to reboot {self.get_device_name(device_id)}: {response}")
self.logger.error(f"failed to reboot '{self.get_device_name(device_id)}': {response}")
def is_rebooting(self: Amcrest2Mqtt, device_id: str) -> bool:
states = self.states[device_id]
@ -185,7 +185,7 @@ class AmcrestAPIMixin:
async def get_storage_stats(self: Amcrest2Mqtt, device_id: str) -> dict[str, str | float]:
if device_id not in self.amcrest_devices:
self.logger.warning(f"device not found for {self.get_device_name(device_id)}")
self.logger.warning(f"device not found for '{self.get_device_name(device_id)}'")
return {}
device = self.amcrest_devices[device_id]
@ -203,16 +203,16 @@ class AmcrestAPIMixin:
)
if not device["camera"]:
self.logger.warning(f"camera not found for {self.get_device_name(device_id)}")
self.logger.warning(f"camera not found for '{self.get_device_name(device_id)}'")
return current
try:
storage = cast(dict, await device["camera"].async_storage_all)
except CommError as err:
self.logger.error(f"failed to get storage stats from ({self.get_device_name(device_id)}): {err!r}")
self.logger.error(f"failed to get storage stats from ('{self.get_device_name(device_id)}'): {err!r}")
return current
except LoginError as err:
self.logger.error(f"failed to auth to ({self.get_device_name(device_id)}): {err!r}")
self.logger.error(f"failed to auth to ('{self.get_device_name(device_id)}'): {err!r}")
return current
self.increase_api_calls()
@ -227,7 +227,7 @@ class AmcrestAPIMixin:
async def get_privacy_mode(self: Amcrest2Mqtt, device_id: str) -> bool:
if device_id not in self.amcrest_devices:
self.logger.warning(f"device not found for {self.get_device_name(device_id)}")
self.logger.warning(f"device not found for '{self.get_device_name(device_id)}'")
return False
device = self.amcrest_devices[device_id]
@ -236,16 +236,16 @@ class AmcrestAPIMixin:
current = True if "sensor" in states and states["sensor"].get("privacy", "OFF") == "ON" else False
if not device["camera"]:
self.logger.warning(f"camera not found for {self.get_device_name(device_id)}")
self.logger.warning(f"camera not found for '{self.get_device_name(device_id)}'")
return current
try:
response = await device["camera"].async_privacy_config()
except CommError as err:
self.logger.error(f"failed to get privacy mode from ({self.get_device_name(device_id)}): {err!r}")
self.logger.error(f"failed to get privacy mode from ('{self.get_device_name(device_id)}'): {err!r}")
return current
except LoginError as err:
self.logger.error(f"failed to auth to device ({self.get_device_name(device_id)}): {err!r}")
self.logger.error(f"failed to auth to device ('{self.get_device_name(device_id)}'): {err!r}")
return current
self.increase_api_calls()
@ -266,7 +266,7 @@ class AmcrestAPIMixin:
break
if enable_value is None:
self.logger.warning(f"failed to get privacy mode from ({self.get_device_name(device_id)}), got: {type(privacy)} with value: {privacy}")
self.logger.warning(f"failed to get privacy mode from ('{self.get_device_name(device_id)}'), got: {type(privacy)} with value: {privacy}")
return current
privacy_mode = bool(enable_value.lower() == "true")
@ -274,36 +274,36 @@ class AmcrestAPIMixin:
async def set_privacy_mode(self: Amcrest2Mqtt, device_id: str, switch: bool) -> None:
if device_id not in self.amcrest_devices:
self.logger.warning(f"device not found for {self.get_device_name(device_id)}")
self.logger.warning(f"device not found for '{self.get_device_name(device_id)}'")
return None
device = self.amcrest_devices[device_id]
if not device["camera"]:
self.logger.warning(f"camera not found for {self.get_device_name(device_id)}")
self.logger.warning(f"camera not found for '{self.get_device_name(device_id)}'")
return None
camera = device["camera"]
try:
response = str(await camera.async_set_privacy(switch)).strip()
except CommError as err:
self.logger.error(f"failed to set privacy mode on ({self.get_device_name(device_id)}): {err!r}")
self.logger.error(f"failed to set privacy mode on ('{self.get_device_name(device_id)}'): {err!r}")
except LoginError as err:
self.logger.error(f"failed to auth to device ({self.get_device_name(device_id)}): {err!r}")
self.logger.error(f"failed to auth to device ('{self.get_device_name(device_id)}'): {err!r}")
self.increase_api_calls()
self.logger.debug(f"set privacy_mode on {self.get_device_name(device_id)} to {switch}, got back: {response}")
self.logger.debug(f"set privacy_mode on '{self.get_device_name(device_id)}' to {switch}, got back: {response}")
if response == "OK":
self.upsert_state(device_id, switch={"privacy": "ON" if switch else "OFF"})
await self.publish_device_state(device_id)
return None
self.logger.error(f"failed to set privacy mode on ({self.get_device_name(device_id)}): {response}")
self.logger.error(f"failed to set privacy mode on ('{self.get_device_name(device_id)}'): {response}")
return None
# Motion detection config ---------------------------------------------------------------------
async def get_motion_detection(self: Amcrest2Mqtt, device_id: str) -> bool:
if device_id not in self.amcrest_devices:
self.logger.warning(f"device not found for {self.get_device_name(device_id)}")
self.logger.warning(f"device not found for '{self.get_device_name(device_id)}'")
return False
device = self.amcrest_devices[device_id]
@ -313,16 +313,16 @@ class AmcrestAPIMixin:
current = True if "sensor" in states and states["sensor"].get("motion_detection", "OFF") == "ON" else False
if not device["camera"]:
self.logger.warning(f"camera not found for {self.get_device_name(device_id)}")
self.logger.warning(f"camera not found for '{self.get_device_name(device_id)}'")
return current
try:
motion_detection = bool(await device["camera"].async_is_motion_detector_on())
except CommError as err:
self.logger.error(f"failed to get motion detection switch on ({self.get_device_name(device_id)}): {err!r}")
self.logger.error(f"failed to get motion detection switch on ('{self.get_device_name(device_id)}'): {err!r}")
return current
except LoginError as err:
self.logger.error(f"failed to auth to device ({self.get_device_name(device_id)}): {err!r}")
self.logger.error(f"failed to auth to device ('{self.get_device_name(device_id)}'): {err!r}")
return current
self.increase_api_calls()
@ -330,24 +330,24 @@ class AmcrestAPIMixin:
async def set_motion_detection(self: Amcrest2Mqtt, device_id: str, switch: bool) -> None:
if device_id not in self.amcrest_devices:
self.logger.warning(f"device not found for {self.get_device_name(device_id)}")
self.logger.warning(f"device not found for '{self.get_device_name(device_id)}'")
return None
device = self.amcrest_devices[device_id]
if not device["camera"]:
self.logger.warning(f"camera not found for {self.get_device_name(device_id)}")
self.logger.warning(f"camera not found for '{self.get_device_name(device_id)}'")
return None
camera = device["camera"]
try:
response = bool(await camera.async_set_motion_detection(switch))
except CommError:
self.logger.error(f"failed to communicate with device ({self.get_device_name(device_id)}) to set motion detections")
self.logger.error(f"failed to communicate with device ('{self.get_device_name(device_id)}') to set motion detections")
except LoginError:
self.logger.error(f"failed to authenticate with device ({self.get_device_name(device_id)}) to set motion detections")
self.logger.error(f"failed to authenticate with device ('{self.get_device_name(device_id)}') to set motion detections")
self.increase_api_calls()
self.logger.debug(f"set motion_detection on {self.get_device_name(device_id)} to {switch}, got back: {response}")
self.logger.debug(f"set motion_detection on '{self.get_device_name(device_id)}' to {switch}, got back: {response}")
if response:
self.upsert_state(device_id, switch={"motion_detection": "ON" if switch else "OFF"})
await self.publish_device_state(device_id)
@ -357,7 +357,7 @@ class AmcrestAPIMixin:
async def get_snapshot_from_device(self: Amcrest2Mqtt, device_id: str) -> str | None:
if device_id not in self.amcrest_devices:
self.logger.warning(f"device not found for {self.get_device_name(device_id)}")
self.logger.warning(f"device not found for '{self.get_device_name(device_id)}'")
return None
device = self.amcrest_devices[device_id]
@ -367,11 +367,11 @@ class AmcrestAPIMixin:
# Respect privacy mode (default False if missing)
if device.get("privacy_mode", False):
self.logger.info(f"skipping snapshot for {self.get_device_name(device_id)} (privacy mode ON)")
self.logger.info(f"skipping snapshot for '{self.get_device_name(device_id)}' (privacy mode ON)")
return None
if not device["camera"]:
self.logger.warning(f"camera not found for {self.get_device_name(device_id)}")
self.logger.warning(f"camera not found for '{self.get_device_name(device_id)}'")
return None
camera = device["camera"]
@ -381,11 +381,11 @@ class AmcrestAPIMixin:
if self.is_rebooting(device_id):
return None
self.logger.debug(f"getting snapshot from {self.get_device_name(device_id)}")
self.logger.debug(f"getting snapshot from '{self.get_device_name(device_id)}'")
image_bytes = await asyncio.wait_for(camera.async_snapshot(), timeout=timeout)
self.increase_api_calls()
if not image_bytes:
self.logger.warning(f"snapshot: empty image from {self.get_device_name(device_id)}, ignoring")
self.logger.warning(f"snapshot: empty image from '{self.get_device_name(device_id)}', ignoring")
return None
encoded_b = base64.b64encode(image_bytes)
@ -397,28 +397,28 @@ class AmcrestAPIMixin:
)
await self.publish_device_state(device_id)
self.logger.debug(f"got snapshot from {self.get_device_name(device_id)} {len(image_bytes)} raw bytes -> {len(encoded)} b64 chars")
self.logger.debug(f"got snapshot from '{self.get_device_name(device_id)}' {len(image_bytes)} raw bytes -> {len(encoded)} b64 chars")
return encoded
except (CommError, LoginError, asyncio.TimeoutError, Exception) as err:
self.logger.debug(f"snapshot attempt {attempt}/{max_tries} failed for {self.get_device_name(device_id)}: {err!r}")
self.logger.debug(f"snapshot attempt {attempt}/{max_tries} failed for '{self.get_device_name(device_id)}': {err!r}")
except asyncio.CancelledError:
self.logger.debug(f"snapshot cancelled for {self.get_device_name(device_id)}, letting shutdown propagate")
self.logger.debug(f"snapshot cancelled for '{self.get_device_name(device_id)}', letting shutdown propagate")
raise
delay = base_backoff * (2 ** (attempt - 1))
delay += random.uniform(0, 5)
await asyncio.sleep(delay)
self.logger.info(f"getting snapshot failed after {max_tries} tries for {self.get_device_name(device_id)}")
self.logger.info(f"getting snapshot failed after {max_tries} tries for '{self.get_device_name(device_id)}'")
return None
# Recorded file -------------------------------------------------------------------------------
async def get_recorded_file(self: Amcrest2Mqtt, device_id: str, file: str, encode: bool = True) -> str | None:
if device_id not in self.amcrest_devices:
self.logger.warning(f"device not found for {self.get_device_name(device_id)}")
self.logger.warning(f"device not found for '{self.get_device_name(device_id)}'")
return None
device = self.amcrest_devices[device_id]
@ -440,7 +440,7 @@ class AmcrestAPIMixin:
return None
data_base64 = base64.b64encode(data_raw)
self.logger.debug(
f"processed recording from ({self.get_device_name(device_id)}) {len(data_raw)} bytes raw, and {len(data_base64)} bytes base64"
f"processed recording from ('{self.get_device_name(device_id)}') {len(data_raw)} bytes raw, and {len(data_base64)} bytes base64"
)
if len(data_base64) < self.mb_to_b(100):
return data_raw.decode("latin-1")
@ -448,13 +448,13 @@ class AmcrestAPIMixin:
self.logger.error(f"skipping recording, too large: {self.b_to_mb(len(data_base64))} MB")
return None
except CommError as err:
self.logger.debug(f"failed to get recording from ({self.get_device_name(device_id)}) on attempt {attempt}: {err!r}")
self.logger.debug(f"failed to get recording from ('{self.get_device_name(device_id)}') on attempt {attempt}: {err!r}")
except LoginError as err:
self.logger.debug(f"failed to get recording from ({self.get_device_name(device_id)}) on attempt {attempt}: {err!r}")
self.logger.debug(f"failed to get recording from ('{self.get_device_name(device_id)}') on attempt {attempt}: {err!r}")
except Exception as err: # noqa: BLE001 (log-and-drop is intentional here)
self.logger.debug(f"failed to get recording from ({self.get_device_name(device_id)}) on attempt {attempt}: {err!r}")
self.logger.debug(f"failed to get recording from ('{self.get_device_name(device_id)}') on attempt {attempt}: {err!r}")
self.logger.error(f"failed to get recording from ({self.get_device_name(device_id)}) after {max_attempts} attempts")
self.logger.error(f"failed to get recording from ('{self.get_device_name(device_id)}') after {max_attempts} attempts")
return None
# Events --------------------------------------------------------------------------------------
@ -462,7 +462,7 @@ class AmcrestAPIMixin:
async def get_events_from_device(self: Amcrest2Mqtt, device_id: str) -> None:
device = self.amcrest_devices[device_id]
if not device["camera"]:
self.logger.warning(f"camera not found for {self.get_device_name(device_id)}")
self.logger.warning(f"camera not found for '{self.get_device_name(device_id)}'")
return None
camera = device["camera"]
@ -478,17 +478,17 @@ class AmcrestAPIMixin:
self.increase_api_calls()
return
except CommError as err:
self.logger.debug(f"failed to get events from ({self.get_device_name(device_id)}) on attempt {attempt}: {err!r}")
self.logger.debug(f"failed to get events from ('{self.get_device_name(device_id)}') on attempt {attempt}: {err!r}")
except LoginError as err:
self.logger.debug(f"failed to get events from ({self.get_device_name(device_id)}) on attempt {attempt}: {err!r}")
self.logger.debug(f"failed to get events from ('{self.get_device_name(device_id)}') on attempt {attempt}: {err!r}")
except Exception as err: # noqa: BLE001 (log-and-drop is intentional here)
self.logger.debug(f"failed to get events from ({self.get_device_name(device_id)}) on attempt {attempt}: {err!r}")
self.logger.debug(f"failed to get events from ('{self.get_device_name(device_id)}') on attempt {attempt}: {err!r}")
self.logger.error(f"failed to check for events on ({self.get_device_name(device_id)}) after {max_attempts} attempts ")
self.logger.error(f"failed to check for events on ('{self.get_device_name(device_id)}') after {max_attempts} attempts ")
async def process_device_event(self: Amcrest2Mqtt, device_id: str, code: str, payload: Any) -> None:
if device_id not in self.amcrest_devices:
self.logger.warning(f"device not found for {self.get_device_name(device_id)}")
self.logger.warning(f"device not found for '{self.get_device_name(device_id)}'")
return None
device = self.amcrest_devices[device_id]
@ -529,10 +529,10 @@ class AmcrestAPIMixin:
# save everything else as a 'generic' event
else:
self.logger.info(f"logged event on {self.get_device_name(device_id)} - {code}: {payload}")
self.logger.info(f"logged event on '{self.get_device_name(device_id)}' - {code}: {payload}")
self.events.append({"device_id": device_id, "event": code, "payload": payload})
except Exception as err:
self.logger.error(f"failed to process event from {self.get_device_name(device_id)}: {err!r}")
self.logger.error(f"failed to process event from '{self.get_device_name(device_id)}': {err!r}")
def get_next_event(self: Amcrest2Mqtt) -> dict[str, Any] | None:
return self.events.pop(0) if len(self.events) > 0 else None

@ -23,7 +23,7 @@ class EventsMixin:
# if one of our known sensors
if event in ["motion", "human", "doorbell", "recording", "privacy_mode", "Reboot"]:
if event == "recording" and "file" in payload:
self.logger.debug(f'recording event for "{self.get_device_name(device_id)}": {payload["file"]}')
self.logger.debug(f'recording event for \'{self.get_device_name(device_id)}\': {payload["file"]}')
if payload["file"].endswith(".jpg"):
image = await self.get_recorded_file(device_id, payload["file"])
if image:
@ -65,11 +65,11 @@ class EventsMixin:
# record just these "events": text and time
self.upsert_state(device_id, sensor={"event_text": event})
needs_publish.add(device_id)
self.logger.debug(f'processed event for "{self.get_device_name(device_id)}": {event} with {payload}')
self.logger.debug(f'processed event for \'{self.get_device_name(device_id)}\': {event} with {payload}')
else:
# we ignore these on purpose, but log if something unexpected comes through
if event not in ["NtpAdjustTime", "TimeChange", "RtspSessionDisconnect"]:
self.logger.debug(f'ignored unexpected event for "{self.get_device_name(device_id)}": {event} with {payload}')
self.logger.debug(f'ignored unexpected event for \'{self.get_device_name(device_id)}\': {event} with {payload}')
tasks = [self.publish_device_state(device_id) for device_id in needs_publish]
if tasks:

@ -30,7 +30,7 @@ class ConfigError(ValueError):
class HelpersMixin:
async def build_device_states(self: Amcrest2Mqtt, device_id: str) -> bool:
if self.is_rebooting(device_id):
self.logger.debug(f"skipping device states for {self.get_device_name(device_id)}, still rebooting")
self.logger.debug(f"skipping device states for '{self.get_device_name(device_id)}', still rebooting")
return False
# get properties from device

@ -62,10 +62,10 @@ class MqttMixin(BaseMqttMixin):
self.logger.error(f"failed to parse device_id and/or payload from mqtt topic components: {components}")
return
if not self.devices.get(device_id, None):
self.logger.warning(f"got Mqtt message for unknown device: {device_id}")
self.logger.warning(f"got Mqtt message for unknown device: ({device_id})")
return
self.logger.info(f"got message for {self.get_device_name(device_id)}: set {components[-2]} to {payload}")
self.logger.info(f"got message for '{self.get_device_name(device_id)}': set {components[-2]} to {payload}")
await self.handle_device_command(device_id, attribute, payload)
def _parse_device_topic(self: Amcrest2Mqtt, components: list[str]) -> list[str | None] | None:

@ -22,7 +22,7 @@ class RefreshMixin:
tasks = []
for device_id in self.devices:
if self.is_rebooting(device_id):
self.logger.debug(f"skipping refresh for {self.get_device_name(device_id)}, still rebooting")
self.logger.debug(f"skipping refresh for '{self.get_device_name(device_id)}', still rebooting")
continue
tasks.append(_refresh(device_id))
if tasks:
@ -32,7 +32,7 @@ class RefreshMixin:
tasks = []
for device_id in self.amcrest_devices:
if self.is_rebooting(device_id):
self.logger.debug(f"skipping collecting events for {self.get_device_name(device_id)}, still rebooting")
self.logger.debug(f"skipping collecting events for '{self.get_device_name(device_id)}', still rebooting")
continue
tasks.append(self.get_events_from_device(device_id))
@ -44,7 +44,7 @@ class RefreshMixin:
tasks = []
for device_id in self.amcrest_devices:
if self.is_rebooting(device_id):
self.logger.debug(f"skipping snapshot for {self.get_device_name(device_id)}, still rebooting")
self.logger.debug(f"skipping snapshot for '{self.get_device_name(device_id)}', still rebooting")
continue
tasks.append(self.get_snapshot_from_device(device_id))

Loading…
Cancel
Save