Update README, MIGRATION.md, and CLAUDE.md for current feature set
This commit is contained in:
@@ -53,6 +53,10 @@ journalctl --user -u battery-tracker -f
|
|||||||
- Unretire: sets status back to `available`
|
- Unretire: sets status back to `available`
|
||||||
- Unassign with `next` form field → redirects to that URL (must start with `/`); falls back to dashboard
|
- Unassign with `next` form field → redirects to that URL (must start with `/`); falls back to dashboard
|
||||||
- Logging a charge entry → sets `battery.battery_percentage = 100`
|
- Logging a charge entry → sets `battery.battery_percentage = 100`
|
||||||
|
- Retired batteries are excluded from `needs_attention` and `low_pct` warnings — both use the `active` list (`status in ("available", "installed")`); the template-side `low_pct` filter and the in-table ⚠ badge also guard against retired status
|
||||||
|
|
||||||
|
### Dashboard filtering
|
||||||
|
The dashboard route builds an `active` list (`status in ("available", "installed")`) used for all warning logic. Client-side filtering uses `data-status` attributes on each table row and `applyFilters()` in JS. The default filter state is `"active"` (retired rows hidden on page load); the Reset button restores `"active"`, not an empty filter. Column visibility choices are stored in `localStorage`.
|
||||||
|
|
||||||
### Home Assistant integration (optional)
|
### Home Assistant integration (optional)
|
||||||
`ha_client.py` wraps the HA REST API (`GET /api/states/<entity_id>`). `ha_poller.py` runs a daemon thread started in `create_app` only when `HOMEASSISTANT_URL` and `HOMEASSISTANT_API_KEY` are set. The poller queries all `Device` rows with `ha_entity_id IS NOT NULL`, fetches the current percentage from HA, and writes it to `battery_percentage` on each installed battery in that device. The poller uses its own `sessionmaker` session (not the request-scoped `scoped_session`). When HA is not configured the app behaves exactly as before — all HA UI is gated on `ha_enabled` passed to templates.
|
`ha_client.py` wraps the HA REST API (`GET /api/states/<entity_id>`). `ha_poller.py` runs a daemon thread started in `create_app` only when `HOMEASSISTANT_URL` and `HOMEASSISTANT_API_KEY` are set. The poller queries all `Device` rows with `ha_entity_id IS NOT NULL`, fetches the current percentage from HA, and writes it to `battery_percentage` on each installed battery in that device. The poller uses its own `sessionmaker` session (not the request-scoped `scoped_session`). When HA is not configured the app behaves exactly as before — all HA UI is gated on `ha_enabled` passed to templates.
|
||||||
|
|||||||
@@ -1,5 +1,81 @@
|
|||||||
# Schema Migrations
|
# Schema Migrations
|
||||||
|
|
||||||
|
## Adding battery metadata fields, device type, and history tables
|
||||||
|
|
||||||
|
These columns and tables were added over several feature commits. `create_all()` does not add columns to existing tables, so existing installations need the `ALTER TABLE` commands below. New tables (`capacity_test`, `charge_log`) are created automatically by `create_all()` on next restart for SQLite — the explicit SQL below is provided for reference and for MariaDB operators who manage schema manually.
|
||||||
|
|
||||||
|
**Always snapshot first:**
|
||||||
|
```bash
|
||||||
|
cp batteries.db batteries.db.$(date +%Y-%m-%d).snapshot
|
||||||
|
```
|
||||||
|
|
||||||
|
**SQLite:**
|
||||||
|
```bash
|
||||||
|
sqlite3 batteries.db "ALTER TABLE device ADD COLUMN device_type VARCHAR(50);"
|
||||||
|
sqlite3 batteries.db "ALTER TABLE battery ADD COLUMN size VARCHAR(20);"
|
||||||
|
sqlite3 batteries.db "ALTER TABLE battery ADD COLUMN chemistry VARCHAR(20);"
|
||||||
|
sqlite3 batteries.db "ALTER TABLE battery ADD COLUMN capacity_mah INTEGER;"
|
||||||
|
sqlite3 batteries.db "ALTER TABLE battery ADD COLUMN tested_capacity_mah INTEGER;"
|
||||||
|
sqlite3 batteries.db "ALTER TABLE battery ADD COLUMN tested_date VARCHAR(10);"
|
||||||
|
sqlite3 batteries.db "ALTER TABLE battery ADD COLUMN charge_cycles INTEGER;"
|
||||||
|
sqlite3 batteries.db "ALTER TABLE battery ADD COLUMN purchase_date VARCHAR(10);"
|
||||||
|
sqlite3 batteries.db "ALTER TABLE battery ADD COLUMN storage_location VARCHAR(100);"
|
||||||
|
```
|
||||||
|
|
||||||
|
New tables (auto-created on restart, shown here for reference):
|
||||||
|
```python
|
||||||
|
import sqlite3
|
||||||
|
conn = sqlite3.connect('batteries.db')
|
||||||
|
conn.execute('''CREATE TABLE IF NOT EXISTS capacity_test (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
battery_id INTEGER NOT NULL REFERENCES battery(id) ON DELETE CASCADE,
|
||||||
|
tested_capacity_mah INTEGER NOT NULL,
|
||||||
|
tested_date VARCHAR(10) NOT NULL,
|
||||||
|
notes TEXT
|
||||||
|
)''')
|
||||||
|
conn.execute('''CREATE TABLE IF NOT EXISTS charge_log (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
battery_id INTEGER NOT NULL REFERENCES battery(id) ON DELETE CASCADE,
|
||||||
|
charged_date VARCHAR(10) NOT NULL,
|
||||||
|
increment_cycles INTEGER NOT NULL DEFAULT 0,
|
||||||
|
notes TEXT
|
||||||
|
)''')
|
||||||
|
conn.commit(); conn.close()
|
||||||
|
```
|
||||||
|
|
||||||
|
**MariaDB / MySQL:**
|
||||||
|
```sql
|
||||||
|
ALTER TABLE device ADD COLUMN device_type VARCHAR(50) NULL;
|
||||||
|
ALTER TABLE battery ADD COLUMN size VARCHAR(20) NULL;
|
||||||
|
ALTER TABLE battery ADD COLUMN chemistry VARCHAR(20) NULL;
|
||||||
|
ALTER TABLE battery ADD COLUMN capacity_mah INT NULL;
|
||||||
|
ALTER TABLE battery ADD COLUMN tested_capacity_mah INT NULL;
|
||||||
|
ALTER TABLE battery ADD COLUMN tested_date VARCHAR(10) NULL;
|
||||||
|
ALTER TABLE battery ADD COLUMN charge_cycles INT NULL;
|
||||||
|
ALTER TABLE battery ADD COLUMN purchase_date VARCHAR(10) NULL;
|
||||||
|
ALTER TABLE battery ADD COLUMN storage_location VARCHAR(100) NULL;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS capacity_test (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
battery_id INT NOT NULL,
|
||||||
|
tested_capacity_mah INT NOT NULL,
|
||||||
|
tested_date VARCHAR(10) NOT NULL,
|
||||||
|
notes TEXT,
|
||||||
|
CONSTRAINT fk_ct_battery FOREIGN KEY (battery_id) REFERENCES battery(id) ON DELETE CASCADE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS charge_log (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
battery_id INT NOT NULL,
|
||||||
|
charged_date VARCHAR(10) NOT NULL,
|
||||||
|
increment_cycles INT NOT NULL DEFAULT 0,
|
||||||
|
notes TEXT,
|
||||||
|
CONSTRAINT fk_cl_battery FOREIGN KEY (battery_id) REFERENCES battery(id) ON DELETE CASCADE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Adding battery_pct_log table
|
## Adding battery_pct_log table
|
||||||
|
|
||||||
This table was added to track battery percentage change history.
|
This table was added to track battery percentage change history.
|
||||||
|
|||||||
@@ -45,11 +45,13 @@ Battery Tracker gives you a single source of truth:
|
|||||||
|
|
||||||
### Dashboard
|
### Dashboard
|
||||||
- Overview stats (total / available / installed / retired) + **Low Battery** count when any battery is below 20%
|
- Overview stats (total / available / installed / retired) + **Low Battery** count when any battery is below 20%
|
||||||
|
- **Needs Attention** panel — highlights batteries with low capacity (< 80% of rated) or low percentage (< 20%, requires HA)
|
||||||
- Charge summary: total charge events and events in the last year
|
- Charge summary: total charge events and events in the last year
|
||||||
- Full battery table with client-side filtering by status, brand, size, storage location, and free-text search
|
- Full battery table with client-side filtering by status, brand, size, storage location, and free-text search; **retired batteries hidden by default** (change the Status filter to show them)
|
||||||
|
- Sortable columns
|
||||||
- Column picker (Chemistry, Capacity, Storage, Purchase Date, Cycles, Battery %) stored in localStorage
|
- Column picker (Chemistry, Capacity, Storage, Purchase Date, Cycles, Battery %) stored in localStorage
|
||||||
- Quick-assign available batteries to a device without leaving the page
|
- Quick-assign available batteries to a device without leaving the page
|
||||||
- Bulk actions: Unassign, Retire, Delete, Set Field (storage location or brand), Install in Device
|
- Bulk actions: Unassign, Retire, Delete, Set Field (storage location or brand), Install in Device, Log Charged
|
||||||
|
|
||||||
### History & Charts
|
### History & Charts
|
||||||
- **Capacity history** — track tested capacity over time with a trend chart; full log in a modal with year filter and pagination
|
- **Capacity history** — track tested capacity over time with a trend chart; full log in a modal with year filter and pagination
|
||||||
@@ -79,7 +81,7 @@ Battery Tracker gives you a single source of truth:
|
|||||||
| Database | SQLite (dev) / MariaDB (prod) |
|
| Database | SQLite (dev) / MariaDB (prod) |
|
||||||
| WSGI server | Waitress |
|
| WSGI server | Waitress |
|
||||||
| Process manager | systemd user service |
|
| Process manager | systemd user service |
|
||||||
| Tests | pytest (80 acceptance tests) |
|
| Tests | pytest (82 tests) |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user