Life360 conversion to entity-based device tracker - Testers Needed

The Life360 Integration is a “legacy” device tracker, meaning it still uses the old Device Tracker mechanisms. E.g., it still uses the known_devices.yaml file. I’ve worked on updating it to the new “entity based” mechanism (like many device tracker integrations did back in the 0.94 days.) This change is long overdue.

Before submitting it for inclusion in an upcoming Home Assistant release, I’d like to get some people to test it out (besides myself) to make sure I didn’t overlook anything, and to get feedback if there are any minor tweaks users might want.

If you use the Life360 integration, and would be willing to test the changes for me and provide feedback (good or bad), then check out a custom integration version in this github repo. Please provide feedback here, or on that repo’s Issues page.

NOTE: This test project only supports the English language configuration (which should not be confused with “English (GB)”.)

If you are using any other language selection, then you should do one of the following, or you should probably not try to use this.

  1. Temporarily change your configuration to “English”.
  2. Copy en.json in custom_components/life360/translations to another file appropriate for your language configuration. (Sorry, can’t really help here as to what to name the new file.) Optionally edit the new file to translate the strings to your language.
1 Like

I converted life360 on my dev version of HA and see one difference between my prod version and dev version. Looks like “raw_speed” is not there (not that I ever use that). Just want to make sure this is expected. Initial observation is everything seems to be working as previously.
**edit - sorry, actually 2 differences. “speed: 0” and “speed: unknown”

dev version:
source_type: gps
battery_level: 85
latitude: xx.xxxxxxx
longitude: -xx.xxxxx
gps_accuracy: 15
address: Home
at_loc_since: 2022-05-16T21:04:52+00:00
battery_charging: true
last_seen: 2022-05-17T00:43:10+00:00
place: Home
speed: 0
wifi_on: true
driving: false
attribution: Data provided by life360.com
entity_picture: https://www.life360.com/img/user_images/ecd5a267-c501-4731-b382-de34d32f1c6e/6ac39b2d-fd2e-400f-a5bc-b53e5c86643f.png?fd=xx
friendly_name: xxxx

prod version:
source_type: gps
latitude: xx.xxxxx
longitude: -xx.xxxxx
gps_accuracy: 15
battery: 85
address: Home
at_loc_since: 2022-05-16T21:04:52+00:00
battery_charging: true
driving: false
last_seen: 2022-05-17T00:43:10+00:00
moving: false
place: Home
raw_speed: null
speed: unknown
wifi_on: true
entity_picture: https://www.life360.com/img/user_images/ecd5a267-c501-4731-b382-de34d32f1c6e/6ac39b2d-fd2e-400f-a5bc-b53e5c86643f.png?fdxx
friendly_name: life360_xxx

just tried installing it by copying the life360 folder to the custom_components directory.

it shows up fine in the integrations list after restart but when trying to configure the integration in the UI with no options selected and just putting in my user/password I get the following error - “User input malformed: expected bool for dictionary value @ data[‘driving’]”.

Then if I tick the “show driving as state” check box I then get the following error - “Unknown error occurred”.

in the logs I see this:

2022-05-17 08:42:04 ERROR (MainThread) [aiohttp.server] Error handling request
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/aiohttp/web_protocol.py", line 435, in _handle_request
    resp = await request_handler(request)
  File "/usr/local/lib/python3.9/site-packages/aiohttp/web_app.py", line 504, in _handle
    resp = await handler(request)
  File "/usr/local/lib/python3.9/site-packages/aiohttp/web_middlewares.py", line 117, in impl
    return await handler(request)
  File "/usr/src/homeassistant/homeassistant/components/http/security_filter.py", line 60, in security_filter_middleware
    return await handler(request)
  File "/usr/src/homeassistant/homeassistant/components/http/forwarded.py", line 100, in forwarded_middleware
    return await handler(request)
  File "/usr/src/homeassistant/homeassistant/components/http/request_context.py", line 28, in request_context_middleware
    return await handler(request)
  File "/usr/src/homeassistant/homeassistant/components/http/ban.py", line 79, in ban_middleware
    return await handler(request)
  File "/usr/src/homeassistant/homeassistant/components/http/auth.py", line 219, in auth_middleware
    return await handler(request)
  File "/usr/src/homeassistant/homeassistant/components/http/view.py", line 137, in handle
    result = await result
  File "/usr/src/homeassistant/homeassistant/components/config/config_entries.py", line 205, in post
    return await super().post(request, flow_id)
  File "/usr/src/homeassistant/homeassistant/components/http/data_validator.py", line 62, in wrapper
    result = await method(view, request, *args, **kwargs)
  File "/usr/src/homeassistant/homeassistant/helpers/data_entry_flow.py", line 109, in post
    result = await self._flow_mgr.async_configure(flow_id, data)
  File "/usr/src/homeassistant/homeassistant/data_entry_flow.py", line 260, in async_configure
    result = await self._async_handle_step(
  File "/usr/src/homeassistant/homeassistant/data_entry_flow.py", line 335, in _async_handle_step
    result: FlowResult = await getattr(flow, method)(user_input)
  File "/config/custom_components/life360/config_flow.py", line 151, in async_step_user
    return await self._async_verify("user")
  File "/config/custom_components/life360/config_flow.py", line 121, in _async_verify
    self.hass.data[DOMAIN]["accounts"][cast(str, self.unique_id)] = AccountData(
KeyError: 'life360'

Using Supervised on latest HA version as a test bed.

First off, thank you very much for giving this a try. Much appreciated!

Yes, I got rid of the raw_speed attribute. It was pretty much useless. I should make a note of that.

Update: BTW, as hinted at, I also removed the moving attribute. And lastly, you’ll also note that the battery attribute got changed to battery_level. This is a function of the device tracker component level software – it uses battery with legacy trackers and battery_level with new entity-based trackers.

Regarding the difference in the speed attribute, yeah, that’s a bug in the prod version. The “raw” speed returned from the server is probably the int value zero, but the code is incorrectly changing that to None, which prints as null. And since that is None, it’s setting the speed attribute to unknown. The value shown by the dev version is actually correct.

First off, thank you very much for giving this a try. Much appreciated!

I’ll try to get a fix for this ASAP.

Ok, found and fixed both bugs, and released as version 0.0.2.

I had recently been focusing my testing on upgrading a system that already had Life360 config entries and forgot to go back and test adding an entry on a system that did not have any existing entries.

THANKS! Let me know if this fixes the problems for you.

So far so good. everything installed correctly.

I’ll watch it over time to see how the old one vs the new one compares.

1 Like

I have been using this for a few days now and everything seems to be reporting correctly. The attributes all seem to match my current prod version. No issues so far.

1 Like

Completely convinced this will be my doing, removed my previous set up and followed your instructions but on configuring I get a translation error - any pointers would be appreciated - I wondered if its referring to the documentation link which is pointing my instance of HA in the absence of anything else?

Translation Error: The intl string context variable “docs_url” was not provided to the string “To set advanced options, see Life360 documentation.
You may want to do that before adding accounts.”

image

Hmm, that looks a bit weird. But, no, I don’t think it’s anything you’re doing wrong.

First off, I should probably have mentioned that I only provided English translations in the test project. I have no idea how to get all the translations. That’s something that happens automagically for built-in integrations. I don’t know how to do it for a custom integration.

Having said that, it appears to be trying to use the strings JSON file(s) from the built-in integration, not the custom integration (because the custom one doesn’t have the string “To set advanced…”.) I.e., I’m assuming your system is configured for a different language. So, HA tries to find the corresponding .json file in custom_components/life360/translations, but when it doesn’t find it, it then tries finding it in homeassistant/components/life360/translations and finds it. But that’s the wrong one!

Bottom line, I don’t know how to provide all the language translations for the test custom integration, so either you’ll need to temporarily reconfigure your system to English, which I doubt you’ll want to do, or I guess you can’t use this.

Or, maybe you could copy custom_components/life360/translations/en.json to an appropriate xxx.json file (into custom_components/life360/translations.) At the very least it should work (but the strings will still be in English, unless you want to convert them in the xxx.json file.)

Does that make sense?

1 Like

I was in English but it was English (GB). Switching to straight English fixed that, thanks for the quick response!!

1 Like

Installed tonight using the “Install, run and reconfigure” instruction and everything working fine first time.

Thanks for the work on this Phil :+1:t2:

1 Like

Pull request submitted:

Convert life360 integration to entity based by pnbruckner · Pull Request #72461 · home-assistant/core (github.com)

1 Like

Maybe i posted this to the wrong place…
Please read it.

Hi. I’m getting an error: Retrying setup: ‘NoneType’ object is not subscriptable.

From the log details:
This error originated from a custom integration.

Logger: custom_components.life360
Source: custom_components/life360/helpers.py:171
Integration: Life360 (documentation, issues)
First occurred: 11:14:19 PM (5 occurrences)
Last logged: 11:16:15 PM

Unexpected error fetching life360 ([email protected]) data: ‘NoneType’ object is not subscriptable
Traceback (most recent call last):
File “/usr/src/homeassistant/homeassistant/helpers/update_coordinator.py”, line 191, in _async_refresh
self.data = await self._async_update_data()
File “/usr/src/homeassistant/homeassistant/helpers/update_coordinator.py”, line 150, in _async_update_data
return await self.update_method()
File “/config/custom_components/life360/init.py”, line 154, in async_update_data
return await get_life360_data(hass, api)
File “/config/custom_components/life360/helpers.py”, line 171, in get_life360_data
place = loc[“name”] or “None”
TypeError: ‘NoneType’ object is not subscriptable

Is it possible one of the Circle Member’s phone is offline?

I had a test for this condition in the original “legacy” implementation, but got rid of it. I guess I need to add it back in.

Thanks!

Released 0.0.3

Adds check for missing location information (like legacy integration used to do.)

@Rudysmama let me know if this eliminates the exception (and adds a proper error message to the log.) Thx!

2 Likes

@pnbruckner I am no longer getting the error! Thanks for the quick response. Now if I can figure out how to pull the battery data for my dashboard purposes. :slight_smile: Thanks again.

To all who have tried this out:

First, thank you again! You have caught at least two bugs that probably would have affected many users. I very much appreciate it!

Second, the implementation in the PR submitted for the official built-in integration has changed such that the version number for the config entry storage is not changing from 1 to 2 (as in my initial implementation, which this custom integration version uses.) That means you will definitely need to back out this change from your system (and restore the configuration & known_devices.yaml) before upgrading HA to the version that will (hopefully) eventually contain the updated integration (i.e., once the PR is approved and merged.)

1 Like

Glad to hear it, and thanks for exposing this bug. I think I already knew I needed to fix this, but it helps to get verification.

BTW, there still should be an error, right? I mean, instead of the exception there should now be a “proper” error message in the log. Do you see one? If so, I’d be really interested to know exactly what it says.

As far as pulling out the battery data:

sensor:
  - platform: template
    sensors:
      phone_battery:
        friendly_name: Phone battery
        value_template: "{{ state_attr('device_tracker.XXX', 'battery_level') }}"
        unit_of_measurement: "%"

Or in the new format:

template:
  - sensor:
      - name: Phone battery
        unit_of_measurement: "%"
        state: "{{ state_attr('device_tracker.XXX', 'battery_level') }}"