Skip to content

Commit f1ffdb6

Browse files
committed
Merge branch 'dev' of https://github.com/devinslick/fmd_api into dev
2 parents 15c3cd4 + 014800f commit f1ffdb6

File tree

17 files changed

+1382
-855
lines changed

17 files changed

+1382
-855
lines changed

.coverage

0 Bytes
Binary file not shown.

.github/workflows/publish-testpypi.yml

Lines changed: 0 additions & 48 deletions
This file was deleted.

README.md

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
[![Tests](https://github.com/devinslick/fmd_api/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/devinslick/fmd_api/actions/workflows/test.yml)
44
[![codecov](https://codecov.io/gh/devinslick/fmd_api/branch/main/graph/badge.svg?token=8WA2TKXIOW)](https://codecov.io/gh/devinslick/fmd_api)
5+
[![PyPI - Downloads](https://img.shields.io/pypi/dm/fmd-api)](https://pypi.org/project/fmd-api/)
56

67
Modern, async Python client for the open‑source FMD (Find My Device) server. It handles authentication, key management, encrypted data decryption, location/picture retrieval, and common device commands with safe, validated helpers.
78

@@ -12,11 +13,7 @@ Modern, async Python client for the open‑source FMD (Find My Device) server. I
1213
```bash
1314
pip install fmd_api
1415
```
15-
- Pre‑release (Test PyPI):
16-
```bash
17-
pip install --pre --index-url https://test.pypi.org/simple/ \
18-
--extra-index-url https://pypi.org/simple/ fmd_api
19-
```
16+
<!-- Pre-release via TestPyPI removed. Use stable releases from PyPI or GitHub Releases for pre-release artifacts -->
2017

2118
## Quickstart
2219

@@ -32,7 +29,9 @@ async def main():
3229

3330
# Fetch most recent locations and decrypt the latest
3431
blobs = await client.get_locations(num_to_get=1)
35-
loc = json.loads(client.decrypt_data_blob(blobs[0]))
32+
# decrypt_data_blob() returns raw bytes — decode then parse JSON for clarity
33+
decrypted = client.decrypt_data_blob(blobs[0])
34+
loc = json.loads(decrypted.decode("utf-8"))
3635
print(loc["lat"], loc["lon"], loc.get("accuracy"))
3736

3837
# Take a picture (validated helper)
@@ -102,7 +101,7 @@ Tips:
102101
## What’s in the box
103102

104103
- `FmdClient` (primary API)
105-
- Auth and key retrieval (salt → Argon2id → access token → private key decrypt)
104+
- Auth and key retrieval (salt → Argon2id → access token → private key retrieval and decryption)
106105
- Decrypt blobs (RSA‑OAEP wrapped AES‑GCM)
107106
- Fetch data: `get_locations`, `get_pictures`
108107
- Export: `export_data_zip(out_path)` — client-side packaging of all locations/pictures into ZIP (mimics web UI, no server endpoint)
@@ -121,6 +120,13 @@ Tips:
121120
- `await device.refresh()` → hydrate cached state
122121
- `await device.get_location()` → parsed last location
123122
- `await device.get_picture_blobs(n)` + `await device.decode_picture(blob)`
123+
- `await device.get_picture_metadata(n)` -> returns only metadata dicts (if the server exposes them)
124+
125+
IMPORTANT (breaking change in v2.0.5): legacy compatibility wrappers were removed.
126+
The following legacy methods were removed from the `Device` API: `fetch_pictures`,
127+
`get_pictures`, `download_photo`, `get_picture`, `take_front_photo`, and `take_rear_photo`.
128+
Update your code to use `get_picture_blobs()`, `decode_picture()`, `take_front_picture()`
129+
and `take_rear_picture()` instead.
124130
- Commands: `await device.play_sound()`, `await device.take_front_picture()`,
125131
`await device.take_rear_picture()`, `await device.lock(message=None)`,
126132
`await device.wipe(pin="YourSecurePIN", confirm=True)`
@@ -143,6 +149,35 @@ async def main():
143149
asyncio.run(main())
144150
```
145151

152+
### Example: Inspect pictures metadata (when available)
153+
154+
Use `get_picture_blobs()` to fetch the raw server responses (strings or dicts). If you want a
155+
strongly-typed list of picture metadata objects (where the server provides metadata as JSON
156+
objects), use `get_picture_metadata()`, which filters for dict entries and returns only those.
157+
158+
```python
159+
from fmd_api import FmdClient, Device
160+
161+
async def inspect_metadata():
162+
client = await FmdClient.create("https://fmd.example.com", "alice", "secret")
163+
device = Device(client, "alice")
164+
165+
# Raw values may be strings (base64 blobs) or dicts (metadata). Keep raw when you need
166+
# to decode or handle both forms yourself.
167+
raw = await device.get_picture_blobs(10)
168+
169+
# If you want only metadata entries returned by the server, use get_picture_metadata().
170+
# This returns a list of dict-like metadata objects (e.g. id/date/filename) and filters
171+
# out any raw string blobs.
172+
metadata = await device.get_picture_metadata(10)
173+
for m in metadata:
174+
print(m.get("id"), m.get("date"))
175+
176+
await client.close()
177+
178+
asyncio.run(inspect_metadata())
179+
```
180+
146181
## Testing
147182

148183
### Functional tests

0 commit comments

Comments
 (0)