Giter VIP home page Giter VIP logo

pytile's Introduction

📡 pytile: A simple Python API for Tile® Bluetooth trackers

CI PyPI Version License Code Coverage Maintainability

Buy Me A Coffee

pytile is a simple Python library for retrieving information on Tile® Bluetooth trackers (including last location and more).

This library is built on an unpublished, unofficial Tile API; it may alter or cease operation at any point.

NOTE: Version 5.0.0

Version 5.0.0 is a complete re-architecture of pytile – as such, the API has changed. Please read the documentation carefully!

Python Versions

pytile is currently supported on:

  • Python 3.10
  • Python 3.11
  • Python 3.12

Installation

pip install pytile

Usage

Getting an API Object

pytile usage starts with an aiohttp ClientSession – note that this ClientSession is required to properly authenticate the library:

import asyncio

from aiohttp import ClientSession

from pytile import async_login


async def main() -> None:
    """Run!"""
    async with ClientSession() as session:
        api = await async_login("<EMAIL>", "<PASSWORD>", session)


asyncio.run(main())

If for some reason you need to use a specific client UUID (to, say, ensure that the Tile API sees you as a client it's seen before) or a specific locale, you can do so easily:

import asyncio

from aiohttp import ClientSession

from pytile import async_login


async def main() -> None:
    """Run!"""
    async with ClientSession() as session:
        api = await async_login(
            "<EMAIL>", "<PASSWORD>", session, client_uuid="MY_UUID", locale="en-GB"
        )


asyncio.run(main())

Getting Tiles

Tile Premium Required: No

import asyncio

from aiohttp import ClientSession

from pytile import async_login


async def main() -> None:
    """Run!"""
    async with ClientSession() as session:
        api = await async_login("<EMAIL>", "<PASSWORD>", session)

        tiles = await api.async_get_tiles()


asyncio.run(main())

The async_get_tiles coroutine returns a dict with Tile UUIDs as the keys and Tile objects as the values.

The Tile Object

The Tile object comes with several properties:

  • accuracy: the location accuracy of the Tile
  • altitude: the altitude of the Tile
  • archetype: the internal reference string that describes the Tile's "family"
  • dead: whether the Tile is inactive
  • firmware_version: the Tile's firmware version
  • hardware_version: the Tile's hardware version
  • kind: the kind of Tile (e.g., TILE, PHONE)
  • last_timestamp: the timestamp at which the current attributes were received
  • latitude: the latitude of the Tile
  • longitude: the latitude of the Tile
  • lost: whether the Tile has been marked as "lost"
  • lost_timestamp: the timestamp at which the Tile was last marked as "lost"
  • name: the name of the Tile
  • uuid: the Tile UUID
  • visible: whether the Tile is visible in the mobile app
import asyncio

from aiohttp import ClientSession

from pytile import async_login


async def main() -> None:
    """Run!"""
    async with ClientSession() as session:
        api = await async_login("<EMAIL>", "<PASSWORD>", session)

        tiles = await api.async_get_tiles()

        for tile_uuid, tile in tiles.items():
            print(f"The Tile's name is {tile.name}")
            # ...


asyncio.run(main())

In addition to these properties, the Tile object comes with an async_update coroutine which requests new data from the Tile cloud API for this Tile:

import asyncio

from aiohttp import ClientSession

from pytile import async_login


async def main() -> None:
    """Run!"""
    async with ClientSession() as session:
        api = await async_login("<EMAIL>", "<PASSWORD>", session)

        tiles = await api.async_get_tiles()

        for tile_uuid, tile in tiles.items():
            await tile.async_update()


asyncio.run(main())

Getting Premium Tile's History

Tile Premium Required: Yes

You can retrieve a Tile's history by calling its async_history coroutine:

import asyncio
from datetime import datetime

from aiohttp import ClientSession

from pytile import async_login


async def main() -> None:
    """Run!"""
    async with ClientSession() as session:
        api = await async_login("<EMAIL>", "<PASSWORD>", session)

        tiles = await api.async_get_tiles()

        for tile_uuid, tile in tiles.items():
            # Define a start and end datetime to get history for:
            start = datetime(2023, 1, 1, 0, 0, 0)
            end = datetime(2023, 1, 31, 0, 0, 0)
            history = await tile.async_history(start, end)
            # >>> { "version": 1, "revision": 1, ... }


asyncio.run(main())

Contributing

Thanks to all of our contributors so far!

  1. Check for open features/bugs or initiate a discussion on one.
  2. Fork the repository.
  3. (optional, but highly recommended) Create a virtual environment: python3 -m venv .venv
  4. (optional, but highly recommended) Enter the virtual environment: source ./.venv/bin/activate
  5. Install the dev environment: script/setup
  6. Code your new feature or bug fix on a new branch.
  7. Write tests that cover your new functionality.
  8. Run tests and ensure 100% code coverage: poetry run pytest --cov pytile tests
  9. Update README.md with any new documentation.
  10. Submit a pull request!

pytile's People

Contributors

bachya avatar cdce8p avatar dependabot-preview[bot] avatar dependabot[bot] avatar juzim avatar mend-bolt-for-github[bot] avatar renovate[bot] avatar tjni avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pytile's Issues

strange/inconsistent version numbering since 2022.1.0

Hello Aaron,

Is your feature request related to a problem? Please describe.

Since 2022.1.0 you (and some other guys) are using a bad new style for version numbers padded with zeros, e.g at Github, you are using the 2nd digit padded with a zero, perhaps this should look better in sorted lists, as you want to treat this as a month in a version number looking like a date.

This is causing some trouble, because a lot of package managers (like portage at Gentoo, or Pypi) are treating the version number segments as integers, this is a hard rule in semver-2.0.

We are using a set of automated build scripts, which now is in trouble. Ok, currently, I patched it, it now rewrites the wrong formatted version number, but I would like to adress the problem at it's source (->you) :-)

According to semver-2.0:

"A normal version number MUST take the form X.Y.Z where X, Y, and Z are non-negative integers, and MUST NOT contain leading zeroes. X is the major version, Y is the minor version, and Z is the patch version. Each element MUST increase numerically. For instance: 1.9.0 -> 1.10.0 -> 1.11.0."

Describe the solution you'd like
Please avoid using leading zeroes in version numbers.

Additional context
Add any other context or screenshots about the feature request here.

Update home-assistant Tile intergration to 5.0.1

Hi there, I saw that the intergration plugin for home-assistant is still using 4.0.0 pypi lib. What i really want to see if it is possible is the lost_timestamp field. So that i now when the tile had has a location update.

Full location history

Is your feature request related to a problem? Please describe.
pytile currently fetches the last-known location of a tile, but Premium services provide up to 30 days of location history. While the app unfortunately does not seem to have an export function this could be a nice addition to your library.

Describe the solution you'd like
Function to retrieve all location history of a tile, not just the last known, along with corresponding timestamps.

Additional context
tile_loc_history

find my phone, or tracker from api?

Have you looked into a way to find the phone, or tile tracker via the API?

I'd like to find my phone, similar to what you can do from their website.

Update tile location, use my RasPi to participate in the network

Hi,

Not sure if simillar request has already been discussed but I have few RasPi around my garden for Ruvvi tags and as they have Bluetooth I've been looking for a way to enable tile tracking as well. The idea is to send tile location back to the network simillar to how other phones can participate in finding my tile or for RasPi to act almost like a 2nd phone.

I wonder if anyone already tried this? It's especially useful when I'm using tile to track my Cat, and it would extend the range for tracking to cover a whole garden.

I'm happy to contribute, write code if someone points me in the right direction.

Thanks

Dependabot can't resolve your Python dependency files

Dependabot can't resolve your Python dependency files.

As a result, Dependabot couldn't update your dependencies.

The error Dependabot encountered was:

Creating virtualenv pytile-De7rrOoD-py3.8 in /home/dependabot/.cache/pypoetry/virtualenvs
Updating dependencies
Resolving dependencies...

[PackageNotFound]
Package pre-commit (2.1.1) not found.

If you think the above is an error on Dependabot's side please don't hesitate to get in touch - we'll do whatever we can to fix it.

View the update logs.

Get location history

In addition to retrieving the current location, it would be very useful to get prior locations as well. This could be a function that takes a date range and returns all latitude and longitude pairs that are within this span.

Add ability to ring a Tile from this library

Is your feature request related to a problem? Please describe.
I'd like to be able to ring my tile without using the app.

Describe the solution you'd like
A clear and concise description of what you want to happen.

Something like a ringMe method on the tile object.

Additional context
Add any other context or screenshots about the feature request here.

'This is filtered down from partner, who said can you please put an icon on our homeassistant UI to ring the remote? I hate the tile app' 🙂

412 'Precondition Failed'

Describe the bug
Tile integration within Home Assistant has not worked for me on two different HASS instances and the HA logs I did not find to be very helpful, so I downloaded pytile and attempted to run examples/test_api.py to test logging in with my username and password.

Upon running examples/test_api.py I get the following error:
INFO:__main__:Error requesting data from tiles/X##############X: 412, message='Precondition Failed', url=URL('https://production.tile-api.com/api/v1/tiles/X##############X')

Note: X##############X is (possibly?) a unique identifier which I redacted just in case, it is 26 characters and begins and ends with a letter with all numbers in between.

To Reproduce
Followed the steps in this previously reported Tile issue in the home-assistant repo:
https://github.com/home-assistant/core/issues#issuecomment-996165557

Expected behavior
Successful login to Tile account

Additional context
I am not certain exactly when this stopped working, but it has been at least a few weeks now.

Not sure if it is relevant, but the only thing that has changed on my Tile account in recent weeks as been adding a few new Tiles as well as some Tile Lost and Found Labels that they recently sent me for free. The Lost and Found Labels are a totally passive Tile product that allows someone who finds an item to contact the owner by scanning the QR code on the sticker. The shop up in the Tile app as another tracker but they lack many of the options of an active Tile tracker device. Perhaps these new Tile Lost and Found Labels are causing issues?

https://www.tile.com/product/lost-and-found-labels

"TypeError: 'NoneType' object is not subscriptable" for Android devices

Hi @bachya,
Thanks so much for this helpful app. I'm trying to get set up to use it in a research study, but am having trouble getting off the ground.

When trying to run your example code, i get the following response:

{"version":1,"revision":1,"timestamp":"2020-06-30T13:16:15.732Z","timestamp_ms":1593522975732,"result_code":0,"result":{"message":"invalid app version, version=null, app_id=null"}}

Seems like DEFAULT_APP_VERSION is hard-coded in client.py? Admittedly an api novice, so any help is greatly appreciated

Dependabot can't resolve your Python dependency files

Dependabot can't resolve your Python dependency files.

As a result, Dependabot couldn't update your dependencies.

The error Dependabot encountered was:

Creating virtualenv pytile-ZKAY8nut-py3.9 in /home/dependabot/.cache/pypoetry/virtualenvs
Updating dependencies
Resolving dependencies...

  PackageNotFound

  Package importlib-metadata (3.1.0) not found.

  at /usr/local/.pyenv/versions/3.9.0/lib/python3.9/site-packages/poetry/repositories/pool.py:144 in package
      140│                     self._packages.append(package)
      141│ 
      142│                     return package
      143│ 
    → 144│         raise PackageNotFound("Package {} ({}) not found.".format(name, version))
      145│ 
      146│     def find_packages(
      147│         self, dependency,
      148│     ):

If you think the above is an error on Dependabot's side please don't hesitate to get in touch - we'll do whatever we can to fix it.

View the update logs.

When I try the example, i get the following error: Precondition Failed

Describe the bug
Today i bought 2 tile sticker. I was able the activate them in the app. Then i try to get the information with this python module. But I get an error message: Precondition Failed.

To Reproduce
Steps to reproduce the behavior:
I go to the pypi page of pytile. And use the example (Create a client, initialize it, and get to work)
Then i fill in the correct login credentials. When i run python3 test.py I get that message.

Expected behavior
I should work.

Screenshots

[pytile]$ python3 test.py 
Traceback (most recent call last):
  File "test.py", line 18, in <module>
    asyncio.get_event_loop().run_until_complete(main())
  File "/usr/local/Cellar/python/3.7.4_1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncio/base_events.py", line 579, in run_until_complete
    return future.result()
  File "test.py", line 15, in main
    await client.tiles.all()
  File "/usr/local/lib/python3.7/site-packages/pytile/tile.py", line 31, in all
    "get", "tiles", params=[("tile_uuids", uuid) for uuid in tile_uuid_list]
  File "/usr/local/lib/python3.7/site-packages/pytile/client.py", line 105, in request
    ) from None
pytile.errors.RequestError: Error requesting data from tiles: 412, message='Precondition Failed', url=URL('https://production.tile-api.com/api/v1/tiles?tile_uuids=********&tile_uuids=p!*******&tile_uuids=p!******')

SSL Certificate Error

Describe the bug
Getting the following error when trying to authenticate:

aiohttp.client_exceptions.ClientConnectorCertificateError: Cannot connect to host production.tile-api.com:443 ssl:True [SSLCertVerificationError: (1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:1123)')]

To Reproduce

async def main() -> None:
    """Run!"""
    async with ClientSession() as session:
        api = await async_login("myEmail", "myPwd", session)
asyncio.run(main())

Expected behavior
Successful connection.

Screenshots
If applicable, add screenshots to help explain your problem.

Additional context
Running Python 3.9 on Mac from virtual environment.

thx for helping a noob

Privacy mode

Is your feature request related to a problem? Please describe.
No

Describe the solution you'd like
Have you considered adding a Privacy Mode, where the user doesn't login, and the app talks
directly to the Tile?

Ring

Hi, I would like to be able to make my smartphone, tile pro, tile mate, etc. ring. Thank you and have a nice day.

Session is closed

import asyncio

from aiohttp import ClientSession

from pytile import Client

async def main() -> None:
        """Create the aiohttp session and run the example."""
        async with ClientSession() as websession:
                client = Client(account, password, websession)
        await client.async_init()

        # Get all Tiles associated with an account:
        await client.tiles.all()


asyncio.get_event_loop().run_until_complete(main())

I follow the Usage and got the following error

Traceback (most recent call last):
  File "index.py", line 19, in <module>
    asyncio.get_event_loop().run_until_complete(main())
  File "/usr/lib/python3.7/asyncio/base_events.py", line 584, in run_until_complete
    return future.result()
  File "index.py", line 13, in main
    await client.async_init()
  File "/home/pi/.local/lib/python3.7/site-packages/pytile/client.py", line 50, in async_init
    'locale': self._locale
  File "/home/pi/.local/lib/python3.7/site-packages/pytile/client.py", line 92, in request
    params=params, data=data) as resp:
  File "/home/pi/.local/lib/python3.7/site-packages/aiohttp/client.py", line 1005, in __aenter__
    self._resp = await self._coro
  File "/home/pi/.local/lib/python3.7/site-packages/aiohttp/client.py", line 348, in _request
    raise RuntimeError('Session is closed')
RuntimeError: Session is closed

API Documentation

Do you have documentation as to the functioning of this API? I'm trying to get it to work from looking at the code, but I keep getting 500 errors.

Add battery level to tile object?

Hey there! Looking at #50, I noticed that battery level may be part of the state of a tile.

Would it be possible to have that exposed in the tile abstraction?

The reason is that I plan to notify me if a tile is starting to die: it's the single most annoying thing of tiles 😁

Filter by tile_type?

Is there currently a way to only bring back reports from the TILE itself? Right now I only see a way to bring back all data, including phone records. Obviously one can filter after the request is delivered, but would save on bandwidth if that was done at run time.

Raise different error on invalid auth

Is your feature request related to a problem? Please describe.

It's currently not easily possible to differentiate between invalid auth and no internet. We need to inspect the status in the response.

pytile/pytile/api.py

Lines 80 to 84 in 08edc29

resp = await self.async_request(
"post",
f"clients/{self.client_uuid}/sessions",
data={"email": self._email, "password": self._password},
)

Describe the solution you'd like
A new exception InvalidAuth so it's clear that the passed in authentication is invalid.

Error messagee in console

Hello,

When I run the example script I do seen to get the updated tile locations, but the following is dumped to the console screen for each tile queried...

"Missing last_tile_state; can't report location info"

Is this normal or is something not working correctly on my end?

Thank you for all the handwork on this fantastic library!

Best,
Michael

is it possible to read button pressed on tile?

Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

Describe the solution you'd like
i would like to read the information about button being pressed on the tile, like long press, number of clicks etc.

Additional context
Add any other context or screenshots about the feature request here.

Session has expired; make a new one!

**We keep getting session failed when we run the example.py file. Any assistance would be greatly appreciated.

Issue may be due to the use of TCPConnector definition but not sure.
Below is my example.py

[root@lab pytile]# cat example.py
"""Run an example script to quickly test."""
import asyncio
import ssl
import aiohttp

from aiohttp import ClientSession
from pytile import Client
from pytile.errors import TileError

async def main():
"""Run."""
sslcontext = ssl.create_default_context()
conn = aiohttp.TCPConnector(ssl=sslcontext)
async with ClientSession(connector=conn) as websession:
try:

""" Create a client: """"
client = Client("[email protected]", "removed#2", websession)

await client.async_init()
print("Showing active Tiles:")
print(await client.tiles.all())
print("Showing all Tiles:")
print(await client.tiles.all(show_inactive=True))
except TileError as err:
print(err)
asyncio.get_event_loop().run_until_complete(main())

To Reproduce
Steps to reproduce the behavior:

  1. Copy the example.py above and run with valid logins
  2. See error

Expected behavior
[root@lab pytile]# python example.py

Showing active Tiles:

Session has expired; make a new one!

[root@lab pytile]#

Additional context
My python version is 3.7.1
[jopoku@lab ~]$ python -V
Python 3.7.1
[jopoku@lab ~]$

SSL certificate error

Any suggestions to get around the following runtime error:

ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1000)

Does this software preclude the need to use the Tile app?

Does this software only work when someone is running the Tile bluetooth app in proximity to the Tile device? Or can it still get some information from the Tile device by itself (like detecting its presence) without an active connection to the Tile bluetooth app?

Trying to run the example I get

Hello,
Thanks for your library! I am running into trouble though. I have a brand new ubuntu install. I installed python 3.6 and your library as well as asyncio and aiohttp.

This is the error I'm getting:

python3 example.py

Traceback (most recent call last):
File "tile.py", line 27, in
asyncio.get_event_loop().run_until_complete(main())
File "/usr/lib/python3.6/asyncio/base_events.py", line 484, in run_until_complete
return future.result()
File "tile.py", line 16, in main
await client.async_init()
File "/usr/local/lib/python3.6/dist-packages/pytile/client.py", line 52, in async_init
"locale": self._locale,
File "/usr/local/lib/python3.6/dist-packages/pytile/client.py", line 97, in request
data=data,
File "/usr/local/lib/python3.6/dist-packages/aiohttp/client.py", line 1012, in aenter
self._resp = await self._coro
File "/usr/local/lib/python3.6/dist-packages/aiohttp/client.py", line 502, in _request
resp = await req.send(conn)
File "/usr/local/lib/python3.6/dist-packages/aiohttp/client_reqrep.py", line 629, in send
await writer.write_headers(status_line, self.headers)
File "/usr/local/lib/python3.6/dist-packages/aiohttp/http_writer.py", line 111, in write_headers
buf = _serialize_headers(status_line, headers)
File "aiohttp/_http_writer.pyx", line 138, in aiohttp._http_writer._serialize_headers
File "aiohttp/_http_writer.pyx", line 110, in aiohttp._http_writer.to_str
TypeError: Cannot serialize non-str key UUID('f006245f-b9df-45f7-8e63-')

I am pretty new to python so it may be something I am missing.

Thanks!

Unauthorized Request Error

I recently bought a tile mate, associated it with an account, and ran the sample script shown in the README file.

I get the following error:

pytile.errors.RequestError: Error requesting data from users/xxxx-xxxx-x-xxx-x-xxx/user_tiles: 401, message='Unauthorized', url=URL('https://production.tile-api.com/api/v1/users/xxxx-xxxx-x-xxx-x-xxx/user_tiles')

I checked the entered credentials to login on the app again, and I had no problem logging in.

Please let me know if i am missing something here or is this a known issue?

Thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.