The Heimdall SDR API provides comprehensive access to radio signal data, anomaly detection results, and system management capabilities. The API follows RESTful principles and includes real-time WebSocket endpoints for live data streaming.
Production: https://api.heimdall.example.com
Development: http://localhost:8000
All API endpoints require authentication via JWT Bearer tokens, except for the health check endpoint.
Authorization: Bearer <jwt_token>
POST /api/v1/auth/login
Content-Type: application/json
{
"username": "user@example.com",
"password": "secure_password"
}
Response:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer",
"expires_in": 3600,
"permissions": ["signals:read", "signals:write"],
"user_id": "550e8400-e29b-41d4-a716-446655440000"
}
POST /api/v1/auth/refresh
Content-Type: application/json
{
"refresh_token": "refresh_token_string"
}
The API uses URL path versioning:
v1Rate limit headers:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1640995200
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"websdr_station_id": "twente-nl",
"frequency_hz": 14235000,
"signal_strength_db": -73.5,
"bandwidth_hz": 2400,
"modulation_type": "USB",
"signal_features": {
"spectral_centroid": 1500.0,
"bandwidth": 2400,
"snr_estimate": 15.3,
"peak_frequency": 14235000
},
"anomaly_score": 0.15,
"is_anomaly": false,
"detection_timestamp": "2024-01-15T14:30:00Z",
"processing_metadata": {
"processing_time_ms": 125,
"model_version": "1.2.0",
"quality_score": 0.89
},
"created_at": "2024-01-15T14:30:05Z",
"updated_at": "2024-01-15T14:30:05Z"
}
{
"id": "twente-nl",
"name": "University of Twente WebSDR",
"url": "http://websdr.ewi.utwente.nl:8901/",
"location": "Enschede, Netherlands",
"latitude": 52.2387,
"longitude": 6.8509,
"frequency_min": 0,
"frequency_max": 29000000,
"status": "active",
"api_config": {
"api_type": "http_streaming",
"poll_interval": 1.0,
"timeout": 30
},
"last_seen": "2024-01-15T14:30:00Z",
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-15T14:30:00Z"
}
{
"id": "550e8400-e29b-41d4-a716-446655440001",
"detection_id": "550e8400-e29b-41d4-a716-446655440000",
"event_type": "unusual_signal_pattern",
"severity": "medium",
"description": "Detected unusual modulation pattern on 14.235 MHz",
"metadata": {
"confidence": 0.87,
"affected_frequencies": [14235000, 14236000],
"duration_seconds": 15.6,
"geographic_correlation": ["twente-nl", "hackgreen-uk"]
},
"acknowledged": false,
"acknowledged_by": null,
"acknowledged_at": null,
"created_at": "2024-01-15T14:30:10Z"
}
Check API service health status.
Response:
{
"status": "healthy",
"timestamp": "2024-01-15T14:30:00Z",
"version": "1.0.0",
"services": {
"database": "healthy",
"redis": "healthy",
"rabbitmq": "healthy",
"websdr_collectors": "healthy"
}
}
Retrieve signal detections with filtering and pagination.
Parameters:
frequency_min (integer, required): Minimum frequency in Hzfrequency_max (integer, required): Maximum frequency in Hztime_start (string, required): Start time in ISO 8601 formattime_end (string, required): End time in ISO 8601 formatwebsdr_station (string, optional): Filter by station IDanomaly_threshold (float, optional): Minimum anomaly score (0.0-1.0)modulation_type (string, optional): Filter by modulation typepage (integer, optional, default=1): Page numberpage_size (integer, optional, default=100): Items per page (max 1000)sort_by (string, optional, default=”detection_timestamp”): Sort fieldsort_order (string, optional, default=”desc”): Sort order (asc/desc)Example Request:
GET /api/v1/signals/detections?frequency_min=14000000&frequency_max=15000000&time_start=2024-01-15T12:00:00Z&time_end=2024-01-15T18:00:00Z&websdr_station=twente-nl&page=1&page_size=50
Response:
{
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"websdr_station_id": "twente-nl",
"frequency_hz": 14235000,
"signal_strength_db": -73.5,
"bandwidth_hz": 2400,
"modulation_type": "USB",
"anomaly_score": 0.15,
"is_anomaly": false,
"detection_timestamp": "2024-01-15T14:30:00Z"
}
],
"pagination": {
"page": 1,
"page_size": 50,
"total_items": 1247,
"total_pages": 25,
"has_next": true,
"has_previous": false
},
"filters_applied": {
"frequency_range": [14000000, 15000000],
"time_range": ["2024-01-15T12:00:00Z", "2024-01-15T18:00:00Z"],
"station": "twente-nl"
}
}
Retrieve a specific signal detection by ID.
Response:
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"websdr_station_id": "twente-nl",
"frequency_hz": 14235000,
"signal_strength_db": -73.5,
"bandwidth_hz": 2400,
"modulation_type": "USB",
"signal_features": {
"spectral_centroid": 1500.0,
"bandwidth": 2400,
"snr_estimate": 15.3,
"peak_frequency": 14235000
},
"anomaly_score": 0.15,
"is_anomaly": false,
"detection_timestamp": "2024-01-15T14:30:00Z",
"processing_metadata": {
"processing_time_ms": 125,
"model_version": "1.2.0",
"quality_score": 0.89
},
"created_at": "2024-01-15T14:30:05Z",
"updated_at": "2024-01-15T14:30:05Z"
}
Analyze uploaded signal data for anomalies.
Request Body:
{
"signal_data": {
"samples": [0.1, 0.2, -0.1, 0.3],
"sample_rate": 48000,
"frequency": 14235000,
"duration": 1.0
},
"analysis_config": {
"fft_size": 1024,
"overlap": 0.5,
"window_function": "hamming"
}
}
Response:
{
"analysis_id": "550e8400-e29b-41d4-a716-446655440002",
"signal_features": {
"spectral_centroid": 1500.0,
"bandwidth": 2400,
"snr_estimate": 15.3,
"peak_frequency": 14235000
},
"anomaly_score": 0.15,
"is_anomaly": false,
"confidence": 0.92,
"processing_time_ms": 125,
"model_version": "1.2.0"
}
Retrieve list of WebSDR stations.
Parameters:
status (string, optional): Filter by status (active/inactive/maintenance)location (string, optional): Filter by location/countryfrequency_range (string, optional): Filter by frequency coverageResponse:
{
"data": [
{
"id": "twente-nl",
"name": "University of Twente WebSDR",
"url": "http://websdr.ewi.utwente.nl:8901/",
"location": "Enschede, Netherlands",
"latitude": 52.2387,
"longitude": 6.8509,
"frequency_min": 0,
"frequency_max": 29000000,
"status": "active",
"last_seen": "2024-01-15T14:30:00Z"
}
],
"total_count": 7,
"active_count": 6,
"inactive_count": 1
}
Retrieve detailed information about a specific WebSDR station.
Response:
{
"id": "twente-nl",
"name": "University of Twente WebSDR",
"url": "http://websdr.ewi.utwente.nl:8901/",
"location": "Enschede, Netherlands",
"latitude": 52.2387,
"longitude": 6.8509,
"frequency_min": 0,
"frequency_max": 29000000,
"status": "active",
"api_config": {
"api_type": "http_streaming",
"poll_interval": 1.0,
"timeout": 30
},
"statistics": {
"uptime_percentage": 98.5,
"average_response_time_ms": 150,
"total_detections_24h": 15423,
"anomalies_detected_24h": 12
},
"last_seen": "2024-01-15T14:30:00Z",
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-15T14:30:00Z"
}
Get real-time status of a WebSDR station.
Response:
{
"station_id": "twente-nl",
"status": "active",
"connection_status": "connected",
"last_data_received": "2024-01-15T14:30:00Z",
"response_time_ms": 145,
"current_listeners": 23,
"signal_quality": 0.92,
"frequency_coverage": {
"current_frequency": 14235000,
"active_bands": ["20m", "40m", "80m"]
}
}
Constellations are logical groupings of WebSDR stations used for radio source localization. They enable resource organization, access control, and collaboration through sharing.
Authentication: All constellation endpoints require JWT authentication.
Authorization: See RBAC documentation for detailed permission requirements.
Retrieve list of constellations accessible to the authenticated user.
Parameters:
skip (integer, optional, default=0): Pagination offsetlimit (integer, optional, default=100, max=1000): Number of resultsAuthorization:
Example Request:
GET /api/v1/constellations?skip=0&limit=50
Authorization: Bearer <jwt_token>
Response: 200 OK
{
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Northern Italy Coverage",
"description": "Stations covering northern Italy for VHF monitoring",
"owner_id": "user-123",
"created_at": "2025-01-15T10:30:00Z",
"updated_at": "2025-01-15T10:30:00Z",
"member_count": 5,
"permission": "edit"
},
{
"id": "550e8400-e29b-41d4-a716-446655440001",
"name": "Team Alpha Network",
"description": "Shared constellation for Team Alpha",
"owner_id": "user-456",
"created_at": "2025-01-10T08:00:00Z",
"updated_at": "2025-01-16T12:00:00Z",
"member_count": 3,
"permission": "read"
}
],
"pagination": {
"skip": 0,
"limit": 50,
"total": 2
}
}
Fields:
permission: User’s permission level
null: User is the owner"read": Shared with read-only access"edit": Shared with edit accessCreate a new constellation.
Requirements: OPERATOR or ADMIN role
Request Body:
{
"name": "Northern Italy Coverage",
"description": "Stations covering northern Italy for VHF monitoring"
}
Validation:
name: Required, 1-255 characters, must be unique per userdescription: Optional, max 2000 charactersResponse: 201 Created
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Northern Italy Coverage",
"description": "Stations covering northern Italy for VHF monitoring",
"owner_id": "user-123",
"created_at": "2025-01-15T10:30:00Z",
"updated_at": "2025-01-15T10:30:00Z"
}
Error Responses:
401 Unauthorized: Authentication required403 Forbidden: Insufficient role (USER cannot create constellations)422 Unprocessable Entity: Validation errorRetrieve detailed information about a specific constellation, including all member WebSDR stations.
Requirements: Owner, shared user, or admin
Response: 200 OK
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Northern Italy Coverage",
"description": "Stations covering northern Italy for VHF monitoring",
"owner_id": "user-123",
"created_at": "2025-01-15T10:30:00Z",
"updated_at": "2025-01-15T10:30:00Z",
"permission": "edit",
"members": [
{
"id": "member-001",
"websdr_station_id": "rome-it",
"websdr_station": {
"id": "rome-it",
"name": "Rome WebSDR",
"location": "Rome, Italy",
"latitude": 41.9028,
"longitude": 12.4964,
"status": "active"
},
"added_at": "2025-01-15T10:35:00Z",
"added_by": "user-123"
},
{
"id": "member-002",
"websdr_station_id": "milan-it",
"websdr_station": {
"id": "milan-it",
"name": "Milan WebSDR",
"location": "Milan, Italy",
"latitude": 45.4642,
"longitude": 9.1900,
"status": "active"
},
"added_at": "2025-01-15T11:00:00Z",
"added_by": "user-123"
}
]
}
Error Responses:
403 Forbidden: No permission to view this constellation404 Not Found: Constellation does not existUpdate constellation name or description.
Requirements: Owner, shared with ‘edit’ permission, or admin
Request Body:
{
"name": "Updated Northern Italy Coverage",
"description": "Updated description with more details"
}
Validation:
name: Optional, 1-255 charactersdescription: Optional, max 2000 charactersResponse: 200 OK
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Updated Northern Italy Coverage",
"description": "Updated description with more details",
"owner_id": "user-123",
"created_at": "2025-01-15T10:30:00Z",
"updated_at": "2025-01-16T14:20:00Z"
}
Error Responses:
403 Forbidden: No edit permission404 Not Found: Constellation does not exist422 Unprocessable Entity: Validation errorDelete a constellation.
Requirements: Owner or admin only
Response: 204 No Content
Side Effects:
Error Responses:
403 Forbidden: Not owner or admin404 Not Found: Constellation does not existAdd a WebSDR station to a constellation.
Requirements: Owner, shared with ‘edit’ permission, or admin
Request Body:
{
"websdr_station_id": "rome-it"
}
Response: 201 Created
{
"id": "member-003",
"constellation_id": "550e8400-e29b-41d4-a716-446655440000",
"websdr_station_id": "rome-it",
"added_at": "2025-01-16T15:00:00Z",
"added_by": "user-123"
}
Error Responses:
403 Forbidden: No edit permission404 Not Found: Constellation or WebSDR station does not exist409 Conflict: WebSDR station already in this constellationRemove a WebSDR station from a constellation.
Requirements: Owner, shared with ‘edit’ permission, or admin
Response: 204 No Content
Error Responses:
403 Forbidden: No edit permission404 Not Found: Constellation, WebSDR, or membership does not existOwners can share their constellations with other users by assigning read or edit permissions.
List all users who have been granted access to a constellation.
Requirements: Owner or admin only
Response: 200 OK
{
"data": [
{
"id": "share-001",
"constellation_id": "550e8400-e29b-41d4-a716-446655440000",
"user_id": "user-456",
"permission": "edit",
"shared_by": "user-123",
"shared_at": "2025-01-15T12:00:00Z",
"user_info": {
"email": "alice@example.com",
"username": "alice",
"display_name": "Alice Johnson"
}
},
{
"id": "share-002",
"constellation_id": "550e8400-e29b-41d4-a716-446655440000",
"user_id": "user-789",
"permission": "read",
"shared_by": "user-123",
"shared_at": "2025-01-15T12:30:00Z",
"user_info": {
"email": "bob@example.com",
"username": "bob",
"display_name": "Bob Smith"
}
}
],
"total": 2
}
Error Responses:
403 Forbidden: Not owner or admin404 Not Found: Constellation does not existShare a constellation with another user.
Requirements: Owner or admin only
Request Body:
{
"user_id": "user-456",
"permission": "edit"
}
Validation:
user_id: Required, must be a valid Keycloak user IDpermission: Required, must be "read" or "edit"Permission Levels:
read: User can view the constellation and use it in localization sessionsedit: User can view, modify (name/description), and manage WebSDR membersResponse: 201 Created
{
"id": "share-001",
"constellation_id": "550e8400-e29b-41d4-a716-446655440000",
"user_id": "user-456",
"permission": "edit",
"shared_by": "user-123",
"shared_at": "2025-01-15T12:00:00Z"
}
Error Responses:
403 Forbidden: Not owner or admin404 Not Found: Constellation or user does not exist409 Conflict: Share already exists for this user422 Unprocessable Entity: Invalid permission levelUpdate the permission level for an existing share.
Requirements: Owner or admin only
Request Body:
{
"permission": "read"
}
Response: 200 OK
{
"id": "share-001",
"constellation_id": "550e8400-e29b-41d4-a716-446655440000",
"user_id": "user-456",
"permission": "read",
"shared_by": "user-123",
"shared_at": "2025-01-15T12:00:00Z",
"updated_at": "2025-01-16T10:00:00Z"
}
Error Responses:
403 Forbidden: Not owner or admin404 Not Found: Constellation or share does not exist422 Unprocessable Entity: Invalid permission levelRevoke a user’s access to a constellation.
Requirements: Owner or admin only
Response: 204 No Content
Error Responses:
403 Forbidden: Not owner or admin404 Not Found: Constellation or share does not existRetrieve anomaly events with filtering.
Parameters:
severity (string, optional): Filter by severity (low/medium/high/critical)event_type (string, optional): Filter by event typetime_start (string, required): Start time in ISO 8601 formattime_end (string, required): End time in ISO 8601 formatacknowledged (boolean, optional): Filter by acknowledgment statusstation_id (string, optional): Filter by WebSDR stationpage (integer, optional, default=1): Page numberpage_size (integer, optional, default=50): Items per pageResponse:
{
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440001",
"detection_id": "550e8400-e29b-41d4-a716-446655440000",
"event_type": "unusual_signal_pattern",
"severity": "medium",
"description": "Detected unusual modulation pattern on 14.235 MHz",
"acknowledged": false,
"created_at": "2024-01-15T14:30:10Z"
}
],
"pagination": {
"page": 1,
"page_size": 50,
"total_items": 234,
"total_pages": 5
},
"summary": {
"total_anomalies": 234,
"by_severity": {
"critical": 2,
"high": 15,
"medium": 67,
"low": 150
},
"acknowledged_count": 189,
"unacknowledged_count": 45
}
}
Acknowledge an anomaly event.
Request Body:
{
"notes": "Investigated - confirmed false positive due to equipment test"
}
Response:
{
"id": "550e8400-e29b-41d4-a716-446655440001",
"acknowledged": true,
"acknowledged_by": "550e8400-e29b-41d4-a716-446655440003",
"acknowledged_at": "2024-01-15T14:35:00Z",
"notes": "Investigated - confirmed false positive due to equipment test"
}
Get overall system statistics.
Parameters:
time_period (string, optional, default=”24h”): Time period (1h/6h/24h/7d/30d)Response:
{
"time_period": "24h",
"generated_at": "2024-01-15T14:30:00Z",
"signal_detections": {
"total": 125430,
"by_station": {
"twente-nl": 18456,
"hackgreen-uk": 15234,
"bratislava-sk": 12987
},
"by_frequency_band": {
"hf": 89234,
"vhf": 23456,
"uhf": 12740
}
},
"anomalies": {
"total": 156,
"by_severity": {
"critical": 2,
"high": 15,
"medium": 67,
"low": 72
},
"detection_rate": 0.0012
},
"system_health": {
"uptime_percentage": 99.8,
"average_processing_time_ms": 125,
"active_stations": 6,
"total_stations": 7
}
}
Get frequency usage statistics.
Parameters:
frequency_min (integer, optional): Minimum frequency in Hzfrequency_max (integer, optional): Maximum frequency in Hztime_period (string, optional, default=”24h”): Time periodgranularity (string, optional, default=”1h”): Data granularity (5m/15m/1h/6h)Response:
{
"frequency_range": [14000000, 15000000],
"time_period": "24h",
"granularity": "1h",
"data": [
{
"timestamp": "2024-01-15T13:00:00Z",
"frequency_bins": [
{
"frequency_start": 14000000,
"frequency_end": 14100000,
"signal_count": 234,
"average_strength": -75.2,
"anomaly_count": 2
}
]
}
],
"popular_frequencies": [
{
"frequency": 14235000,
"signal_count": 1456,
"percentage": 12.5
}
]
}
Retrieve information about ML models.
Response:
{
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440004",
"name": "isolation-forest-v1",
"version": "1.2.0",
"model_type": "anomaly_detection",
"status": "deployed",
"metrics": {
"accuracy": 0.94,
"precision": 0.89,
"recall": 0.92,
"f1_score": 0.90
},
"deployment_date": "2024-01-10T10:00:00Z",
"last_training_date": "2024-01-08T15:30:00Z"
}
]
}
Make predictions using a specific model.
Request Body:
{
"features": {
"spectral_centroid": 1500.0,
"bandwidth": 2400,
"snr_estimate": 15.3,
"signal_power": -65.2
}
}
Response:
{
"model_id": "550e8400-e29b-41d4-a716-446655440004",
"prediction": {
"anomaly_score": 0.15,
"is_anomaly": false,
"confidence": 0.92
},
"processing_time_ms": 45,
"timestamp": "2024-01-15T14:30:00Z"
}
Connect to the WebSocket endpoint for real-time data streaming:
const ws = new WebSocket('ws://localhost:8000/ws/signals/live?token=jwt_token');
Subscribe to real-time signal detections:
// Send subscription message
ws.send(JSON.stringify({
type: 'subscribe',
channels: ['signal_detections'],
filters: {
station_ids: ['twente-nl', 'hackgreen-uk'],
frequency_range: [14000000, 15000000],
anomaly_threshold: 0.5
}
}));
// Receive real-time data
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log('Signal detection:', data);
};
Message Format:
{
"type": "signal_detection",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"websdr_station_id": "twente-nl",
"frequency_hz": 14235000,
"signal_strength_db": -73.5,
"anomaly_score": 0.15,
"detection_timestamp": "2024-01-15T14:30:00Z"
},
"timestamp": "2024-01-15T14:30:05Z"
}
Subscribe to real-time anomaly notifications:
// Subscribe to anomaly alerts
ws.send(JSON.stringify({
type: 'subscribe',
channels: ['anomaly_alerts'],
filters: {
severity: ['medium', 'high', 'critical'],
stations: ['twente-nl']
}
}));
Message Format:
{
"type": "anomaly_alert",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440001",
"event_type": "unusual_signal_pattern",
"severity": "high",
"frequency_hz": 14235000,
"station_id": "twente-nl",
"description": "Detected unusual modulation pattern",
"anomaly_score": 0.87,
"created_at": "2024-01-15T14:30:10Z"
},
"timestamp": "2024-01-15T14:30:10Z"
}
Subscribe to system health updates:
// Subscribe to system status
ws.send(JSON.stringify({
type: 'subscribe',
channels: ['system_status']
}));
Message Format:
{
"type": "system_status",
"data": {
"overall_status": "healthy",
"services": {
"websdr_collectors": "healthy",
"signal_processor": "degraded",
"ml_detector": "healthy"
},
"station_status": {
"twente-nl": "active",
"hackgreen-uk": "active",
"bratislava-sk": "maintenance"
}
},
"timestamp": "2024-01-15T14:30:00Z"
}
All API errors follow a consistent format:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid frequency range specified",
"details": {
"field": "frequency_min",
"value": -1000000,
"constraint": "must be positive"
},
"request_id": "550e8400-e29b-41d4-a716-446655440005",
"timestamp": "2024-01-15T14:30:00Z"
}
}
200 OK: Successful request201 Created: Resource created successfully400 Bad Request: Invalid request parameters401 Unauthorized: Authentication required403 Forbidden: Insufficient permissions404 Not Found: Resource not found409 Conflict: Resource conflict422 Unprocessable Entity: Validation error429 Too Many Requests: Rate limit exceeded500 Internal Server Error: Server error503 Service Unavailable: Service temporarily unavailableAUTHENTICATION_REQUIRED: Valid JWT token requiredINVALID_TOKEN: JWT token is invalid or expiredINSUFFICIENT_PERMISSIONS: User lacks required permissionsVALIDATION_ERROR: Request validation failedRESOURCE_NOT_FOUND: Requested resource does not existRATE_LIMIT_EXCEEDED: API rate limit exceededSERVICE_UNAVAILABLE: External service unavailablePROCESSING_ERROR: Signal processing failedMODEL_ERROR: ML model prediction failedfrom heimdall_sdk import HeimdallClient
# Initialize client
client = HeimdallClient(
base_url="https://api.heimdall.example.com",
api_key="your_api_key"
)
# Get signal detections
detections = await client.signals.get_detections(
frequency_range=(14000000, 15000000),
time_range=("2024-01-15T12:00:00Z", "2024-01-15T18:00:00Z"),
station_id="twente-nl"
)
# Analyze signal data
result = await client.signals.analyze(
signal_data=signal_samples,
sample_rate=48000,
frequency=14235000
)
# Subscribe to live data
async with client.websocket.connect() as ws:
await ws.subscribe_signals(
stations=["twente-nl"],
frequency_range=(14000000, 15000000)
)
async for signal in ws.stream():
print(f"Signal detected: {signal.frequency_hz} Hz")
import { HeimdallClient } from '@heimdall/sdk';
// Initialize client
const client = new HeimdallClient({
baseURL: 'https://api.heimdall.example.com',
apiKey: 'your_api_key'
});
// Get signal detections
const detections = await client.signals.getDetections({
frequencyRange: [14000000, 15000000],
timeRange: ['2024-01-15T12:00:00Z', '2024-01-15T18:00:00Z'],
stationId: 'twente-nl'
});
// Real-time WebSocket connection
const ws = client.websocket.connect();
ws.subscribeSignals({
stations: ['twente-nl'],
frequencyRange: [14000000, 15000000]
});
ws.on('signal_detection', (signal) => {
console.log('Signal detected:', signal);
});
For additional support or feature requests, please visit our GitHub repository or contact the development team.