331 lines
9.5 KiB
Markdown
331 lines
9.5 KiB
Markdown
# Seismo Fleet Manager v0.1.1
|
|
|
|
Backend API and web interface for managing seismograph fleet status. Track multiple seismographs calling in data from remote deployments, monitor their status, and manage your fleet through a unified database.
|
|
|
|
## Features
|
|
|
|
- **Web Dashboard**: Modern, responsive UI with dark/light mode support
|
|
- **Fleet Monitoring**: Track all seismograph units in one place
|
|
- **Roster Management**: Full CRUD operations via API or CSV import *(New in v0.1.1)*
|
|
- **Status Management**: Automatically mark units as OK, Pending (>12h), or Missing (>24h)
|
|
- **Data Ingestion**: Accept reports from emitter scripts via REST API
|
|
- **Photo Management**: Upload and view photos for each unit
|
|
- **Interactive Maps**: Leaflet-based maps showing unit locations
|
|
- **SQLite Storage**: Lightweight, file-based database for easy deployment
|
|
|
|
## Tech Stack
|
|
|
|
- **FastAPI**: Modern, fast web framework
|
|
- **SQLAlchemy**: SQL toolkit and ORM
|
|
- **SQLite**: Lightweight database
|
|
- **HTMX**: Dynamic updates without heavy JavaScript frameworks
|
|
- **TailwindCSS**: Utility-first CSS framework
|
|
- **Leaflet**: Interactive maps
|
|
- **Jinja2**: Server-side templating
|
|
- **uvicorn**: ASGI server
|
|
- **Docker**: Containerization for easy deployment
|
|
|
|
## Quick Start with Docker Compose (Recommended)
|
|
|
|
### Prerequisites
|
|
- Docker and Docker Compose installed
|
|
|
|
### Running the Application
|
|
|
|
1. **Start the service:**
|
|
```bash
|
|
docker compose up -d
|
|
```
|
|
|
|
2. **Check logs:**
|
|
```bash
|
|
docker compose logs -f
|
|
```
|
|
|
|
3. **Stop the service:**
|
|
```bash
|
|
docker compose down
|
|
```
|
|
|
|
The application will be available at:
|
|
- **Web Interface**: http://localhost:8001
|
|
- **API Documentation**: http://localhost:8001/docs
|
|
- **Health Check**: http://localhost:8001/health
|
|
|
|
### Data Persistence
|
|
|
|
The SQLite database and photos are stored in the `./data` directory, which is mounted as a volume. Your data will persist even if you restart or rebuild the container.
|
|
|
|
## Local Development (Without Docker)
|
|
|
|
### Prerequisites
|
|
- Python 3.11+
|
|
- pip
|
|
|
|
### Setup
|
|
|
|
1. **Install dependencies:**
|
|
```bash
|
|
pip install -r requirements.txt
|
|
```
|
|
|
|
2. **Run the server:**
|
|
```bash
|
|
uvicorn backend.main:app --host 0.0.0.0 --port 8001 --reload
|
|
```
|
|
|
|
The application will be available at http://localhost:8001
|
|
|
|
## API Endpoints
|
|
|
|
### Web Pages
|
|
- **GET** `/` - Dashboard home page
|
|
- **GET** `/roster` - Fleet roster page
|
|
- **GET** `/unit/{unit_id}` - Unit detail page
|
|
|
|
### Fleet Status & Monitoring
|
|
- **GET** `/api/status-snapshot` - Complete fleet status snapshot
|
|
- **GET** `/api/roster` - List of all units with metadata
|
|
- **GET** `/api/unit/{unit_id}` - Detailed unit information
|
|
- **GET** `/health` - Health check endpoint
|
|
|
|
### Roster Management *(New in v0.1.1)*
|
|
- **POST** `/api/roster/add` - Add new unit to roster
|
|
```bash
|
|
curl -X POST http://localhost:8001/api/roster/add \
|
|
-F "id=BE1234" \
|
|
-F "unit_type=series3" \
|
|
-F "deployed=true" \
|
|
-F "note=Main site sensor"
|
|
```
|
|
- **POST** `/api/roster/set-deployed/{unit_id}` - Toggle deployment status
|
|
- **POST** `/api/roster/set-retired/{unit_id}` - Toggle retired status
|
|
- **POST** `/api/roster/set-note/{unit_id}` - Update unit notes
|
|
- **POST** `/api/roster/import-csv` - Bulk import from CSV
|
|
```bash
|
|
curl -X POST http://localhost:8001/api/roster/import-csv \
|
|
-F "file=@roster.csv" \
|
|
-F "update_existing=true"
|
|
```
|
|
|
|
### CSV Import Format
|
|
Create a CSV file with the following columns (only `unit_id` is required):
|
|
```csv
|
|
unit_id,unit_type,deployed,retired,note,project_id,location
|
|
BE1234,series3,true,false,Primary sensor,PROJ-001,San Francisco CA
|
|
BE5678,series3,true,false,Backup sensor,PROJ-001,Los Angeles CA
|
|
```
|
|
|
|
See [sample_roster.csv](sample_roster.csv) for a working example.
|
|
|
|
### Emitter Reporting
|
|
- **POST** `/emitters/report` - Submit status report from a seismograph unit
|
|
- **POST** `/api/series3/heartbeat` - Series3 multi-unit telemetry payload
|
|
- **GET** `/fleet/status` - Retrieve status of all seismograph units (legacy)
|
|
|
|
### Photo Management
|
|
- **GET** `/api/unit/{unit_id}/photos` - List photos for a unit
|
|
- **GET** `/api/unit/{unit_id}/photo/{filename}` - Serve specific photo file
|
|
|
|
## API Documentation
|
|
|
|
Once running, interactive API documentation is available at:
|
|
- **Swagger UI**: http://localhost:8001/docs
|
|
- **ReDoc**: http://localhost:8001/redoc
|
|
|
|
## Testing the API
|
|
|
|
### Using curl
|
|
|
|
**Submit a report:**
|
|
```bash
|
|
curl -X POST http://localhost:8001/emitters/report \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"unit": "SEISMO-001",
|
|
"unit_type": "series3",
|
|
"timestamp": "2025-11-20T10:30:00",
|
|
"file": "event_20251120_103000.dat",
|
|
"status": "OK"
|
|
}'
|
|
```
|
|
|
|
**Get fleet status:**
|
|
```bash
|
|
curl http://localhost:8001/api/roster
|
|
```
|
|
|
|
**Import roster from CSV:**
|
|
```bash
|
|
curl -X POST http://localhost:8001/api/roster/import-csv \
|
|
-F "file=@sample_roster.csv" \
|
|
-F "update_existing=true"
|
|
```
|
|
|
|
### Using Python
|
|
|
|
```python
|
|
import requests
|
|
from datetime import datetime
|
|
|
|
# Submit report
|
|
response = requests.post(
|
|
"http://localhost:8001/emitters/report",
|
|
json={
|
|
"unit": "SEISMO-001",
|
|
"unit_type": "series3",
|
|
"timestamp": datetime.utcnow().isoformat(),
|
|
"file": "event_20251120_103000.dat",
|
|
"status": "OK"
|
|
}
|
|
)
|
|
print(response.json())
|
|
|
|
# Get fleet status
|
|
response = requests.get("http://localhost:8001/api/roster")
|
|
print(response.json())
|
|
|
|
# Import CSV
|
|
with open('roster.csv', 'rb') as f:
|
|
files = {'file': f}
|
|
data = {'update_existing': 'true'}
|
|
response = requests.post(
|
|
"http://localhost:8001/api/roster/import-csv",
|
|
files=files,
|
|
data=data
|
|
)
|
|
print(response.json())
|
|
```
|
|
|
|
## Data Model
|
|
|
|
### RosterUnit Table (Your Fleet Roster)
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| id | string | Unit identifier (primary key) |
|
|
| unit_type | string | Type of seismograph (default: "series3") |
|
|
| deployed | boolean | Whether unit is deployed in field |
|
|
| retired | boolean | Whether unit is retired from service |
|
|
| note | string | Notes about the unit |
|
|
| project_id | string | Associated project identifier |
|
|
| location | string | Deployment location description |
|
|
| last_updated | datetime | Last modification timestamp |
|
|
|
|
### Emitter Table (Device Check-ins)
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| id | string | Unit identifier (primary key) |
|
|
| unit_type | string | Type of seismograph (e.g., "series3") |
|
|
| last_seen | datetime | Last report timestamp |
|
|
| last_file | string | Last file processed |
|
|
| status | string | Current status: OK, Pending, Missing |
|
|
| notes | string | Optional notes (nullable) |
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
seismo-fleet-manager/
|
|
├── backend/
|
|
│ ├── main.py # FastAPI app entry point
|
|
│ ├── database.py # SQLAlchemy database configuration
|
|
│ ├── models.py # Database models (RosterUnit, Emitter)
|
|
│ ├── routes.py # Legacy API endpoints
|
|
│ ├── routers/ # Modular API routers
|
|
│ │ ├── roster.py # Fleet status endpoints
|
|
│ │ ├── roster_edit.py # Roster management & CSV import
|
|
│ │ ├── units.py # Unit detail endpoints
|
|
│ │ ├── photos.py # Photo management
|
|
│ │ ├── dashboard.py # Dashboard partials
|
|
│ │ └── dashboard_tabs.py # Dashboard tab endpoints
|
|
│ ├── services/
|
|
│ │ └── snapshot.py # Fleet status snapshot logic
|
|
│ └── static/ # Static assets (CSS, etc.)
|
|
├── templates/ # Jinja2 HTML templates
|
|
│ ├── base.html # Base layout with sidebar
|
|
│ ├── dashboard.html # Main dashboard
|
|
│ ├── roster.html # Fleet roster table
|
|
│ ├── unit_detail.html # Unit detail page
|
|
│ └── partials/ # HTMX partial templates
|
|
├── data/ # SQLite database & photos (persisted)
|
|
├── requirements.txt # Python dependencies
|
|
├── Dockerfile # Docker container definition
|
|
├── docker-compose.yml # Docker Compose configuration
|
|
├── CHANGELOG.md # Version history
|
|
├── FRONTEND_README.md # Frontend documentation
|
|
└── README.md # This file
|
|
```
|
|
|
|
## Docker Commands
|
|
|
|
**Build the image:**
|
|
```bash
|
|
docker compose build
|
|
```
|
|
|
|
**Start in foreground:**
|
|
```bash
|
|
docker compose up
|
|
```
|
|
|
|
**Start in background:**
|
|
```bash
|
|
docker compose up -d
|
|
```
|
|
|
|
**View logs:**
|
|
```bash
|
|
docker compose logs -f seismo-backend
|
|
```
|
|
|
|
**Restart service:**
|
|
```bash
|
|
docker compose restart
|
|
```
|
|
|
|
**Rebuild and restart:**
|
|
```bash
|
|
docker compose up -d --build
|
|
```
|
|
|
|
**Stop and remove containers:**
|
|
```bash
|
|
docker compose down
|
|
```
|
|
|
|
**Remove containers and volumes:**
|
|
```bash
|
|
docker compose down -v
|
|
```
|
|
|
|
## What's New in v0.1.1
|
|
|
|
- **Roster Editing API**: Full CRUD operations for managing your fleet roster
|
|
- **CSV Import**: Bulk upload roster data from CSV files
|
|
- **Enhanced Data Model**: Added project_id and location fields to roster
|
|
- **Bug Fixes**: Improved database session management and error handling
|
|
- **Dashboard Improvements**: Separate views for Active, Benched, and Retired units
|
|
|
|
See [CHANGELOG.md](CHANGELOG.md) for complete version history.
|
|
|
|
## Future Enhancements
|
|
|
|
- Email/SMS alerts for missing units
|
|
- Historical data tracking and reporting
|
|
- Multi-user authentication
|
|
- PostgreSQL support for larger deployments
|
|
- Advanced filtering and search
|
|
- Export roster to various formats
|
|
- Automated backup and restore
|
|
|
|
## License
|
|
|
|
MIT
|
|
|
|
## Version
|
|
|
|
**Current: 0.1.1** - Roster Management & CSV Import (2025-12-02)
|
|
|
|
Previous: 0.1.0 - Initial Release (2024-11-20)
|