tliu93
d35ac7d752
M6-T07: add metering billing engine + period job + summary + recompute
...
- app/services/energy_cost.py: register_at (register values at a UTC boundary),
compute_period (register deltas x active-version strategy, snapshot price +
contract_version_id, immutable unless overwrite), compute_closed_periods
(bounded lookback), recompute_range (explicit overwrite), summarize
(sum net + standing fees month/30 - heffingskorting year/365).
- Missing tibber price -> skip; missing reading -> degraded (zeroed amounts,
null version), consistently on both create and recompute paths.
- main.py: 1-minute energy-cost job (existing jobs/MQTT untouched). Tests added.
2026-06-23 22:26:56 +02:00
tliu93
ef48032adb
M6-T06: extend MqttManager with subscribe + DSMR ingest
...
- mqtt.py: subscription registry, on_message dispatch (swallows handler
errors), re-subscribe on (re)connect; publish/connect/disconnect/reconnect
unchanged.
- app/services/dsmr_ingest.py: handle_message stores the full telegram frame
(no allowlist; gas/phases/null preserved), 10s downsample by timestamp.second,
source_id idempotency (select + IntegrityError rollback). Net-thread safe.
- main.py registers the DSMR subscription only when dsmr_ingest_enabled.
2026-06-23 21:52:57 +02:00
tliu93
7e266a21eb
M6-T05: add Tibber GraphQL client + price refresh service + schedule
...
- app/integrations/tibber/client.py: fetch_price_range/fetch_current_price
(priceInfoRange QUARTER_HOURLY, startsAt->UTC, no fixed node count assumption),
TibberError/TibberAuthError; token never logged or put in exception text.
- app/services/tibber_prices.py: refresh_prices upserts by starts_at (idempotent),
no-op unless an active kind=tibber contract + token exist.
- main.py: hourly tibber-refresh job (existing jobs/MQTT untouched). Tests added.
2026-06-23 21:35:29 +02:00
tliu93
4284bd40a7
M6-T04: add EnergyContract CRUD + versions + profile validation API
...
- app/services/contracts.py: create_contract, add_version (append-only,
auto-closes prior version), activate_contract (mutex), and
active_contract_version_at (half-open [from, to)) for the billing engine.
- app/schemas/energy_contract.py + routes/api/energy_contracts.py: 6 endpoints
(GET/POST contracts, GET/PATCH contracts/{id}, POST .../versions, GET profiles).
Values validated against pricing profiles (422 on mismatch); no DELETE.
- main.py registers router; OpenAPI re-exported; tests for CRUD/version/activate.
2026-06-23 21:19:25 +02:00
tliu93
35cdc7f22a
M5: use DB-merged runtime settings for MQTT/discovery; add MQTT test button; move Expose panel into config accordion
2026-06-22 20:11:54 +02:00
tliu93
45d87f36f7
M5-T12: add expose toggle API and Home Assistant Expose settings panel
2026-06-22 15:50:49 +02:00
tliu93
35b95f5c88
M5-T11: add HA discovery and state publishing wired to polling
2026-06-22 15:32:43 +02:00
tliu93
9d05f5ea62
M5-T10: add paho MQTT client with lifespan connect/reconnect and mqtt/test endpoint
2026-06-22 15:06:30 +02:00
tliu93
702a1cec00
M5-T05: add Modbus JSON API (device CRUD, readings, metrics, test)
2026-06-22 13:37:48 +02:00
tliu93
49d15d8ffe
M5-T04: add Modbus poll service and APScheduler polling job
2026-06-22 13:24:11 +02:00
tliu93
a9830c42d8
M2-T11: serve React SPA from FastAPI and remove Jinja pages
...
- app/main.py serves the SPA build (SPA_DIST_DIR, default frontend/dist):
mounts /assets and a GET catch-all returning index.html for client routes;
catch-all 404s on /api/*, never swallows /docs, /openapi.json, /static, assets,
ingestion/ticktick/status; skips SPA serving when dist absent (backend-only CI)
- delete app/api/routes/pages.py, app/api/routes/auth.py, app/templates/
(all replaced by /api/* + SPA; auth service layer kept)
- remove/replace Jinja page tests (JSON coverage already in test_api_*);
add tests/test_spa_hosting.py for the fallback contract
- regenerate openapi/ (Jinja paths gone) and frontend schema.d.ts
2026-06-13 15:20:50 +02:00
tliu93
0fba7cfe11
M2-T03: add read-only data JSON API
...
- GET /api/locations (inclusive time window start/end, pagination, cap 5000)
- GET /api/poo (pagination, cap 1000, newest first)
- GET /api/public-ip (current state + recent history, cap 1000)
- all session-protected, read-only, bounded (no full-table export)
- typed response schemas; register router; regenerate openapi/
- tests/test_api_data.py
2026-06-12 23:24:17 +02:00
tliu93
8da1f13e60
M2-T02: add session/auth JSON API for the SPA
...
- GET /api/session (user + csrf_token, 401 when unauthenticated)
- POST /api/auth/login (sets HttpOnly session cookie; 401 on bad creds; no CSRF)
- POST /api/auth/logout (session+CSRF; revokes session, clears cookie; 204)
- POST /api/auth/password (session+CSRF; reuses change_password; 400 on failure; 204)
- reuses app/services/auth.py and shared require_session/require_csrf deps
- register router in app/main.py; regenerate openapi/
- tests/test_api_session.py
2026-06-12 23:15:56 +02:00
tliu93
c2b1b7b751
M2-T01: add config JSON API (GET/PUT /api/config)
...
- new app/api/routes/api/ package with shared require_session (401) and
require_csrf (presence-only X-CSRF-Token, 403) dependencies
- GET /api/config returns masked config sections; PUT /api/config reuses
save_config_updates (blank secret keeps old; invalid -> 422, no write)
- session-protected; PUT also CSRF-protected
- register router in app/main.py; regenerate openapi/
- tests/test_api_config.py
2026-06-12 23:08:14 +02:00
tliu93
0d898e09f2
M1-T04: converge startup chain onto the single app DB
...
run_all_migrations() now adopts/initializes only the app DB and returns
{'app': ...}. app/main.py drops the location/poo readiness checks
(ensure_location_db_ready / ensure_poo_db_ready) and their imports;
ensure_runtime_dirs only provisions the app DB path; lifespan still
fail-closes on a missing/unmanaged app DB. Delete the retired
location/poo adopt scripts and the alembic_location / alembic_poo
chains. Update tests to single-DB expectations and drop the obsolete
location/poo adoption + readiness tests.
pytest 95 passed; ruff clean (pre-existing only); a fresh app DB
initialized via scripts.run_migrations contains location + poo_records.
2026-06-12 16:50:05 +02:00
tliu93
3d3c2bcc57
M1-T03: unify data layer, models, deps and routes onto single app DB
...
Collapse the three data layers into one. app/db.py now exposes a single
Base, a cached engine bound to app_database_url with SQLite WAL enabled, and
get_engine/get_session_local/reset_db_caches/get_db_session. Delete
app/auth_db.py, app/poo_db.py and app/models/base.py. All models (auth,
config, public_ip, location, poo) inherit the one Base and register on a
single metadata. Dependencies converge to a single get_db; all routes use it.
Also update the alembic env.py files (app/location/poo) and tests that
imported the removed modules so the suite stays green, and drop the obsolete
test_legacy_style_location_db test whose flow (app reading a separate location
DB) no longer exists. Location/poo Alembic chains, adopt scripts and adoption
tests remain for M1-T04; config fields remain for M1-T05.
pytest 109 passed; ruff clean (pre-existing only); WAL verified; single
Base.metadata holds all seven tables.
2026-06-12 16:35:07 +02:00
tliu93
779e160b95
add ip change notification and refine sender display
pytest / test (push) Successful in 57s
pytest / test (pull_request) Successful in 54s
2026-04-29 13:03:12 +02:00
tliu93
5a420bd37b
add get public and storage feature
2026-04-29 11:45:49 +02:00
tliu93
1805d5d8ea
Finalize first Python release
pytest / test (push) Successful in 40s
pytest / test (pull_request) Successful in 41s
2026-04-20 20:40:04 +02:00
tliu93
982af62f4f
Migrate TickTick OAuth and action tasks
2026-04-20 17:06:03 +02:00
tliu93
179aae264e
Persist runtime config in app db and seed from env
2026-04-20 15:56:10 +02:00
tliu93
e1aad408ab
Add auth foundation and app DB management
2026-04-20 15:16:47 +02:00
tliu93
044b47c573
Migrate poo recorder and align Alembic naming
2026-04-20 11:48:48 +02:00
tliu93
e334df992f
Add Home Assistant inbound gateway
2026-04-20 10:42:35 +02:00
tliu93
1a2f9c75d9
Harden location db startup validation
2026-04-19 23:02:43 +02:00
tliu93
32cc6847fd
Migrate location recorder and refine db config
2026-04-19 21:39:23 +02:00
tliu93
31390882ef
Bootstrap Python rewrite skeleton
2026-04-19 20:19:58 +02:00