The device registry is the core of WAVE Synapse. Every piece of equipment in your facility, from a USB webcam to a cloud-based Zoom participant, is represented as a normalized device record with a consistent set of fields.
Synapse supports 18 device classes organized into six categories:
| Class | Description | Typical Discovery |
|---|---|---|
usb_input | USB-connected cameras, capture cards, microphones | usb_enumeration |
broadcast_hardware | SDI routers, frame synchronizers, signal processors | manual or network_scan |
ptz_camera | Pan-tilt-zoom cameras with remote control | mdns or network_scan |
atem_switcher | Blackmagic ATEM production switchers | mdns or manual |
| Class | Description | Typical Discovery |
|---|---|---|
desktop_node | WAVE Desktop application instances | heartbeat_registration or qr_code |
byod_source | Bring-your-own-device browser sources | heartbeat_registration |
cloud_device | Generic cloud-hosted processing nodes | manual |
| Class | Description | Typical Discovery |
|---|---|---|
ndi_source | NDI-enabled video sources and receivers | mdns |
dante_device | Dante/AES67 audio endpoints | dante_discovery |
generic_ip | IP-addressable devices not covered by other classes | network_scan |
| Class | Description | Typical Discovery |
|---|---|---|
encoder | Hardware or software encoders (SRT, RTMP, HLS) | network_scan |
decoder | Hardware or software decoders | network_scan |
ingress_endpoint | Cloud ingress points for external contribution feeds | manual |
| Class | Description | Typical Discovery |
|---|---|---|
livekit_participant | LiveKit room participants | livekit_room |
zoom_participant | Zoom meeting participants (individuals) | zoom_bridge |
zoom_room | Zoom Rooms appliances | zoom_bridge |
| Class | Description | Typical Discovery |
|---|---|---|
fleet_endpoint | Fleet-managed remote devices | heartbeat_registration |
signage_display | Digital signage screens and players | network_scan |
Devices enter the registry through two paths:
The discovery engine scans the network and registers devices automatically. Auto-discovered devices have auto_discovered: true and require approval before they can participate in routing. See Discovery Engine for details.
Register a device directly via the API:
const response = await fetch('/api/ncp/devices', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${accessToken}`,
},
body: JSON.stringify({
display_name: 'Studio A - Camera 1',
device_class: 'ptz_camera',
ip_address: '10.0.1.50',
mac_address: '00:1A:2B:3C:4D:5E',
hostname: 'cam1.studio-a.local',
capabilities: {
video_input: true,
ptz: true,
tally: true,
protocols: ['ndi', 'srt'],
max_resolution: '3840x2160',
},
site_id: 'site-uuid',
physical_location: 'Studio A, Camera Position 1',
failover_mode: 'automatic',
backup_device_id: 'backup-cam-uuid',
}),
});
Manually registered devices are approved by default (approved: true).
Auto-discovered devices follow this lifecycle:
Approve a device by calling the approval endpoint:
await fetch(`/api/ncp/devices/${deviceId}/approve`, {
method: 'POST',
headers: { 'Authorization': `Bearer ${accessToken}` },
});
Every device has a health_score from 0 to 100, computed from:
| Factor | Weight | Source |
|---|---|---|
| Heartbeat recency | 30% | Time since last_heartbeat_at |
| Connection stability | 25% | Consecutive heartbeats without interruption |
| Resource usage | 25% | CPU, memory, disk from heartbeat metrics |
| Network quality | 20% | Latency, packet loss, jitter from active routes |
| Range | Status | Meaning |
|---|---|---|
| 80-100 | Healthy | Device operating normally |
| 50-79 | Degraded | Performance issues detected; investigate |
| 20-49 | Critical | Significant problems; may affect production |
| 0-19 | Failing | Device is non-functional or unreachable |
Every change in health status is recorded as a HealthEvent in the partitioned ncp_device_health_events table. Event types include:
heartbeat - Regular heartbeat receivedstatus_change - Device status transitioned (e.g., online to offline)health_score_change - Score changed beyond thresholdalert_triggered - Alert condition metconfig_change - Device configuration modifiedfirmware_update - Firmware version changederror - Error condition recordedDevices are never hard-deleted. The DELETE /api/ncp/devices/{id} endpoint performs a soft delete by setting deleted_at and deleted_by. Soft-deleted devices are excluded from listings by default but can be included by passing include_deleted=true.
// Soft delete (decommission) a device
await fetch(`/api/ncp/devices/${deviceId}`, {
method: 'DELETE',
headers: { 'Authorization': `Bearer ${accessToken}` },
});
// List including decommissioned devices
const response = await fetch('/api/ncp/devices?include_deleted=true', {
headers: { 'Authorization': `Bearer ${accessToken}` },
});
Pair a device with a backup for automatic or manual failover:
await fetch(`/api/ncp/devices/${deviceId}`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${accessToken}`,
},
body: JSON.stringify({
backup_device_id: 'backup-device-uuid',
failover_mode: 'automatic',
}),
});
| Failover Mode | Behavior |
|---|---|
none | No failover configured |
manual | Alert is raised; operator must switch manually |
automatic | Synapse reroutes signals to backup when health drops below threshold |
The device-failover-handler Inngest function monitors health scores and triggers automatic failover when configured.
The capabilities JSON object describes what a device can do:
interface DeviceCapabilities {
video_input?: boolean; // Can send video
video_output?: boolean; // Can receive/display video
audio_input?: boolean; // Can send audio
audio_output?: boolean; // Can receive/play audio
ptz?: boolean; // Supports pan-tilt-zoom control
tally?: boolean; // Supports tally light state
recording?: boolean; // Can record locally
protocols?: string[]; // Supported protocols (e.g., ['ndi', 'srt'])
max_resolution?: string; // Maximum supported resolution
audio_channels?: number; // Number of audio channels
supported_codecs?: string[]; // Supported codecs
ndi_version?: string; // NDI SDK version (NDI devices)
dante_channels?: number; // Dante channel count (Dante devices)
atem_inputs?: number; // Input count (ATEM switchers)
atem_outputs?: number; // Output count (ATEM switchers)
}
Capabilities are populated during discovery and can be updated manually via PATCH /api/ncp/devices/{id}.