Skip to content

Commit bfafca4

Browse files
committed
Draft improvements
1 parent b711458 commit bfafca4

10 files changed

Lines changed: 417 additions & 52 deletions

File tree

CHANGELOG.md

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# Changelog
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## [Unreleased]
9+
10+
## [2.0.8] - 2025-02-01
11+
12+
### Added
13+
- `decrypt_data_blob_async()` method for non-blocking decryption in async contexts
14+
- Exported `Location`, `PhotoResult`, and `RateLimitError` from package root
15+
- `CHANGELOG.md` following Keep a Changelog format
16+
- Comprehensive exception documentation (Raises sections) for all public API methods
17+
18+
### Changed
19+
- Improved lock message sanitization to re-collapse whitespace after removing special characters
20+
- Simplified `get_history()` signature by removing unused `start`/`end` parameters
21+
- Improved docstrings for helpers.py functions
22+
23+
### Removed
24+
- Dead code: `_parse_location_blob()` function that was never called
25+
- Placeholder comment from helpers.py
26+
27+
### Fixed
28+
- Lock messages containing only special characters now correctly fall back to plain "lock" command
29+
30+
## [2.0.7] - 2025-01-15
31+
32+
### Changed
33+
- Cleanup release to trigger new PyPI deployment
34+
- No functional changes from 2.0.6
35+
36+
## [2.0.6] - 2025-01-10
37+
38+
### Added
39+
- 100% test coverage achieved
40+
41+
### Changed
42+
- Full type safety with strict mypy checks
43+
- Improved method signatures with precise return types
44+
45+
## [2.0.5] - 2025-01-08
46+
47+
### Added
48+
- Strict typing enforcement (Phase 1)
49+
- Comprehensive edge case tests for `Location` parsing
50+
- `docs/strict_typing_enforcement_plan.md` roadmap
51+
52+
### Changed
53+
- Updated community instance URL to https://server.fmd-foss.org/
54+
55+
## [2.0.4] - 2024-11-09
56+
57+
### Added
58+
- Password-free authentication via `export_auth_artifacts()` and `from_auth_artifacts()`
59+
- `drop_password=True` option to discard raw password after onboarding
60+
- `Device.get_picture_blobs()` and `Device.decode_picture()` methods
61+
- `Device.lock(message=...)` with sanitization (quotes, backticks, semicolons removed)
62+
- Wipe PIN validation (alphanumeric ASCII only, no spaces)
63+
- PNG detection via magic bytes in `export_data_zip()`
64+
65+
### Changed
66+
- 401 handling now supports hash-based token refresh
67+
- Private key loading supports both PEM and DER formats
68+
- Test coverage increased to ~98%
69+
70+
### Deprecated
71+
- `Device.take_front_photo()` - use `take_front_picture()`
72+
- `Device.take_rear_photo()` - use `take_rear_picture()`
73+
- `Device.fetch_pictures()` - use `get_picture_blobs()`
74+
- `Device.download_photo()` - use `decode_picture()`
75+
76+
## [2.0.0] - 2024-10-01
77+
78+
### Added
79+
- Async client with `FmdClient.create()` factory method
80+
- Async context manager support (`async with`)
81+
- HTTPS enforcement (plain HTTP rejected)
82+
- Configurable SSL validation (`ssl=False` for dev, custom `SSLContext` for production)
83+
- Request timeouts on all HTTP calls
84+
- Retry logic with exponential backoff and jitter for 5xx errors
85+
- 429 rate-limit handling with Retry-After support
86+
- Client-side ZIP export (locations + pictures)
87+
- `Device` helper class for convenience actions
88+
- `py.typed` marker for PEP 561 compliance
89+
- GitHub Actions CI (lint, type-check, tests, coverage)
90+
- Codecov integration with badges
91+
92+
### Changed
93+
- Complete rewrite from sync to async API
94+
- Python 3.8+ required (3.7 dropped)
95+
96+
### Removed
97+
- Legacy synchronous `FmdApi` class
98+
99+
### Security
100+
- Sanitized logging (no sensitive payloads exposed)
101+
- Token masking in debug output
102+
103+
## [1.x] - Legacy
104+
105+
Previous synchronous implementation. See git history for details.
106+
107+
[Unreleased]: https://github.com/devinslick/fmd_api/compare/v2.0.8...HEAD
108+
[2.0.8]: https://github.com/devinslick/fmd_api/compare/v2.0.7...v2.0.8
109+
[2.0.7]: https://github.com/devinslick/fmd_api/compare/v2.0.6...v2.0.7
110+
[2.0.6]: https://github.com/devinslick/fmd_api/compare/v2.0.5...v2.0.6
111+
[2.0.5]: https://github.com/devinslick/fmd_api/compare/v2.0.4...v2.0.5
112+
[2.0.4]: https://github.com/devinslick/fmd_api/compare/v2.0.0...v2.0.4
113+
[2.0.0]: https://github.com/devinslick/fmd_api/releases/tag/v2.0.0

docs/HOME_ASSISTANT_REVIEW.md

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,10 @@ async def decrypt_data_blob_async(self, data_b64: str) -> bytes:
318318

319319
**HA Rationale:** Event loop blocking causes UI freezes and integration performance issues.
320320

321-
**Status:** ❌ TODO
321+
**Status:** ✅ FIXED
322+
- Added `decrypt_data_blob_async()` method that uses `run_in_executor()`
323+
- Added test coverage for the async method
324+
- Documented the sync vs async usage in docstrings
322325

323326
---
324327

@@ -350,7 +353,9 @@ async def decrypt_data_blob_async(self, data_b64: str) -> bytes:
350353

351354
**HA Rationale:** Good practice for library maintenance and user communication.
352355

353-
**Status:** ❌ TODO
356+
**Status:** ✅ FIXED
357+
- Added `CHANGELOG.md` following Keep a Changelog format
358+
- Documents all releases from 2.0.0 to current
354359

355360
---
356361

@@ -375,7 +380,9 @@ async def get_locations(...) -> List[str]:
375380

376381
**HA Rationale:** Users need to know how to handle errors properly.
377382

378-
**Status:** ❌ TODO
383+
**Status:** ✅ FIXED
384+
- Added Raises sections to all public API methods in client.py
385+
- Documented ValueError, FmdApiException, aiohttp.ClientError, asyncio.TimeoutError
379386

380387
---
381388

@@ -391,7 +398,10 @@ async def get_locations(...) -> List[str]:
391398

392399
**HA Rationale:** Demonstrates code quality and test thoroughness.
393400

394-
**Status:** ❌ TODO
401+
**Status:** ✅ FIXED
402+
- Coverage reporting implemented with pytest-cov
403+
- 100% branch coverage achieved
404+
- Codecov badge added to README
395405

396406
---
397407

@@ -413,7 +423,8 @@ __all__ = [
413423

414424
**HA Rationale:** Makes API more discoverable and IDE-friendly.
415425

416-
**Status:** ❌ TODO
426+
**Status:** ✅ FIXED
427+
- Added `Location`, `PhotoResult`, and `RateLimitError` to `__all__` exports
417428

418429
---
419430

@@ -502,14 +513,14 @@ def __init__(self, ..., ssl_context: Optional[ssl.SSLContext] = None):
502513
- Improve type hints
503514
- Add retry logic — DONE
504515
- Configure connection pooling — DONE
505-
- Make decryption async
516+
- Make decryption async — DONE
506517

507518
**For Best Practices (Minor):**
508519
- Add CI badges — PARTIAL (Added Tests + Codecov badges; PyPI/version badges pending)
509-
- Create CHANGELOG.md
510-
- Document exceptions
511-
- Add test coverage reporting
512-
- Export all public models
520+
- Create CHANGELOG.md — DONE
521+
- Document exceptions — DONE
522+
- Add test coverage reporting — DONE (100% branch coverage)
523+
- Export all public models — DONE
513524

514525
---
515526

@@ -566,16 +577,16 @@ def __init__(self, ..., ssl_context: Optional[ssl.SSLContext] = None):
566577

567578
Before submitting to Home Assistant:
568579

569-
- [ ] All critical issues resolved
570-
- [ ] Major security concerns addressed
571-
- [ ] Type hints complete and accurate
572-
- [ ] Documentation comprehensive
573-
- [ ] Test coverage > 80%
574-
- [ ] CHANGELOG.md up to date
575-
- [ ] Stable version released to PyPI
576-
- [ ] Code passes `flake8` and `mypy`
577-
- [ ] CI runs tests on all supported Python versions
578-
- [ ] CI enforces linting and type checking
580+
- [x] All critical issues resolved
581+
- [x] Major security concerns addressed
582+
- [x] Type hints complete and accurate
583+
- [x] Documentation comprehensive
584+
- [x] Test coverage > 80% (Currently at 100%)
585+
- [x] CHANGELOG.md up to date
586+
- [x] Stable version released to PyPI
587+
- [x] Code passes `flake8` and `mypy`
588+
- [x] CI runs tests on all supported Python versions
589+
- [x] CI enforces linting and type checking
579590

580591
---
581592

fmd_api/__init__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
# fmd_api package exports
22
from .client import FmdClient
33
from .device import Device
4-
from .exceptions import FmdApiException, AuthenticationError, DeviceNotFoundError, OperationError
4+
from .models import Location, PhotoResult
5+
from .exceptions import FmdApiException, AuthenticationError, DeviceNotFoundError, OperationError, RateLimitError
56
from ._version import __version__
67

78
__all__ = [
89
"FmdClient",
910
"Device",
11+
"Location",
12+
"PhotoResult",
1013
"FmdApiException",
1114
"AuthenticationError",
1215
"DeviceNotFoundError",
1316
"OperationError",
17+
"RateLimitError",
1418
"__version__",
1519
]

fmd_api/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "2.0.7"
1+
__version__ = "2.0.8"

0 commit comments

Comments
 (0)