Releases: jasonjhofmann/aranet-cloud
Releases · jasonjhofmann/aranet-cloud
v0.2.1
Error-contract hardening from the remaining v0.1.0 audit findings. No API changes.
Fixed
get_bytes(binary attachment downloads) no longer leaks a rawTimeoutError— timeouts are now retried and, once retries are exhausted, wrapped inAranetConnectionError, matching the JSON path and the documented "all errors derive fromAranetError" contract.- The polite-spacing floor (
_respect_min_interval) now runs before every attempt of a binary download, not just once before the retry loop, so retries can no longer hammer the API back-to-back. - A
200response whose body is valid JSON but not an object (e.g. a top-level array or string) now raisesAranetServerErrorinstead of surfacing later as anAttributeErroroutside the exception hierarchy. AranetRateLimitError.retry_afteris now populated from the final 429 response'sRetry-Afterheader (the value already honoured for backoff) instead of attempting tofloat()the response body, which effectively always yieldedNone.
Full Changelog: v0.2.0...v0.2.1
v0.2.0 — audit hardening
Hardening release from a code audit. One breaking change: numeric measurement values are now float | None.
Changed
- Breaking:
Reading.value,Alarm.value, andAlarm.worstare nowfloat | None. Anull(or unparseable) value from the API surfaces asNoneinstead of being silently coerced to0.0— missing data can no longer masquerade as a genuine zero reading (e.g. 0 ppm CO₂). - Sample payloads in
docs/and the test fixtures are now fully synthetic: all real identifiers replaced with fabricated equivalents (originals remain in git history prior to this release).
Fixed
- The configured request
timeout(default 30 s) is now applied to every request, including when anaiohttp.ClientSessionis injected by the caller. Previously it only took effect on transport-owned sessions, so Home Assistant-style deployments silently ran with aiohttp's 300 s default.
Security
- Server-supplied pagination
nextlinks are only followed when their origin (scheme + host + port) matches the configuredbase_url. A foreign host or https→http downgrade raisesAranetErrorinstead of being requested with theApiKeyheader attached.
Note: this release is not yet on PyPI — the repo has no automated publish workflow and no publish credentials were available at release time. PyPI still has 0.1.0.
v0.1.0 — Initial release
Async client for every endpoint in the Aranet Cloud OpenAPI 3.0 spec (27 GETs, read-only), typed dataclass models, hidden pagination, full exception hierarchy.
Available on PyPI: pip install aranet-cloud==0.1.0
Added
AranetCloudClient— async client with one method per documented endpoint:- Sensors:
get_sensors,get_sensor,get_sensor_types,get_sensor_type - Measurements:
get_measurements_last,iter_measurements_history - Telemetry:
get_telemetry_last,iter_telemetry_history - Bases:
get_bases,get_base - Alarms:
get_alarms_actual,get_alarms_history,get_alarm_rules,get_alarm_rule - Assets:
get_assets,get_asset - Tags:
get_tags,get_tag - Catalog:
get_metrics,get_metric,get_unit - Attachments:
download_sensor_attachment,download_asset_attachment
- Sensors:
- 21 dataclasses covering the response schemas, each with a
from_dictthat silently ignores unknown fields (forward-compatible). - Exception hierarchy:
AranetError(base),AranetAuthError(401),AranetValidationError(400 withcorrelation_id),AranetRateLimitError(429 withretry_after),AranetServerError(5xx after retries),AranetConnectionError,AranetNotFoundError. - Async-iterator pagination —
iter_measurements_historyanditer_telemetry_historyfollow thenextURL transparently. - Exponential-backoff retry on 5xx / 429 / transient network errors, capped at 30 s; honours server-supplied
Retry-Afteron 429. - Polite-spacing floor (250 ms) between successive requests.
- Optional session injection — pass an existing
aiohttp.ClientSession; lib auto-creates and owns its session otherwise. py.typedmarker for PEP-561 type checkers.- 23 unit + integration tests against
aioresponses.
Notes
- Live-verified end-to-end against the production Aranet Cloud API on 2026-05-19.
- Build tooling:
ruff(lint),mypy --strict(types),pytest+pytest-asyncio(tests),hatchling(wheel/sdist).