Skip to content

About

A production-shaped FastAPI adapter for the legacy Urja Meter Ops portal, providing typed, stable JSON endpoints for meter search, details, and consumption readings.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

Repository files navigation

Flock Energy Meter API

A small production-shaped API adapter in front of the legacy Urja Meter Ops portal. It gives downstream clients typed, stable JSON without requiring them to understand the portal's form login, session cookie, abbreviated fields, HTML detail page, or string-encoded numeric values.

What is included

  • GET /api/v1/meters — paginated meter search (q matches meter ID or serial number).
  • GET /api/v1/meters/{meter_id} — normalized nameplate, network breadcrumb, and coordinates.
  • GET /api/v1/meters/{meter_id}/consumption — normalized half-hourly energy readings.
  • GET /health — liveness endpoint.
  • /docs — interactive Swagger UI; /openapi.json — generated OpenAPI 3 schema.

The protocol investigation is recorded in PROTOCOL.md. The reflection is in REFLECTION.md.

Run locally

Requires Python 3.10+.

py -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txt
Copy-Item .env.example .env
# edit .env and set PORTAL_PASSWORD
uvicorn app.main:app --reload

The service is then available at http://127.0.0.1:8000. Never commit .env; credentials are intentionally not hard-coded.

Example requests

curl "http://127.0.0.1:8000/api/v1/meters?q=SE33962&page=1"
curl "http://127.0.0.1:8000/api/v1/meters/J100000"
curl "http://127.0.0.1:8000/api/v1/meters/J100000/consumption"

Example list response shape:

{
  "data": [{
    "meter_id": "J100000",
    "serial_number": "SE33962",
    "make": "HPL",
    "phase_type": "single",
    "installation_status": "Decommissioned",
    "transformer_code": "DT-001"
  }],
  "meta": {"page": 1, "page_size": 20, "total": 403, "has_next": true}
}

Architecture

HTTP consumer
    -> FastAPI routes / Pydantic DTOs / request IDs
    -> UrjaPortalClient (anti-corruption adapter)
    -> httpx cookie-aware session + BeautifulSoup HTML parser
    -> Urja Meter Ops portal

The route layer owns HTTP semantics and validation. The client owns upstream authentication, session renewal, endpoint calls, and normalization. Pydantic models form the contract boundary. This keeps portal-specific behavior isolated so a future replacement of the portal does not leak into consumers.

Decisions and trade-offs

  • FastAPI + async httpx: provides typed validation and generated OpenAPI while allowing concurrent web-server work. The upstream calls are still deliberately simple and bounded.
  • One process-wide client: appropriate for this take-home service and reuses the connection pool and cookie. A multi-tenant deployment would use a credential-scoped client pool instead.
  • Pass-through freshness: data is fetched on request; no cache can silently serve stale operational data. A short TTL cache would be a sensible next step after measuring upstream load.
  • Stable envelope: all successful resources use data; list calls include meta. Upstream failures are translated to controlled errors and never expose portal HTML or credentials.
  • Conservative scope: hierarchy is parsed as part of meter detail, but a separate hierarchy index, frontend, persistence, rate limiting, and distributed session store are intentionally not included in this 4–6 hour solution.

Testing

pytest -q

Unit tests cover portal field normalization, HTML breadcrumb parsing, and required configuration. The adapter boundary is designed for HTTP mocking with respx; integration testing against the supplied portal should be run manually with real environment credentials and must not be part of CI.

Production hardening / future work

  • Add service authentication (for example OAuth2 or mTLS), rate limiting, audit logging, and secrets-manager integration before exposing this API beyond a trusted network.
  • Add contract tests with recorded, sanitized fixtures and a scheduled upstream compatibility check.
  • Add retries with bounded exponential backoff only for safe/idempotent transient failures, plus metrics/traces for upstream latency and auth renewal.
  • Confirm the portal timezone and represent timestamps as timezone-aware values.
  • Add a local index or materialized snapshot for cross-meter filtering and hierarchy queries if request volume outgrows the portal.
  • Add a separate frontend only after product requirements clarify the operational workflow.

Submission files

  • PROTOCOL.md — observed portal behavior.
  • REFLECTION.md — engineering reflection.
  • openapi.json — exported contract for this service.

About

A production-shaped FastAPI adapter for the legacy Urja Meter Ops portal, providing typed, stable JSON endpoints for meter search, details, and consumption readings.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages