Releases: devinslick/fmd_api
v2.0.7
Full Changelog: 2.0.6...2.0.7
v2.0.6
Release v2.0.6
Overview
This release focuses on code quality, stability, and developer experience. We have implemented Phase 1 of our Strict Typing Enforcement Plan, ensuring the core library is fully type-safe. Additionally, we have achieved 100% test coverage, ensuring robust handling of edge cases and deprecated methods.
Key Changes
🛡️ Strict Typing (Phase 1)
- Full Type Safety: The
fmd_apicore library (client.py,device.py,models.py) now passes strictmypychecks. - Improved Signatures: Public methods now have precise return types and generic type hints (e.g.,
List[Dict[str, Any]]), improving IDE autocompletion and static analysis for consumers. - Configuration: Updated
pyproject.tomlto enforce strict typing rules (disallowing untyped definitions and implicit optionals).
🧪 Test Coverage Improvements
- Full Coverage: Increased overall test coverage to 100%.
- Edge Case Handling: Added comprehensive tests for
Locationparsing, including scenarios with missing dates or invalid inputs. - Deprecation Verification: Added specific tests to ensure deprecated methods in
Device(liketake_front_photo,fetch_pictures) continue to function correctly while emitting appropriate warnings. - Command Sanitization: Verified that
Device.lock()correctly sanitizes and truncates messages.
📚 Documentation
- Roadmap: Added
docs/strict_typing_enforcement_plan.mdoutlining the roadmap for maintaining type safety.
Upgrade Guide
This release is fully backward compatible with v2.0.5. No code changes are required for consumers, though you may notice improved type checking results if you use mypy in your own projects.
v2.0.5
Release v2.0.5
Overview
This release focuses on code quality, stability, and developer experience. We have implemented Phase 1 of our Strict Typing Enforcement Plan, ensuring the core library is fully type-safe. Additionally, we have significantly improved test coverage and updated documentation.
Key Changes
🛡️ Strict Typing (Phase 1)
- Full Type Safety: The
fmd_apicore library (client.py,device.py,models.py) now passes strictmypychecks. - Improved Signatures: Public methods now have precise return types and generic type hints (e.g.,
List[Dict[str, Any]]), improving IDE autocompletion and static analysis for consumers. - Configuration: Updated
pyproject.tomlto enforce strict typing rules (disallowing untyped definitions and implicit optionals).
🧪 Test Coverage Improvements
- Coverage Boost: Increased overall test coverage to 97%.
- Edge Case Handling: Added comprehensive tests for
Locationparsing, including scenarios with missing dates or invalid inputs. - Deprecation Verification: Added specific tests to ensure deprecated methods in
Device(liketake_front_photo,fetch_pictures) continue to function correctly while emitting appropriate warnings. - Command Sanitization: Verified that
Device.lock()correctly sanitizes and truncates messages.
📚 Documentation
- Roadmap: Added
docs/strict_typing_enforcement_plan.mdoutlining the roadmap for maintaining type safety. - Community Updates: Updated the community instance URL in
README.mdto point to the new server location (https://server.fmd-foss.org/).
Upgrade Guide
This release is fully backward compatible with v2.0.4. No code changes are required for consumers, though you may notice improved type checking results if you use mypy in your own projects.
v2.0.4
Summary
v2.0.4 is a hardening + ergonomics release focused on secure password-free resume flows, clarified and modernized picture APIs, safer destructive actions, and significantly expanded test coverage (now ~98%). It remains fully backward compatible for consumers relying on deprecated method names; all new functionality is additive.
Highlights
1. Authentication Artifacts (Password-Free Resume)
- New methods:
FmdClient.from_auth_artifacts(artifacts: dict)– Restore a client without the raw password.FmdClient.resume(...)– Lower-level variant accepting explicit fields.await client.export_auth_artifacts()– Exportbase_url,fmd_id,access_token,private_key(PEM), optionalpassword_hash,session_duration,token_issued_at.await client.drop_password()/drop_password=Trueincreate()– Immediately discard raw password after onboarding.
- 401 handling logic hierarchy:
- If raw password present → reauthenticate (existing flow)
- Else if
password_hashpresent → hash-based token refresh (_reauth_with_hash()) - Else → raise
FmdApiException(caller must re-onboard)
- Private key load now supports both PEM and DER (fallback path tested).
2. Picture API Renaming & Deprecations
- New canonical methods on
Device:get_picture_blobs()– fetch encrypted Base64 blobs.decode_picture()– decrypt + decode intoPhotoResult.
- Deprecated (still functional, emit
DeprecationWarning):take_front_photo(),take_rear_photo()→ usetake_front_picture(),take_rear_picture()fetch_pictures(),get_pictures()(Device) → useget_picture_blobs()download_photo(),get_picture()(Device) → usedecode_picture()
download_photo()now points directly todecode_picture()(avoids chained deprecated call).
3. Wipe (Factory Reset) Hardening
Device.wipe()now strictly requires:confirm=Truepinargument present- PIN must be alphanumeric ASCII (no spaces). Future enforcement of 16+ length is noted (fmd-android MR 379).
- Removed redundant space validation branch.
4. Lock Message Support
Device.lock(message=...)allows an optional user message; sanitized (quotes / backticks / semicolons removed, whitespace collapsed, 120 char cap). Falls back cleanly if server ignores payload.
5. Expanded Export Functionality & Robustness
export_data_zip()improvements:- Picture file extension detection:
.pngvia magic bytes, default.jpgelse. - Resilient manifest entries capturing per-item decryption errors (non-fatal).
- Additional validation of location/picture list types with graceful fallbacks.
- Picture file extension detection:
6. Coverage & Testing Improvements
- Overall coverage ~98% (client.py ~98%, device.py mid/high 90s, models 100%).
- New targeted tests exercise:
- DER private key resume path
- Missing artifact field errors
- 401 reauth when neither password nor hash is available (expected exception)
- Hash-based 401 reauth success path
- PNG export branch + unknown image default
.jpg - Deprecated wrapper warning emission
- Non-dict JSON fallback handling & non-list picture responses
- Error recording during export (location & picture failures)
- Retry logic: 429 (Retry-After numeric/date/negative), 500/502 sequences, connection errors, backoff jitter/no-jitter paths
- Masking helpers and retry-after parsing edge cases
7. Documentation Updates
- README: Added password-free artifact usage, wipe PIN notes, lock message mention, community listing.
MIGRATE_FROM_V1.md: Corrected camera method naming, clarified wipe requirements, updated picture usage.AUTH_ARTIFACTS_DESIGN.md: Formal specification of artifact-based resume workflow.
8. Internal / Quality Enhancements
- Removed chained deprecation in
Device.download_photo(). - Simplified
wipe()validation logic (single branch covers spaces & non-alphanumeric). - Eliminated redundant PIN space check.
- Minor consistency and defensive branches now covered or documented.
Deprecations (No Immediate Removal)
| Deprecated | Replacement |
|---|---|
Device.take_front_photo() |
Device.take_front_picture() |
Device.take_rear_photo() |
Device.take_rear_picture() |
Device.fetch_pictures() |
Device.get_picture_blobs() |
Device.get_pictures() (Device wrapper) |
Device.get_picture_blobs() |
Device.download_photo() |
Device.decode_picture() |
Device.get_picture() |
Device.decode_picture() |
Plan: Monitor usage; consider removal or formal EOL notice in a future minor/major once ecosystem migrates.
Security Considerations
- Encourages immediate password discarding (
drop_password=True), reducing exposure of raw credentials. password_hashstill sensitive—store using platform secret storage if possible.- Wipe PIN validation prevents accidental destructive actions with weak/empty inputs.
- Lock message sanitization avoids command injection edge cases in future server parsing contexts.
Migration Notes (2.0.3 → 2.0.4)
- Existing code continues to function; deprecation warnings guide picture API migration.
- To adopt password-free resume:
- Onboard normally with
create(..., drop_password=True). - Persist
await client.export_auth_artifacts()securely. - Resume with
await FmdClient.from_auth_artifacts(artifacts).
- Onboard normally with
Example: Password-Free Cycle
client = await FmdClient.create(url, fmd_id, password, drop_password=True)
artifacts = await client.export_auth_artifacts()
# Persist artifacts securely...
await client.close()
client2 = await FmdClient.from_auth_artifacts(artifacts)
locations = await client2.get_locations(1)Potential Follow-Ups (Not Included)
- Enforce future 16+ PIN length once upstream server mandates it.
- Add a CHANGELOG.md consolidating releases (this file can seed that entry).
- Provide optional encrypted artifact export (password-protected ZIP or keyring integration).
- Add coverage for final remaining defensive lines (currently low-risk).
Version
fmd_api.__version__ == "2.0.4"
Acknowledgements
Thanks to contributors and early testers providing feedback on artifact-based auth and API naming clarity.
Released: 2025-11-09
v2.0.3
🎯 Highlights
- Test coverage increased from 81% to 98% with comprehensive unit tests
- Pre-commit hooks for local code quality enforcement
- Improved CI/CD workflows to prevent publish conflicts
✨ Testing Improvements
- Added 45+ new unit tests covering edge cases and error handling paths in
client.pyanddevice.py - Comprehensive coverage of:
- Authentication flows and password hashing
- Connection error retry logic with backoff/jitter
- HTTP 429/5xx retry handling with Retry-After header parsing
- JSON parsing fallbacks and error handling
- Export data ZIP generation with picture format detection
- Device photo download and history decryption error paths
- Stream response handling
🔧 Developer Experience
- Pre-commit hooks configured with:
flake8for linting (catch CI errors locally!)blackfor code formattingmypyfor type checking- File cleanup (trailing whitespace, line endings, etc.)
- Setup:
pip install -e ".[dev]"thenpython -m pre_commit install
🚀 CI/CD Enhancements
- Simplified publish workflow: Only publishes to PyPI from main branch or GitHub releases
- Manual TestPyPI workflow: New workflow for controlled pre-release testing (trigger from Actions UI)
- Fixed version conflicts: Removed automatic TestPyPI publishing from PRs to avoid duplicate version errors
📊 Coverage Metrics
- Overall: 98% (512 statements, 10 missed)
- client.py: 97%
- device.py: 100%
- All tests pass: 104 unit tests
🐛 Bug Fixes
- Fixed packaging version alignment between
pyproject.tomland_version.py - Resolved flake8 linting issues (import ordering, whitespace)
📦 What's Changed
- Version bumped to 2.0.3
- Added pre-commit to dev dependencies
- Updated documentation and line endings normalization
v2.0.1
Summary
This major release delivers a production-ready async client with robust TLS handling, resilient request logic (timeouts, retries, rate limits), and a fully wired CI pipeline (lint, type-check, tests, coverage). It replaces the legacy synchronous v1 client and prepares the project for Home Assistant and broader integration.
Highlights
- Async client
- New
FmdClientwith an async factory (await FmdClient.create(...)) and async context manager (async with ...). - Clean session lifecycle management and connection pooling controls.
- New
- TLS/SSL
- HTTPS-only
base_urlenforcement (rejects plain HTTP). - Configurable validation:
ssl=False(dev only) or pass a customssl.SSLContext. - Certificate pinning example included in docs.
- HTTPS-only
- Reliability
- Timeouts applied across all HTTP requests.
- Retries with exponential backoff and optional jitter for 5xx and connection errors.
- 429 rate-limit handling with Retry-After support.
- Safe behavior for command POSTs (no unsafe retries).
- Features
- Client-side export to ZIP (locations + pictures).
- Device helper with convenience actions (e.g., request location, play sound, take picture).
- Safety and ergonomics
- Sanitized logging (no sensitive payloads); token masking helper.
- Typed package (
py.typed) and mypy-clean.
- CI/CD
- GitHub Actions: lint (flake8), type-check (mypy), unit tests matrix (Ubuntu/Windows; Py 3.8–3.12).
- Coverage with branch analysis and Codecov upload + badges.
- Publish workflows for TestPyPI (non-main) and PyPI (main or Release).
Breaking changes
- API surface moved to async:
- Before (v1, sync):
client = FmdApi(...); client.authenticate(...); client.get_all_locations() - Now (v2, async):
client = await FmdClient.create(base_url, fmd_id, password, ...)await client.get_locations(...),await client.get_pictures(...),await client.send_command(...)- Prefer:
async with FmdClient.create(...) as client: ...
- Before (v1, sync):
- Transport requirements:
base_urlmust be HTTPS; plain HTTP raisesValueError.
- Python versions:
- Targets Python 3.8+ (3.7 removed from classifiers).
Migration guide
- Replace
FmdApiusage with the asyncFmdClient:- Use
await FmdClient.create(...)andasync withfor safe resource management. - Update all calls to await the async methods.
- Use
- TLS and self-signed setups:
- For dev-only scenarios: pass
ssl=False. - For proper self-signed use: pass a custom
ssl.SSLContext. - For high-security setups: consider the certificate pinning example in README.
- For dev-only scenarios: pass
- Connection tuning:
- Optional:
conn_limit,conn_limit_per_host,keepalive_timeouton the TCPConnector via client init.
- Optional:
Error handling and semantics
- 401 triggers one automatic re-authenticate then retries the request.
- 429 honors Retry-After, otherwise uses exponential backoff with jitter.
- Transient 5xx/connection errors are retried (except unsafe command POST replays).
- Exceptions are normalized to
FmdApiExceptionwhere appropriate; messages mask sensitive data.
Documentation and examples
- README: TLS/self-signed guidance, warnings, and certificate pinning example.
- Debugging:
pin_cert_example.pydemonstrates secure pinning and avoids CLI secrets.
CI/CD and release automation
- Tests: unit suite expanded; functional tests run when credentials are available.
- Coverage: ~83% overall; XML + branch coverage uploaded to Codecov (badges included).
- Workflows:
test.yml: runs on push/PR for all branches (lint, mypy, unit tests matrix, coverage, optional functional tests).publish.yml: builds on push/releases; publishes to TestPyPI for non-main pushes, PyPI on main or release.
Checklist
- All unit tests pass
- Flake8 clean
- Mypy clean
- Coverage collected and uploaded
- README/docs updated (TLS, pinning, badges)
- Packaging: sdist and wheel built; publish workflows configured
Notes
- Use
ssl=Falsesparingly and never in production. - Consider adding Dependabot and security scanning in a follow-up.
- A
CHANGELOG.mdentry for 2.0.0 is recommended if not already included.
BREAKING CHANGE: v2 switches to an async client, enforces HTTPS, and drops Python 3.7; synchronous v1 usage must be migrated as noted above.
0.1.0
Initial published release