0.4.2 - Early implementation of SLMs. WIP.
This commit is contained in:
120
scripts/README.md
Normal file
120
scripts/README.md
Normal file
@@ -0,0 +1,120 @@
|
||||
# Helper Scripts
|
||||
|
||||
This directory contains helper scripts for database management and testing.
|
||||
|
||||
## Database Migration Scripts
|
||||
|
||||
### migrate_dev_db.py
|
||||
Migrates the DEV database schema to add SLM-specific columns to the `roster` table.
|
||||
|
||||
**Usage:**
|
||||
```bash
|
||||
cd /home/serversdown/sfm/seismo-fleet-manager
|
||||
python3 scripts/migrate_dev_db.py
|
||||
```
|
||||
|
||||
**What it does:**
|
||||
- Adds 8 SLM-specific columns to the DEV database (data-dev/seismo_fleet.db)
|
||||
- Columns: slm_host, slm_tcp_port, slm_model, slm_serial_number, slm_frequency_weighting, slm_time_weighting, slm_measurement_range, slm_last_check
|
||||
- Safe to run multiple times (skips existing columns)
|
||||
|
||||
### update_dev_db_schema.py
|
||||
Inspects and displays the DEV database schema.
|
||||
|
||||
**Usage:**
|
||||
```bash
|
||||
python3 scripts/update_dev_db_schema.py
|
||||
```
|
||||
|
||||
**What it does:**
|
||||
- Shows all tables in the DEV database
|
||||
- Lists all columns in the roster table
|
||||
- Useful for verifying schema after migrations
|
||||
|
||||
## Test Data Scripts
|
||||
|
||||
### add_test_slms.py
|
||||
Adds test Sound Level Meter units to the DEV database.
|
||||
|
||||
**Usage:**
|
||||
```bash
|
||||
python3 scripts/add_test_slms.py
|
||||
```
|
||||
|
||||
**What it creates:**
|
||||
- nl43-001: NL-43 SLM at Construction Site A
|
||||
- nl43-002: NL-43 SLM at Construction Site B
|
||||
- nl53-001: NL-53 SLM at Residential Area
|
||||
- nl43-003: NL-43 SLM (not deployed, spare unit)
|
||||
|
||||
### add_test_modems.py
|
||||
Adds test modem units to the DEV database and assigns them to SLMs.
|
||||
|
||||
**Usage:**
|
||||
```bash
|
||||
python3 scripts/add_test_modems.py
|
||||
```
|
||||
|
||||
**What it creates:**
|
||||
- modem-001, modem-002, modem-003: Deployed modems (Raven XTV and Sierra Wireless)
|
||||
- modem-004: Spare modem (not deployed)
|
||||
|
||||
**Modem assignments:**
|
||||
- nl43-001 → modem-001
|
||||
- nl43-002 → modem-002
|
||||
- nl53-001 → modem-003
|
||||
|
||||
## Cleanup Scripts
|
||||
|
||||
### remove_test_data_from_prod.py
|
||||
**⚠️ PRODUCTION DATABASE CLEANUP**
|
||||
|
||||
Removes test data from the production database (data/seismo_fleet.db).
|
||||
|
||||
**Status:** Already executed successfully. Production database is clean.
|
||||
|
||||
**What it removed:**
|
||||
- All test SLM units (nl43-001, nl43-002, nl53-001, nl43-003)
|
||||
- All test modem units (modem-001, modem-002, modem-003, modem-004)
|
||||
|
||||
## Database Cloning
|
||||
|
||||
### clone_db_to_dev.py
|
||||
Clones the production database to create/update the DEV database.
|
||||
|
||||
**Usage:**
|
||||
```bash
|
||||
python3 scripts/clone_db_to_dev.py
|
||||
```
|
||||
|
||||
**What it does:**
|
||||
- Copies data/seismo_fleet.db → data-dev/seismo_fleet.db
|
||||
- Useful for syncing DEV database with production schema/data
|
||||
|
||||
## Setup Sequence
|
||||
|
||||
To set up a fresh DEV database with test data:
|
||||
|
||||
```bash
|
||||
cd /home/serversdown/sfm/seismo-fleet-manager
|
||||
|
||||
# 1. Fix permissions (if needed)
|
||||
sudo chown -R serversdown:serversdown data-dev/
|
||||
|
||||
# 2. Migrate schema
|
||||
python3 scripts/migrate_dev_db.py
|
||||
|
||||
# 3. Add test data
|
||||
python3 scripts/add_test_slms.py
|
||||
python3 scripts/add_test_modems.py
|
||||
|
||||
# 4. Verify
|
||||
sqlite3 data-dev/seismo_fleet.db "SELECT id, device_type FROM roster WHERE device_type IN ('sound_level_meter', 'modem');"
|
||||
```
|
||||
|
||||
## Important Notes
|
||||
|
||||
- **DEV Database**: `data-dev/seismo_fleet.db` - Used for development and testing
|
||||
- **Production Database**: `data/seismo_fleet.db` - Used by the running application
|
||||
- All test scripts are configured to use the DEV database only
|
||||
- Never run test data scripts against production
|
||||
39
scripts/add_slm_ftp_port.py
Normal file
39
scripts/add_slm_ftp_port.py
Normal file
@@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Add slm_ftp_port column to roster table for FTP data retrieval port
|
||||
"""
|
||||
|
||||
from sqlalchemy import create_engine, text
|
||||
import os
|
||||
|
||||
# Determine database based on environment
|
||||
ENVIRONMENT = os.getenv("ENVIRONMENT", "production")
|
||||
if ENVIRONMENT == "development":
|
||||
DB_URL = "sqlite:///./data-dev/seismo_fleet.db"
|
||||
else:
|
||||
DB_URL = "sqlite:///./data/seismo_fleet.db"
|
||||
|
||||
def add_ftp_port_column():
|
||||
print(f"Adding slm_ftp_port column to {DB_URL}...")
|
||||
print("=" * 60)
|
||||
|
||||
engine = create_engine(DB_URL, connect_args={"check_same_thread": False})
|
||||
|
||||
with engine.connect() as conn:
|
||||
try:
|
||||
# Try to add the column
|
||||
conn.execute(text("ALTER TABLE roster ADD COLUMN slm_ftp_port INTEGER"))
|
||||
conn.commit()
|
||||
print("✓ Added column: slm_ftp_port (INTEGER)")
|
||||
except Exception as e:
|
||||
if "duplicate column name" in str(e).lower():
|
||||
print(" Column slm_ftp_port already exists, skipping")
|
||||
else:
|
||||
print(f"✗ Error adding slm_ftp_port: {e}")
|
||||
raise
|
||||
|
||||
print("=" * 60)
|
||||
print("Migration completed!")
|
||||
|
||||
if __name__ == "__main__":
|
||||
add_ftp_port_column()
|
||||
105
scripts/add_test_modems.py
Executable file
105
scripts/add_test_modems.py
Executable file
@@ -0,0 +1,105 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Add test modem units and assign them to SLMs in DEV database
|
||||
"""
|
||||
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from backend.models import RosterUnit
|
||||
from datetime import datetime
|
||||
|
||||
# DEV database
|
||||
DEV_DB_URL = "sqlite:///./data-dev/seismo_fleet.db"
|
||||
|
||||
def add_test_modems():
|
||||
engine = create_engine(DEV_DB_URL, connect_args={"check_same_thread": False})
|
||||
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||
db = SessionLocal()
|
||||
|
||||
# Test modems
|
||||
test_modems = [
|
||||
{
|
||||
"id": "modem-001",
|
||||
"device_type": "modem",
|
||||
"deployed": True,
|
||||
"retired": False,
|
||||
"note": "Raven XTV modem for Construction Site A",
|
||||
"address": "123 Main St, Construction Site A",
|
||||
"coordinates": "34.0522,-118.2437",
|
||||
"ip_address": "192.168.1.100",
|
||||
"phone_number": "+1-555-0100",
|
||||
"hardware_model": "Raven XTV"
|
||||
},
|
||||
{
|
||||
"id": "modem-002",
|
||||
"device_type": "modem",
|
||||
"deployed": True,
|
||||
"retired": False,
|
||||
"note": "Raven XTV modem for Construction Site B",
|
||||
"address": "456 Oak Ave, Construction Site B",
|
||||
"coordinates": "34.0622,-118.2537",
|
||||
"ip_address": "192.168.1.101",
|
||||
"phone_number": "+1-555-0101",
|
||||
"hardware_model": "Raven XTV"
|
||||
},
|
||||
{
|
||||
"id": "modem-003",
|
||||
"device_type": "modem",
|
||||
"deployed": True,
|
||||
"retired": False,
|
||||
"note": "Sierra Wireless modem for Residential Area",
|
||||
"address": "789 Elm St, Residential Area",
|
||||
"coordinates": "34.0722,-118.2637",
|
||||
"ip_address": "192.168.1.102",
|
||||
"phone_number": "+1-555-0102",
|
||||
"hardware_model": "Sierra Wireless AirLink"
|
||||
},
|
||||
{
|
||||
"id": "modem-004",
|
||||
"device_type": "modem",
|
||||
"deployed": False,
|
||||
"retired": False,
|
||||
"note": "Spare modem - not deployed",
|
||||
"ip_address": None,
|
||||
"phone_number": "+1-555-0103",
|
||||
"hardware_model": "Raven XTV"
|
||||
}
|
||||
]
|
||||
|
||||
for modem_data in test_modems:
|
||||
# Check if modem already exists
|
||||
existing = db.query(RosterUnit).filter_by(id=modem_data["id"]).first()
|
||||
if existing:
|
||||
print(f"Modem {modem_data['id']} already exists, skipping...")
|
||||
continue
|
||||
|
||||
modem = RosterUnit(**modem_data)
|
||||
db.add(modem)
|
||||
print(f"Added {modem_data['id']}")
|
||||
|
||||
# Assign modems to existing SLMs
|
||||
slm_modem_assignments = {
|
||||
"nl43-001": "modem-001",
|
||||
"nl43-002": "modem-002",
|
||||
"nl53-001": "modem-003"
|
||||
}
|
||||
|
||||
for slm_id, modem_id in slm_modem_assignments.items():
|
||||
slm = db.query(RosterUnit).filter_by(id=slm_id).first()
|
||||
if slm:
|
||||
slm.deployed_with_modem_id = modem_id
|
||||
# Remove legacy slm_host since we're using modems now
|
||||
slm.slm_host = None
|
||||
print(f"Assigned {slm_id} to {modem_id}")
|
||||
else:
|
||||
print(f"SLM {slm_id} not found, skipping assignment...")
|
||||
|
||||
db.commit()
|
||||
db.close()
|
||||
print("\nTest modems added and assigned to SLMs successfully in DEV database (data-dev/seismo_fleet.db)!")
|
||||
print("\nModem assignments:")
|
||||
for slm_id, modem_id in slm_modem_assignments.items():
|
||||
print(f" {slm_id} → {modem_id}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
add_test_modems()
|
||||
106
scripts/add_test_slms.py
Executable file
106
scripts/add_test_slms.py
Executable file
@@ -0,0 +1,106 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Add test Sound Level Meter units to the DEV database
|
||||
"""
|
||||
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from backend.models import RosterUnit
|
||||
from datetime import datetime
|
||||
|
||||
# DEV database
|
||||
DEV_DB_URL = "sqlite:///./data-dev/seismo_fleet.db"
|
||||
|
||||
def add_test_slms():
|
||||
engine = create_engine(DEV_DB_URL, connect_args={"check_same_thread": False})
|
||||
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||
db = SessionLocal()
|
||||
|
||||
test_slms = [
|
||||
{
|
||||
"id": "nl43-001",
|
||||
"device_type": "sound_level_meter",
|
||||
"deployed": True,
|
||||
"retired": False,
|
||||
"note": "Test unit at construction site A",
|
||||
"address": "123 Main St, Construction Site A",
|
||||
"coordinates": "34.0522,-118.2437",
|
||||
"slm_host": "192.168.1.100",
|
||||
"slm_tcp_port": 2255,
|
||||
"slm_model": "NL-43",
|
||||
"slm_serial_number": "123456",
|
||||
"slm_frequency_weighting": "A",
|
||||
"slm_time_weighting": "F",
|
||||
"slm_measurement_range": "30-130 dB",
|
||||
"slm_last_check": datetime.utcnow()
|
||||
},
|
||||
{
|
||||
"id": "nl43-002",
|
||||
"device_type": "sound_level_meter",
|
||||
"deployed": True,
|
||||
"retired": False,
|
||||
"note": "Test unit at construction site B",
|
||||
"address": "456 Oak Ave, Construction Site B",
|
||||
"coordinates": "34.0622,-118.2537",
|
||||
"slm_host": "192.168.1.101",
|
||||
"slm_tcp_port": 2255,
|
||||
"slm_model": "NL-43",
|
||||
"slm_serial_number": "123457",
|
||||
"slm_frequency_weighting": "A",
|
||||
"slm_time_weighting": "S",
|
||||
"slm_measurement_range": "30-130 dB",
|
||||
"slm_last_check": datetime.utcnow()
|
||||
},
|
||||
{
|
||||
"id": "nl53-001",
|
||||
"device_type": "sound_level_meter",
|
||||
"deployed": True,
|
||||
"retired": False,
|
||||
"note": "Test unit at residential monitoring",
|
||||
"address": "789 Elm St, Residential Area",
|
||||
"coordinates": "34.0722,-118.2637",
|
||||
"slm_host": "192.168.1.102",
|
||||
"slm_tcp_port": 2255,
|
||||
"slm_model": "NL-53",
|
||||
"slm_serial_number": "234567",
|
||||
"slm_frequency_weighting": "C",
|
||||
"slm_time_weighting": "F",
|
||||
"slm_measurement_range": "25-140 dB",
|
||||
"slm_last_check": datetime.utcnow()
|
||||
},
|
||||
{
|
||||
"id": "nl43-003",
|
||||
"device_type": "sound_level_meter",
|
||||
"deployed": False,
|
||||
"retired": False,
|
||||
"note": "Benched for calibration",
|
||||
"address": None,
|
||||
"coordinates": None,
|
||||
"slm_host": None,
|
||||
"slm_tcp_port": None,
|
||||
"slm_model": "NL-43",
|
||||
"slm_serial_number": "123458",
|
||||
"slm_frequency_weighting": "A",
|
||||
"slm_time_weighting": "F",
|
||||
"slm_measurement_range": "30-130 dB",
|
||||
"slm_last_check": None
|
||||
}
|
||||
]
|
||||
|
||||
for slm_data in test_slms:
|
||||
# Check if unit already exists
|
||||
existing = db.query(RosterUnit).filter_by(id=slm_data["id"]).first()
|
||||
if existing:
|
||||
print(f"Unit {slm_data['id']} already exists, skipping...")
|
||||
continue
|
||||
|
||||
unit = RosterUnit(**slm_data)
|
||||
db.add(unit)
|
||||
print(f"Added {slm_data['id']}")
|
||||
|
||||
db.commit()
|
||||
db.close()
|
||||
print("\nTest SLM units added successfully to DEV database (data-dev/seismo_fleet.db)!")
|
||||
|
||||
if __name__ == "__main__":
|
||||
add_test_slms()
|
||||
46
scripts/migrate_dev_db.py
Normal file
46
scripts/migrate_dev_db.py
Normal file
@@ -0,0 +1,46 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Migrate DEV database to add SLM-specific columns
|
||||
"""
|
||||
|
||||
from sqlalchemy import create_engine, text
|
||||
|
||||
# DEV database
|
||||
DEV_DB_URL = "sqlite:///./data-dev/seismo_fleet.db"
|
||||
|
||||
def migrate_dev_database():
|
||||
print("Migrating DEV database to add SLM columns...")
|
||||
print("=" * 60)
|
||||
|
||||
engine = create_engine(DEV_DB_URL, connect_args={"check_same_thread": False})
|
||||
|
||||
# SLM columns to add
|
||||
slm_columns = [
|
||||
("slm_host", "VARCHAR"),
|
||||
("slm_tcp_port", "INTEGER"),
|
||||
("slm_model", "VARCHAR"),
|
||||
("slm_serial_number", "VARCHAR"),
|
||||
("slm_frequency_weighting", "VARCHAR"),
|
||||
("slm_time_weighting", "VARCHAR"),
|
||||
("slm_measurement_range", "VARCHAR"),
|
||||
("slm_last_check", "DATETIME"),
|
||||
]
|
||||
|
||||
with engine.connect() as conn:
|
||||
for column_name, column_type in slm_columns:
|
||||
try:
|
||||
# Try to add the column
|
||||
conn.execute(text(f"ALTER TABLE roster ADD COLUMN {column_name} {column_type}"))
|
||||
conn.commit()
|
||||
print(f"✓ Added column: {column_name}")
|
||||
except Exception as e:
|
||||
if "duplicate column name" in str(e).lower():
|
||||
print(f" Column {column_name} already exists, skipping")
|
||||
else:
|
||||
print(f"✗ Error adding {column_name}: {e}")
|
||||
|
||||
print("=" * 60)
|
||||
print("DEV database migration completed!")
|
||||
|
||||
if __name__ == "__main__":
|
||||
migrate_dev_database()
|
||||
45
scripts/remove_test_data_from_prod.py
Normal file
45
scripts/remove_test_data_from_prod.py
Normal file
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Remove test SLMs and modems from PRODUCTION database
|
||||
"""
|
||||
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from backend.models import RosterUnit
|
||||
|
||||
# PRODUCTION database
|
||||
PROD_DB_URL = "sqlite:///./data/seismo_fleet.db"
|
||||
|
||||
def remove_test_data():
|
||||
engine = create_engine(PROD_DB_URL, connect_args={"check_same_thread": False})
|
||||
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||
db = SessionLocal()
|
||||
|
||||
# IDs to remove
|
||||
test_slm_ids = ["nl43-001", "nl43-002", "nl53-001", "nl43-003"]
|
||||
test_modem_ids = ["modem-001", "modem-002", "modem-003", "modem-004"]
|
||||
|
||||
all_test_ids = test_slm_ids + test_modem_ids
|
||||
|
||||
removed = []
|
||||
for unit_id in all_test_ids:
|
||||
unit = db.query(RosterUnit).filter_by(id=unit_id).first()
|
||||
if unit:
|
||||
db.delete(unit)
|
||||
removed.append(unit_id)
|
||||
print(f"Removed {unit_id}")
|
||||
|
||||
if removed:
|
||||
db.commit()
|
||||
print(f"\nRemoved {len(removed)} test units from PRODUCTION database")
|
||||
else:
|
||||
print("No test units found in production database")
|
||||
|
||||
db.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("Removing test data from PRODUCTION database...")
|
||||
print("=" * 60)
|
||||
remove_test_data()
|
||||
print("=" * 60)
|
||||
print("Done! Production database is clean.")
|
||||
39
scripts/update_dev_db_schema.py
Normal file
39
scripts/update_dev_db_schema.py
Normal file
@@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Update DEV database schema to match current models
|
||||
"""
|
||||
|
||||
from sqlalchemy import create_engine, inspect
|
||||
from backend.models import Base
|
||||
|
||||
# DEV database
|
||||
DEV_DB_URL = "sqlite:///./data-dev/seismo_fleet.db"
|
||||
|
||||
def update_schema():
|
||||
print("Updating DEV database schema...")
|
||||
print("=" * 60)
|
||||
|
||||
engine = create_engine(DEV_DB_URL, connect_args={"check_same_thread": False})
|
||||
|
||||
# Create all tables (will update existing tables with new columns)
|
||||
Base.metadata.create_all(bind=engine)
|
||||
|
||||
# Inspect to see what we have
|
||||
inspector = inspect(engine)
|
||||
tables = inspector.get_table_names()
|
||||
|
||||
print(f"Tables in DEV database: {tables}")
|
||||
|
||||
if 'roster' in tables:
|
||||
columns = [col['name'] for col in inspector.get_columns('roster')]
|
||||
print(f"\nColumns in roster table:")
|
||||
for col in sorted(columns):
|
||||
print(f" - {col}")
|
||||
|
||||
print("=" * 60)
|
||||
print("DEV database schema updated successfully!")
|
||||
print("\nNote: SQLite doesn't support ALTER COLUMN, so existing")
|
||||
print("columns won't be modified, but new columns will be added.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
update_schema()
|
||||
Reference in New Issue
Block a user