|
|
|
@@ -0,0 +1,288 @@
|
|
|
|
|
# Device Type Schema - Terra-View
|
|
|
|
|
|
|
|
|
|
## Overview
|
|
|
|
|
|
|
|
|
|
Terra-View uses a single roster table to manage three different device types. The `device_type` field is the primary discriminator that determines which fields are relevant for each unit.
|
|
|
|
|
|
|
|
|
|
## Official device_type Values
|
|
|
|
|
|
|
|
|
|
As of **Terra-View v0.4.3**, the following device_type values are standardized:
|
|
|
|
|
|
|
|
|
|
### 1. `"seismograph"` (Default)
|
|
|
|
|
**Purpose**: Seismic monitoring devices
|
|
|
|
|
|
|
|
|
|
**Applicable Fields**:
|
|
|
|
|
- Common: id, unit_type, deployed, retired, note, project_id, location, address, coordinates
|
|
|
|
|
- Specific: last_calibrated, next_calibration_due, deployed_with_modem_id
|
|
|
|
|
|
|
|
|
|
**Examples**:
|
|
|
|
|
- `BE1234` - Series 3 seismograph
|
|
|
|
|
- `UM12345` - Series 4 Micromate unit
|
|
|
|
|
- `SEISMO-001` - Custom seismograph
|
|
|
|
|
|
|
|
|
|
**Unit Type Values**:
|
|
|
|
|
- `series3` - Series 3 devices (default)
|
|
|
|
|
- `series4` - Series 4 devices
|
|
|
|
|
- `micromate` - Micromate devices
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
### 2. `"modem"`
|
|
|
|
|
**Purpose**: Field modems and network equipment
|
|
|
|
|
|
|
|
|
|
**Applicable Fields**:
|
|
|
|
|
- Common: id, unit_type, deployed, retired, note, project_id, location, address, coordinates
|
|
|
|
|
- Specific: ip_address, phone_number, hardware_model
|
|
|
|
|
|
|
|
|
|
**Examples**:
|
|
|
|
|
- `MDM001` - Field modem
|
|
|
|
|
- `MODEM-2025-01` - Network modem
|
|
|
|
|
- `RAVEN-XTV-01` - Specific modem model
|
|
|
|
|
|
|
|
|
|
**Unit Type Values**:
|
|
|
|
|
- `modem` - Generic modem
|
|
|
|
|
- `raven-xtv` - Raven XTV model
|
|
|
|
|
- Custom values for specific hardware
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
### 3. `"slm"` ⭐
|
|
|
|
|
**Purpose**: Sound level meters (Rion NL-43/NL-53)
|
|
|
|
|
|
|
|
|
|
**Applicable Fields**:
|
|
|
|
|
- Common: id, unit_type, deployed, retired, note, project_id, location, address, coordinates
|
|
|
|
|
- Specific: slm_host, slm_tcp_port, slm_ftp_port, slm_model, slm_serial_number, slm_frequency_weighting, slm_time_weighting, slm_measurement_range, slm_last_check, deployed_with_modem_id
|
|
|
|
|
|
|
|
|
|
**Examples**:
|
|
|
|
|
- `SLM-43-01` - NL-43 sound level meter
|
|
|
|
|
- `NL43-001` - NL-43 unit
|
|
|
|
|
- `NL53-002` - NL-53 unit
|
|
|
|
|
|
|
|
|
|
**Unit Type Values**:
|
|
|
|
|
- `nl43` - Rion NL-43 model
|
|
|
|
|
- `nl53` - Rion NL-53 model
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## Migration from Legacy Values
|
|
|
|
|
|
|
|
|
|
### Deprecated Values
|
|
|
|
|
|
|
|
|
|
The following device_type values have been **deprecated** and should be migrated:
|
|
|
|
|
|
|
|
|
|
- ❌ `"sound_level_meter"` → ✅ `"slm"`
|
|
|
|
|
|
|
|
|
|
### How to Migrate
|
|
|
|
|
|
|
|
|
|
Run the standardization migration script to update existing databases:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
cd /home/serversdown/tmi/terra-view
|
|
|
|
|
python3 backend/migrate_standardize_device_types.py
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
This script:
|
|
|
|
|
- Converts all `"sound_level_meter"` values to `"slm"`
|
|
|
|
|
- Is idempotent (safe to run multiple times)
|
|
|
|
|
- Shows before/after distribution of device types
|
|
|
|
|
- No data loss
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## Database Schema
|
|
|
|
|
|
|
|
|
|
### RosterUnit Model (`backend/models.py`)
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
class RosterUnit(Base):
|
|
|
|
|
"""
|
|
|
|
|
Supports multiple device types:
|
|
|
|
|
- "seismograph" - Seismic monitoring devices (default)
|
|
|
|
|
- "modem" - Field modems and network equipment
|
|
|
|
|
- "slm" - Sound level meters (NL-43/NL-53)
|
|
|
|
|
"""
|
|
|
|
|
__tablename__ = "roster"
|
|
|
|
|
|
|
|
|
|
# Core fields (all device types)
|
|
|
|
|
id = Column(String, primary_key=True)
|
|
|
|
|
unit_type = Column(String, default="series3")
|
|
|
|
|
device_type = Column(String, default="seismograph") # "seismograph" | "modem" | "slm"
|
|
|
|
|
deployed = Column(Boolean, default=True)
|
|
|
|
|
retired = Column(Boolean, default=False)
|
|
|
|
|
# ... other common fields
|
|
|
|
|
|
|
|
|
|
# Seismograph-specific
|
|
|
|
|
last_calibrated = Column(Date, nullable=True)
|
|
|
|
|
next_calibration_due = Column(Date, nullable=True)
|
|
|
|
|
|
|
|
|
|
# Modem-specific
|
|
|
|
|
ip_address = Column(String, nullable=True)
|
|
|
|
|
phone_number = Column(String, nullable=True)
|
|
|
|
|
hardware_model = Column(String, nullable=True)
|
|
|
|
|
|
|
|
|
|
# SLM-specific
|
|
|
|
|
slm_host = Column(String, nullable=True)
|
|
|
|
|
slm_tcp_port = Column(Integer, nullable=True)
|
|
|
|
|
slm_ftp_port = Column(Integer, nullable=True)
|
|
|
|
|
slm_model = Column(String, nullable=True)
|
|
|
|
|
slm_serial_number = Column(String, nullable=True)
|
|
|
|
|
slm_frequency_weighting = Column(String, nullable=True)
|
|
|
|
|
slm_time_weighting = Column(String, nullable=True)
|
|
|
|
|
slm_measurement_range = Column(String, nullable=True)
|
|
|
|
|
slm_last_check = Column(DateTime, nullable=True)
|
|
|
|
|
|
|
|
|
|
# Shared fields (seismograph + SLM)
|
|
|
|
|
deployed_with_modem_id = Column(String, nullable=True) # FK to modem
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## API Usage
|
|
|
|
|
|
|
|
|
|
### Adding a New Unit
|
|
|
|
|
|
|
|
|
|
**Seismograph**:
|
|
|
|
|
```bash
|
|
|
|
|
curl -X POST http://localhost:8001/api/roster/add \
|
|
|
|
|
-F "id=BE1234" \
|
|
|
|
|
-F "device_type=seismograph" \
|
|
|
|
|
-F "unit_type=series3" \
|
|
|
|
|
-F "deployed=true"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**Modem**:
|
|
|
|
|
```bash
|
|
|
|
|
curl -X POST http://localhost:8001/api/roster/add \
|
|
|
|
|
-F "id=MDM001" \
|
|
|
|
|
-F "device_type=modem" \
|
|
|
|
|
-F "ip_address=192.0.2.10" \
|
|
|
|
|
-F "phone_number=+1-555-0100"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**Sound Level Meter**:
|
|
|
|
|
```bash
|
|
|
|
|
curl -X POST http://localhost:8001/api/roster/add \
|
|
|
|
|
-F "id=SLM-43-01" \
|
|
|
|
|
-F "device_type=slm" \
|
|
|
|
|
-F "slm_host=63.45.161.30" \
|
|
|
|
|
-F "slm_tcp_port=2255" \
|
|
|
|
|
-F "slm_model=NL-43"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### CSV Import Format
|
|
|
|
|
|
|
|
|
|
```csv
|
|
|
|
|
unit_id,unit_type,device_type,deployed,slm_host,slm_tcp_port,slm_model
|
|
|
|
|
SLM-43-01,nl43,slm,true,63.45.161.30,2255,NL-43
|
|
|
|
|
SLM-43-02,nl43,slm,true,63.45.161.31,2255,NL-43
|
|
|
|
|
BE1234,series3,seismograph,true,,,
|
|
|
|
|
MDM001,modem,modem,true,,,
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## Frontend Behavior
|
|
|
|
|
|
|
|
|
|
### Device Type Selection
|
|
|
|
|
|
|
|
|
|
**Templates**: `unit_detail.html`, `roster.html`
|
|
|
|
|
|
|
|
|
|
```html
|
|
|
|
|
<select name="device_type">
|
|
|
|
|
<option value="seismograph">Seismograph</option>
|
|
|
|
|
<option value="modem">Modem</option>
|
|
|
|
|
<option value="slm">Sound Level Meter</option>
|
|
|
|
|
</select>
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Conditional Field Display
|
|
|
|
|
|
|
|
|
|
JavaScript functions check `device_type` to show/hide relevant fields:
|
|
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
function toggleDetailFields() {
|
|
|
|
|
const deviceType = document.getElementById('device_type').value;
|
|
|
|
|
|
|
|
|
|
if (deviceType === 'seismograph') {
|
|
|
|
|
// Show calibration fields
|
|
|
|
|
} else if (deviceType === 'modem') {
|
|
|
|
|
// Show network fields
|
|
|
|
|
} else if (deviceType === 'slm') {
|
|
|
|
|
// Show SLM configuration fields
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## Code Conventions
|
|
|
|
|
|
|
|
|
|
### Always Use Lowercase
|
|
|
|
|
|
|
|
|
|
✅ **Correct**:
|
|
|
|
|
```python
|
|
|
|
|
if unit.device_type == "slm":
|
|
|
|
|
# Handle sound level meter
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
❌ **Incorrect**:
|
|
|
|
|
```python
|
|
|
|
|
if unit.device_type == "SLM": # Wrong - case sensitive
|
|
|
|
|
if unit.device_type == "sound_level_meter": # Deprecated
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Query Patterns
|
|
|
|
|
|
|
|
|
|
**Filter by device type**:
|
|
|
|
|
```python
|
|
|
|
|
# Get all SLMs
|
|
|
|
|
slms = db.query(RosterUnit).filter_by(device_type="slm").all()
|
|
|
|
|
|
|
|
|
|
# Get deployed seismographs
|
|
|
|
|
seismos = db.query(RosterUnit).filter_by(
|
|
|
|
|
device_type="seismograph",
|
|
|
|
|
deployed=True
|
|
|
|
|
).all()
|
|
|
|
|
|
|
|
|
|
# Get all modems
|
|
|
|
|
modems = db.query(RosterUnit).filter_by(device_type="modem").all()
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## Testing
|
|
|
|
|
|
|
|
|
|
### Verify Device Type Distribution
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
# Quick check
|
|
|
|
|
sqlite3 data/seismo_fleet.db "SELECT device_type, COUNT(*) FROM roster GROUP BY device_type;"
|
|
|
|
|
|
|
|
|
|
# Detailed view
|
|
|
|
|
sqlite3 data/seismo_fleet.db "SELECT id, device_type, unit_type, deployed FROM roster ORDER BY device_type, id;"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Check for Legacy Values
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
# Should return 0 rows after migration
|
|
|
|
|
sqlite3 data/seismo_fleet.db "SELECT id FROM roster WHERE device_type = 'sound_level_meter';"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## Version History
|
|
|
|
|
|
|
|
|
|
- **v0.4.3** (2026-01-16) - Standardized device_type values, deprecated `"sound_level_meter"` → `"slm"`
|
|
|
|
|
- **v0.4.0** (2026-01-05) - Added SLM support with `"sound_level_meter"` value
|
|
|
|
|
- **v0.2.0** (2025-12-03) - Added modem device type
|
|
|
|
|
- **v0.1.0** (2024-11-20) - Initial release with seismograph-only support
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## Related Documentation
|
|
|
|
|
|
|
|
|
|
- [README.md](../README.md) - Main project documentation with data model
|
|
|
|
|
- [DEVICE_TYPE_SLM_SUPPORT.md](DEVICE_TYPE_SLM_SUPPORT.md) - Legacy SLM implementation notes
|
|
|
|
|
- [SOUND_LEVEL_METERS_DASHBOARD.md](SOUND_LEVEL_METERS_DASHBOARD.md) - SLM dashboard features
|
|
|
|
|
- [SLM_CONFIGURATION.md](SLM_CONFIGURATION.md) - SLM device configuration guide
|