# Device Type Dashboards

This document describes the separate dashboard system for different device types in SFM.

## Overview

SFM now has dedicated dashboards for each device type:
- **Main Dashboard** (`/`) - Combined overview of all devices
- **Seismographs Dashboard** (`/seismographs`) - Seismograph-specific view
- **Sound Level Meters Dashboard** (`/sound-level-meters`) - SLM-specific view
- **Fleet Roster** (`/roster`) - All devices with filtering and management

## Architecture

### 1. Main Dashboard

**Route**: `/`
**Template**: [templates/dashboard.html](../templates/dashboard.html)
**Purpose**: Combined overview showing all device types

**Features**:
- Fleet summary card now includes device type breakdown
- Shows count of seismographs and SLMs separately
- Links to dedicated dashboards for each device type
- Shared components: map, alerts, recent photos, fleet status

**Device Type Counts**:
The dashboard calculates device type counts in JavaScript from the snapshot data:

```javascript
// Device type counts
let seismoCount = 0;
let slmCount = 0;
Object.values(data.units || {}).forEach(unit => {
    if (unit.retired) return; // Don't count retired units
    const deviceType = unit.device_type || 'seismograph';
    if (deviceType === 'seismograph') {
        seismoCount++;
    } else if (deviceType === 'sound_level_meter') {
        slmCount++;
    }
});
```

### 2. Seismographs Dashboard

**Route**: `/seismographs`
**Template**: [templates/seismographs.html](../templates/seismographs.html)
**Router**: [backend/routers/seismo_dashboard.py](../backend/routers/seismo_dashboard.py)

**API Endpoints**:
- `GET /api/seismo-dashboard/stats` - Statistics summary (HTML partial)
- `GET /api/seismo-dashboard/units?search=<query>` - Unit list with search (HTML partial)

**Features**:
- Statistics cards (total, deployed, benched, with/without modem)
- Searchable unit list with real-time filtering
- Shows modem assignments
- Links to individual unit detail pages

**Stats Calculation** ([backend/routers/seismo_dashboard.py:18](../backend/routers/seismo_dashboard.py#L18)):

```python
seismos = db.query(RosterUnit).filter_by(
    device_type="seismograph",
    retired=False
).all()

total = len(seismos)
deployed = sum(1 for s in seismos if s.deployed)
benched = sum(1 for s in seismos if not s.deployed)
with_modem = sum(1 for s in seismos if s.deployed and s.deployed_with_modem_id)
```

### 3. Sound Level Meters Dashboard

**Route**: `/sound-level-meters`
**Template**: [templates/sound_level_meters.html](../templates/sound_level_meters.html)
**Router**: [backend/routers/slm_dashboard.py](../backend/routers/slm_dashboard.py)

**API Endpoints**:
- `GET /api/slm-dashboard/stats` - Statistics summary (HTML partial)
- `GET /api/slm-dashboard/units?search=<query>` - Unit list with search (HTML partial)
- `GET /api/slm-dashboard/live-view/{unit_id}` - Live view panel (HTML partial)

**Features**:
- Statistics cards (total, deployed, benched, measuring)
- Searchable unit list
- Live view panel with real-time measurement data
- WebSocket integration for DRD streaming
- Shows modem assignments and IP resolution

See [SOUND_LEVEL_METERS_DASHBOARD.md](SOUND_LEVEL_METERS_DASHBOARD.md) for detailed SLM dashboard documentation.

## Navigation

The sidebar navigation ([templates/base.html:116-128](../templates/base.html#L116-L128)) includes links to both dashboards:

```html
<a href="/seismographs">
    <svg>...</svg>
    Seismographs
</a>

<a href="/sound-level-meters">
    <svg>...</svg>
    Sound Level Meters
</a>
```

Active page highlighting is automatic based on `request.url.path`.

## Database Queries

All dashboards filter by device type using SQLAlchemy:

### Seismographs Query
```python
seismos = db.query(RosterUnit).filter_by(
    device_type="seismograph",
    retired=False
).all()
```

### Sound Level Meters Query
```python
slms = db.query(RosterUnit).filter_by(
    device_type="slm",
    retired=False
).all()
```

### With Search Filter
```python
query = db.query(RosterUnit).filter_by(
    device_type="seismograph",
    retired=False
)

if search:
    query = query.filter(
        (RosterUnit.id.ilike(f"%{search}%")) |
        (RosterUnit.note.ilike(f"%{search}%")) |
        (RosterUnit.address.ilike(f"%{search}%"))
    )
```

## UI Components

### Stats Cards (Partials)

**Seismograph Stats**: [templates/partials/seismo_stats.html](../templates/partials/seismo_stats.html)
- Total Seismographs
- Deployed
- Benched
- With Modem (showing X / Y deployed)

**SLM Stats**: [templates/partials/slm_stats.html](../templates/partials/slm_stats.html)
- Total SLMs
- Deployed
- Benched
- Currently Measuring (from live status)

### Unit Lists (Partials)

**Seismograph List**: [templates/partials/seismo_unit_list.html](../templates/partials/seismo_unit_list.html)

Table columns:
- Unit ID (link to detail page)
- Status (Deployed/Benched badge)
- Modem (link to modem unit)
- Location (address or coordinates)
- Notes
- Actions (View Details link)

**SLM List**: [templates/partials/slm_unit_list.html](../templates/partials/slm_unit_list.html)

Table columns:
- Unit ID (link to detail page)
- Model (NL-43, NL-53)
- Status (Deployed/Benched badge)
- Modem (link to modem unit)
- Location
- Actions (View Details, Live View)

## HTMX Integration

Both dashboards use HTMX for dynamic updates:

### Auto-refresh Stats
```html
<div hx-get="/api/seismo-dashboard/stats"
     hx-trigger="load, every 30s"
     hx-swap="innerHTML">
```

### Search with Debouncing
```html
<input type="text"
       hx-get="/api/seismo-dashboard/units"
       hx-trigger="keyup changed delay:300ms"
       hx-target="#seismo-units-list"
       name="search" />
```

## Adding New Device Types

To add support for a new device type (e.g., "modem"):

1. **Create Router** (`backend/routers/modem_dashboard.py`):
```python
@router.get("/stats", response_class=HTMLResponse)
async def get_modem_stats(request: Request, db: Session = Depends(get_db)):
    modems = db.query(RosterUnit).filter_by(
        device_type="modem",
        retired=False
    ).all()
    # Calculate stats and return partial
```

2. **Create Templates**:
   - `templates/modems.html` - Main dashboard page
   - `templates/partials/modem_stats.html` - Stats cards
   - `templates/partials/modem_unit_list.html` - Unit list table

3. **Register in main.py**:
```python
from backend.routers import modem_dashboard
app.include_router(modem_dashboard.router)

@app.get("/modems", response_class=HTMLResponse)
async def modems_page(request: Request):
    return templates.TemplateResponse("modems.html", {"request": request})
```

4. **Add to Navigation** (`templates/base.html`):
```html
<a href="/modems">
    <svg>...</svg>
    Modems
</a>
```

5. **Update Main Dashboard** (`templates/dashboard.html`):
Add modem count to the device type breakdown:
```html
<div class="flex justify-between items-center">
    <a href="/modems">Modems</a>
    <span id="modem-count">--</span>
</div>
```

Update JavaScript to count modems:
```javascript
let modemCount = 0;
Object.values(data.units || {}).forEach(unit => {
    if (unit.device_type === 'modem' && !unit.retired) {
        modemCount++;
    }
});
document.getElementById('modem-count').textContent = modemCount;
```

## Benefits

1. **Separation of Concerns**: Each device type has its own dedicated interface
2. **Scalability**: Easy to add new device types following the established pattern
3. **Performance**: Queries are filtered by device type, reducing data transfer
4. **User Experience**: Users can focus on specific device types without clutter
5. **Maintainability**: Each dashboard is self-contained and easy to modify

## Related Documentation

- [SOUND_LEVEL_METERS_DASHBOARD.md](SOUND_LEVEL_METERS_DASHBOARD.md) - SLM dashboard details
- [DEVICE_TYPE_SLM_SUPPORT.md](DEVICE_TYPE_SLM_SUPPORT.md) - Adding SLM device type support
- [MODEM_INTEGRATION.md](MODEM_INTEGRATION.md) - Modem assignment architecture
