# SLMM - Sound Level Meter Manager **Version 0.2.1** Backend API service for controlling and monitoring Rion NL-43/NL-53 Sound Level Meters via TCP and FTP protocols. ## Overview SLMM is a standalone backend module that provides REST API routing and command translation for NL43/NL53 sound level meters. This service acts as a bridge between the hardware devices and frontend applications, handling all device communication, data persistence, and protocol management. **Note:** This is a backend-only service. Actual user interfacing is done via customized front ends or cli. ## Features - **Background Polling** ⭐ NEW: Continuous automatic polling of devices with configurable intervals - **Offline Detection** ⭐ NEW: Automatic device reachability tracking with failure counters - **Device Management**: Configure and manage multiple NL43/NL53 devices - **Real-time Monitoring**: Stream live measurement data via WebSocket - **Measurement Control**: Start, stop, pause, resume, and reset measurements - **Data Retrieval**: Access current and historical measurement snapshots - **FTP Integration**: Download measurement files directly from devices - **Device Configuration**: Manage frequency/time weighting, clock sync, and more - **Rate Limiting**: Automatic 1-second delay enforcement between device commands - **Persistent Storage**: SQLite database for device configs and measurement cache ## Architecture ``` ┌─────────────────┐ ┌──────────────────────────────┐ ┌─────────────────┐ │ │◄───────►│ SLMM API │◄───────►│ NL43/NL53 │ │ (Frontend) │ HTTP │ • REST Endpoints │ TCP │ Sound Meters │ └─────────────────┘ │ • WebSocket Streaming │ └─────────────────┘ │ • Background Poller ⭐ NEW │ ▲ └──────────────────────────────┘ │ │ Continuous ▼ Polling ┌──────────────┐ │ │ SQLite DB │◄─────────────────────┘ │ • Config │ │ • Status │ └──────────────┘ ``` ### Background Polling (v0.2.0) SLMM now includes a background polling service that continuously queries devices and updates the status cache: - **Automatic Updates**: Devices are polled at configurable intervals (10-3600 seconds) - **Offline Detection**: Devices marked unreachable after 3 consecutive failures - **Per-Device Configuration**: Each device can have a custom polling interval - **Resource Efficient**: Dynamic sleep intervals and smart scheduling - **Graceful Shutdown**: Background task stops cleanly on service shutdown This makes Terra-View significantly more responsive - status requests return cached data instantly (<100ms) instead of waiting for device queries (1-2 seconds). ## Quick Start ### Prerequisites - Python 3.10+ - pip package manager ### Installation 1. Clone the repository: ```bash git clone cd slmm ``` 2. Install dependencies: ```bash pip install -r requirements.txt ``` ### Running the Server ```bash # Development mode with auto-reload uvicorn app.main:app --reload --port 8100 # Production mode uvicorn app.main:app --host 0.0.0.0 --port 8100 ``` The API will be available at `http://localhost:8100` ### API Documentation Once running, visit: - Swagger UI: `http://localhost:8100/docs` - ReDoc: `http://localhost:8100/redoc` - Health Check: `http://localhost:8100/health` ## Configuration ### Environment Variables - `PORT`: Server port (default: 8100) - `CORS_ORIGINS`: Comma-separated list of allowed origins (default: "*") ### Database The SQLite database is automatically created at [data/slmm.db](data/slmm.db) on first run. ### Logging Logs are written to: - Console output (stdout) - [data/slmm.log](data/slmm.log) file ## API Endpoints ### Device Configuration | Method | Endpoint | Description | |--------|----------|-------------| | GET | `/api/nl43/{unit_id}/config` | Get device configuration | | PUT | `/api/nl43/{unit_id}/config` | Update device configuration | ### Device Status | Method | Endpoint | Description | |--------|----------|-------------| | GET | `/api/nl43/{unit_id}/status` | Get cached measurement snapshot (updated by background poller) | | GET | `/api/nl43/{unit_id}/live` | Request fresh DOD data from device (bypasses cache) | | WS | `/api/nl43/{unit_id}/stream` | WebSocket stream for real-time DRD data | ### Background Polling Configuration ⭐ NEW | Method | Endpoint | Description | |--------|----------|-------------| | GET | `/api/nl43/{unit_id}/polling/config` | Get device polling configuration | | PUT | `/api/nl43/{unit_id}/polling/config` | Update polling interval and enable/disable polling | | GET | `/api/nl43/_polling/status` | Get global polling status for all devices | ### Measurement Control | Method | Endpoint | Description | |--------|----------|-------------| | POST | `/api/nl43/{unit_id}/start` | Start measurement | | POST | `/api/nl43/{unit_id}/stop` | Stop measurement | | POST | `/api/nl43/{unit_id}/pause` | Pause measurement | | POST | `/api/nl43/{unit_id}/resume` | Resume paused measurement | | POST | `/api/nl43/{unit_id}/reset` | Reset measurement data | | POST | `/api/nl43/{unit_id}/store` | Manually store data to SD card | ### Device Information | Method | Endpoint | Description | |--------|----------|-------------| | GET | `/api/nl43/{unit_id}/battery` | Get battery level | | GET | `/api/nl43/{unit_id}/clock` | Get device clock time | | PUT | `/api/nl43/{unit_id}/clock` | Set device clock time | | GET | `/api/nl43/{unit_id}/results` | Get final calculation results (DLC) | ### Measurement Settings | Method | Endpoint | Description | |--------|----------|-------------| | GET | `/api/nl43/{unit_id}/settings` | Get all current device settings for verification | | GET | `/api/nl43/{unit_id}/frequency-weighting` | Get frequency weighting (A/C/Z) | | PUT | `/api/nl43/{unit_id}/frequency-weighting` | Set frequency weighting | | GET | `/api/nl43/{unit_id}/time-weighting` | Get time weighting (F/S/I) | | PUT | `/api/nl43/{unit_id}/time-weighting` | Set time weighting | ### Sleep Mode | Method | Endpoint | Description | |--------|----------|-------------| | POST | `/api/nl43/{unit_id}/sleep` | Put device into sleep mode | | POST | `/api/nl43/{unit_id}/wake` | Wake device from sleep | | GET | `/api/nl43/{unit_id}/sleep/status` | Get sleep mode status | ### FTP File Management | Method | Endpoint | Description | |--------|----------|-------------| | POST | `/api/nl43/{unit_id}/ftp/enable` | Enable FTP server on device | | POST | `/api/nl43/{unit_id}/ftp/disable` | Disable FTP server on device | | GET | `/api/nl43/{unit_id}/ftp/status` | Get FTP server status | | GET | `/api/nl43/{unit_id}/ftp/files` | List files on device | | POST | `/api/nl43/{unit_id}/ftp/download` | Download file from device | For detailed API documentation and examples, see [API.md](API.md). ## Project Structure ``` slmm/ ├── app/ │ ├── __init__.py # Package initialization │ ├── main.py # FastAPI application and startup │ ├── routers.py # API route definitions │ ├── models.py # SQLAlchemy database models │ ├── services.py # NL43Client and business logic │ ├── background_poller.py # Background polling service ⭐ NEW │ └── database.py # Database configuration ├── data/ │ ├── slmm.db # SQLite database (auto-created) │ ├── slmm.log # Application logs │ └── downloads/ # Downloaded files from devices ├── templates/ │ └── index.html # Simple web interface (optional) ├── manuals/ # Device documentation ├── migrate_add_polling_fields.py # Database migration for v0.2.0 ⭐ NEW ├── test_polling.sh # Polling feature test script ⭐ NEW ├── API.md # Detailed API documentation ├── COMMUNICATION_GUIDE.md # NL43 protocol documentation ├── NL43_COMMANDS.md # Command reference ├── CHANGELOG.md # Version history ⭐ NEW ├── requirements.txt # Python dependencies └── README.md # This file ``` ## Database Schema ### NL43Config Table Stores device connection configuration: - `unit_id` (PK): Unique device identifier - `host`: Device IP address or hostname - `tcp_port`: TCP control port (default: 80) - `tcp_enabled`: Enable/disable TCP communication - `ftp_enabled`: Enable/disable FTP functionality - `ftp_username`: FTP authentication username - `ftp_password`: FTP authentication password - `web_enabled`: Enable/disable web interface access - `poll_interval_seconds`: Polling interval in seconds (10-3600, default: 60) ⭐ NEW - `poll_enabled`: Enable/disable background polling for this device ⭐ NEW ### NL43Status Table Caches latest measurement snapshot: - `unit_id` (PK): Unique device identifier - `last_seen`: Timestamp of last update - `measurement_state`: Current state (Measure/Stop) - `measurement_start_time`: When measurement started (UTC) - `counter`: Measurement interval counter (1-600) - `lp`: Instantaneous sound pressure level - `leq`: Equivalent continuous sound level - `lmax`: Maximum sound level - `lmin`: Minimum sound level - `lpeak`: Peak sound level - `battery_level`: Battery percentage - `power_source`: Current power source - `sd_remaining_mb`: Free SD card space (MB) - `sd_free_ratio`: SD card free space ratio - `raw_payload`: Raw device response data - `is_reachable`: Device reachability status (Boolean) ⭐ NEW - `consecutive_failures`: Count of consecutive poll failures ⭐ NEW - `last_poll_attempt`: Last time background poller attempted to poll ⭐ NEW - `last_success`: Last successful poll timestamp ⭐ NEW - `last_error`: Last error message (truncated to 500 chars) ⭐ NEW ## Protocol Details ### TCP Communication - Uses ASCII command protocol over TCP - Enforces ≥1 second delay between commands to same device - Two-line response format: - Line 1: Result code (R+0000 for success) - Line 2: Data payload (for query commands) ### FTP Communication - Uses active mode FTP (requires device to connect back) - TCP and FTP are mutually exclusive on the device - Credentials configurable per device - **Default NL43 FTP Credentials**: Username: `USER`, Password: `0000` ### Data Formats **DOD (Data Output Display)**: Snapshot of current display values **DRD (Data Real-time Display)**: Continuous streaming data **DLC (Data Last Calculation)**: Final stored measurement results ## Example Usage ### Configure a Device ```bash curl -X PUT http://localhost:8100/api/nl43/meter-001/config \ -H "Content-Type: application/json" \ -d '{ "host": "192.168.1.100", "tcp_port": 2255, "tcp_enabled": true, "ftp_enabled": true, "ftp_username": "USER", "ftp_password": "0000" }' ``` ### Start Measurement ```bash curl -X POST http://localhost:8100/api/nl43/meter-001/start ``` ### Get Cached Status (Fast - from background poller) ```bash curl http://localhost:8100/api/nl43/meter-001/status ``` ### Get Live Status (Bypasses cache) ```bash curl http://localhost:8100/api/nl43/meter-001/live ``` ### Configure Background Polling ⭐ NEW ```bash # Set polling interval to 30 seconds curl -X PUT http://localhost:8100/api/nl43/meter-001/polling/config \ -H "Content-Type: application/json" \ -d '{ "poll_interval_seconds": 30, "poll_enabled": true }' # Get polling configuration curl http://localhost:8100/api/nl43/meter-001/polling/config # Check global polling status curl http://localhost:8100/api/nl43/_polling/status ``` ### Verify Device Settings ```bash curl http://localhost:8100/api/nl43/meter-001/settings ``` This returns all current device configuration: ```json { "status": "ok", "unit_id": "meter-001", "settings": { "measurement_state": "Stop", "frequency_weighting": "A", "time_weighting": "F", "measurement_time": "00:01:00", "leq_interval": "1s", "lp_interval": "125ms", "index_number": "0", "battery_level": "100%", "clock": "2025/12/24,20:45:30", "sleep_mode": "Off", "ftp_status": "On" } } ``` ### Stream Real-time Data (JavaScript) ```javascript const ws = new WebSocket('ws://localhost:8100/api/nl43/meter-001/stream'); ws.onmessage = (event) => { const data = JSON.parse(event.data); console.log('Live measurement:', data); }; ``` ### Download Files via FTP ```bash # Enable FTP curl -X POST http://localhost:8100/api/nl43/meter-001/ftp/enable # List files curl http://localhost:8100/api/nl43/meter-001/ftp/files?path=/NL43_DATA # Download file curl -X POST http://localhost:8100/api/nl43/meter-001/ftp/download \ -H "Content-Type: application/json" \ -d '{"remote_path": "/NL43_DATA/measurement.wav"}' \ --output measurement.wav # Disable FTP curl -X POST http://localhost:8100/api/nl43/meter-001/ftp/disable ``` ## Integration with Terra-View This backend is designed to be consumed by the Terra-View frontend application. The frontend should: 1. Use the config endpoints to register and configure devices 2. Poll or stream live status for real-time monitoring 3. Use control endpoints to manage measurements 4. Download files via FTP endpoints for analysis See [API.md](API.md) for detailed integration examples. ## Troubleshooting ### Connection Issues - Verify device IP address and port in configuration - Ensure device is on the same network - Check firewall rules allow TCP/FTP connections - Verify RX55 network adapter is properly configured on device ### Rate Limiting - API automatically enforces 1-second delay between commands - If experiencing delays, this is normal device behavior - Multiple devices can be controlled in parallel ### FTP Active Mode - Ensure server can accept incoming connections from device - FTP uses active mode (device connects back to server) - May require firewall configuration for data channel ### WebSocket Disconnects - WebSocket streams maintain persistent connection - Limit concurrent streams to avoid device overload - Connection will auto-close if device stops responding ## Development ### Running Tests ```bash # Add test commands when implemented pytest ``` ### Database Migrations ```bash # Migrate to v0.2.0 (add background polling fields) python3 migrate_add_polling_fields.py # Legacy: Migrate to add FTP credentials python migrate_add_ftp_credentials.py # Set FTP credentials for a device python set_ftp_credentials.py ``` ### Testing Background Polling ```bash # Run comprehensive polling tests ./test_polling.sh [unit_id] # Test settings endpoint python3 test_settings_endpoint.py # Test sleep mode auto-disable python3 test_sleep_mode_auto_disable.py ``` ### Legacy Scripts Old migration scripts and manual polling tools have been moved to `archive/` for reference. See [archive/README.md](archive/README.md) for details. ## Contributing This is a standalone module kept separate from the SFM/Terra-View codebase. When contributing: 1. Maintain separation from frontend code 2. Follow existing API patterns and error handling 3. Update API documentation for new endpoints 4. Ensure rate limiting is enforced for device commands ## License [Specify license here] ## Related Documentation - [API.md](API.md) - Complete API reference with examples - [COMMUNICATION_GUIDE.md](COMMUNICATION_GUIDE.md) - NL43 protocol details - [NL43_COMMANDS.md](NL43_COMMANDS.md) - Device command reference - [manuals/](manuals/) - Device manufacturer documentation ## Support For issues and questions: - Backend API issues: This repository - Frontend/UI issues: Terra-View repository - Device protocol questions: See COMMUNICATION_GUIDE.md