4.8 KiB
Schema Migrations
Adding Home Assistant fields (ha_entity_id, battery_percentage)
These columns were added in the Home Assistant integration feature. Existing databases
need a manual migration — create_all() does not add columns to existing tables.
Always snapshot first:
cp batteries.db batteries.db.$(date +%Y-%m-%d).snapshot
SQLite:
sqlite3 batteries.db "ALTER TABLE device ADD COLUMN ha_entity_id VARCHAR(100);"
sqlite3 batteries.db "ALTER TABLE battery ADD COLUMN battery_percentage INTEGER;"
MariaDB / MySQL:
ALTER TABLE device ADD COLUMN ha_entity_id VARCHAR(100) NULL;
ALTER TABLE battery ADD COLUMN battery_percentage INT NULL;
Both columns are nullable with no default, which is valid on all supported databases.
Migrating from SQLite to MariaDB
This guide covers moving the Battery Tracker database from SQLite to MariaDB/MySQL without changing any application code — only the connection string changes.
1. Install PyMySQL
source .venv/bin/activate
pip install pymysql
pip freeze > requirements.txt
2. Create the MariaDB database and user
CREATE DATABASE batteries CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'battuser'@'localhost' IDENTIFIED BY 'strongpassword';
GRANT ALL PRIVILEGES ON batteries.* TO 'battuser'@'localhost';
FLUSH PRIVILEGES;
3. Update the connection string
Set the DATABASE_URL environment variable before starting the app:
export DATABASE_URL='mysql+pymysql://battuser:strongpassword@localhost/batteries?charset=utf8mb4'
Or add it to a .env file and load it with your process manager / systemd service:
# In ~/.config/systemd/user/battery-tracker.service, add under [Service]:
Environment=DATABASE_URL=mysql+pymysql://battuser:strongpassword@localhost/batteries?charset=utf8mb4
4. (Optional) Use Flask-Migrate for schema management
Flask-Migrate lets you apply schema changes incrementally via flask db upgrade
rather than dropping and recreating tables.
pip install Flask-Migrate
In app.py, after the db setup, add:
from flask_migrate import Migrate
migrate = Migrate(app, db) # pass your SQLAlchemy db object
Then:
flask db init # first time only — creates migrations/ directory
flask db migrate -m "initial schema"
flask db upgrade
Note: The app uses raw SQLAlchemy (not Flask-SQLAlchemy), so you will need to adapt the
Migrate(app, db)call to wrap your engine/session. Alternatively, runBase.metadata.create_all(engine)directly for the initial schema — the app already does this on startup.
5. Run the migration script
The migrate_to_mariadb.py script reads every record from SQLite and inserts
it into MariaDB using the SQLAlchemy ORM — no raw SQL, no CSV exports.
MARIADB_URL='mysql+pymysql://battuser:strongpassword@localhost/batteries?charset=utf8mb4' \
python migrate_to_mariadb.py
Or pass the URL as a positional argument:
python migrate_to_mariadb.py 'mysql+pymysql://battuser:strongpassword@localhost/batteries?charset=utf8mb4'
The script:
- Creates all tables on MariaDB if they don't exist
- Inserts all Device records (preserving primary keys)
- Inserts all Battery records (preserving primary keys and foreign keys)
- Resets
AUTO_INCREMENTcounters past the highest migrated ID - Prints a verification table comparing row counts
6. Verify row counts
The migration script prints a summary:
=== Verification ===
Table SQLite MariaDB OK?
--------------------------------------
device 5 5 OK
battery 40 40 OK
Migration complete. All row counts match.
If you see MISMATCH, do not decommission SQLite. Re-run the script after
investigating the error output.
You can also verify manually in the MariaDB shell:
SELECT COUNT(*) FROM device;
SELECT COUNT(*) FROM battery;
7. MariaDB configuration notes
| Setting | Recommended value |
|---|---|
| Character set | utf8mb4 |
| Collation | utf8mb4_unicode_ci |
innodb_strict_mode |
ON (default in MariaDB 10.2+) |
sql_mode |
Include STRICT_TRANS_TABLES |
Set these in /etc/mysql/mariadb.conf.d/50-server.cnf (or equivalent):
[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
The ?charset=utf8mb4 query parameter in the connection string ensures the
client connection also uses utf8mb4, regardless of the server default.
8. Decommission SQLite
Once you have confirmed the row counts match and the app is running correctly against MariaDB:
# Optional: keep a backup
cp batteries.db batteries.db.bak
# Remove the SQLite file
rm batteries.db
The DATABASE_URL environment variable now fully controls which database is used —
no code changes were required.