Do not spam log when Life360 member location is missing (#75029)

This commit is contained in:
Phil Bruckner 2022-07-12 01:42:33 -05:00 committed by GitHub
parent 5d8e1b8387
commit f4953e6e9b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 54 additions and 14 deletions

View File

@ -37,7 +37,7 @@ from .const import (
SHOW_DRIVING, SHOW_DRIVING,
SHOW_MOVING, SHOW_MOVING,
) )
from .coordinator import Life360DataUpdateCoordinator from .coordinator import Life360DataUpdateCoordinator, MissingLocReason
PLATFORMS = [Platform.DEVICE_TRACKER] PLATFORMS = [Platform.DEVICE_TRACKER]
@ -128,6 +128,10 @@ class IntegData:
coordinators: dict[str, Life360DataUpdateCoordinator] = field( coordinators: dict[str, Life360DataUpdateCoordinator] = field(
init=False, default_factory=dict init=False, default_factory=dict
) )
# member_id: missing location reason
missing_loc_reason: dict[str, MissingLocReason] = field(
init=False, default_factory=dict
)
# member_id: ConfigEntry.entry_id # member_id: ConfigEntry.entry_id
tracked_members: dict[str, str] = field(init=False, default_factory=dict) tracked_members: dict[str, str] = field(init=False, default_factory=dict)
logged_circles: list[str] = field(init=False, default_factory=list) logged_circles: list[str] = field(init=False, default_factory=list)

View File

@ -2,8 +2,10 @@
from __future__ import annotations from __future__ import annotations
from contextlib import suppress
from dataclasses import dataclass, field from dataclasses import dataclass, field
from datetime import datetime from datetime import datetime
from enum import Enum
from typing import Any from typing import Any
from life360 import Life360, Life360Error, LoginError from life360 import Life360, Life360Error, LoginError
@ -33,6 +35,13 @@ from .const import (
) )
class MissingLocReason(Enum):
"""Reason member location information is missing."""
VAGUE_ERROR_REASON = "vague error reason"
EXPLICIT_ERROR_REASON = "explicit error reason"
@dataclass @dataclass
class Life360Place: class Life360Place:
"""Life360 Place data.""" """Life360 Place data."""
@ -99,6 +108,7 @@ class Life360DataUpdateCoordinator(DataUpdateCoordinator):
max_retries=COMM_MAX_RETRIES, max_retries=COMM_MAX_RETRIES,
authorization=entry.data[CONF_AUTHORIZATION], authorization=entry.data[CONF_AUTHORIZATION],
) )
self._missing_loc_reason = hass.data[DOMAIN].missing_loc_reason
async def _retrieve_data(self, func: str, *args: Any) -> list[dict[str, Any]]: async def _retrieve_data(self, func: str, *args: Any) -> list[dict[str, Any]]:
"""Get data from Life360.""" """Get data from Life360."""
@ -141,10 +151,7 @@ class Life360DataUpdateCoordinator(DataUpdateCoordinator):
if not int(member["features"]["shareLocation"]): if not int(member["features"]["shareLocation"]):
continue continue
# Note that member may be in more than one circle. If that's the case just member_id = member["id"]
# go ahead and process the newly retrieved data (overwriting the older
# data), since it might be slightly newer than what was retrieved while
# processing another circle.
first = member["firstName"] first = member["firstName"]
last = member["lastName"] last = member["lastName"]
@ -153,16 +160,45 @@ class Life360DataUpdateCoordinator(DataUpdateCoordinator):
else: else:
name = first or last name = first or last
loc = member["location"] cur_missing_reason = self._missing_loc_reason.get(member_id)
if not loc:
if err_msg := member["issues"]["title"]: # Check if location information is missing. This can happen if server
if member["issues"]["dialog"]: # has not heard from member's device in a long time (e.g., has been off
err_msg += f": {member['issues']['dialog']}" # for a long time, or has lost service, etc.)
else: if loc := member["location"]:
err_msg = "Location information missing" with suppress(KeyError):
LOGGER.error("%s: %s", name, err_msg) del self._missing_loc_reason[member_id]
else:
if explicit_reason := member["issues"]["title"]:
if extended_reason := member["issues"]["dialog"]:
explicit_reason += f": {extended_reason}"
# Note that different Circles can report missing location in
# different ways. E.g., one might report an explicit reason and
# another does not. If a vague reason has already been logged but a
# more explicit reason is now available, log that, too.
if (
cur_missing_reason is None
or cur_missing_reason == MissingLocReason.VAGUE_ERROR_REASON
and explicit_reason
):
if explicit_reason:
self._missing_loc_reason[
member_id
] = MissingLocReason.EXPLICIT_ERROR_REASON
err_msg = explicit_reason
else:
self._missing_loc_reason[
member_id
] = MissingLocReason.VAGUE_ERROR_REASON
err_msg = "Location information missing"
LOGGER.error("%s: %s", name, err_msg)
continue continue
# Note that member may be in more than one circle. If that's the case
# just go ahead and process the newly retrieved data (overwriting the
# older data), since it might be slightly newer than what was retrieved
# while processing another circle.
place = loc["name"] or None place = loc["name"] or None
if place: if place:
@ -179,7 +215,7 @@ class Life360DataUpdateCoordinator(DataUpdateCoordinator):
if self._hass.config.units.is_metric: if self._hass.config.units.is_metric:
speed = convert(speed, LENGTH_MILES, LENGTH_KILOMETERS) speed = convert(speed, LENGTH_MILES, LENGTH_KILOMETERS)
data.members[member["id"]] = Life360Member( data.members[member_id] = Life360Member(
address, address,
dt_util.utc_from_timestamp(int(loc["since"])), dt_util.utc_from_timestamp(int(loc["since"])),
bool(int(loc["charge"])), bool(int(loc["charge"])),