A modular TypeScript listener for Vital Recorder data with flexible output options including medical monitoring systems.
- 🔌 Socket.IO v4.0.0 server for receiving Vital Recorder data
- 📊 Real-time data processing and transformation
- 🎯 Multiple output targets (Console, API endpoints, JSON files, Telegraf/InfluxDB)
- ⏱️ Millisecond-precision timestamps (ISO format)
- 🔄 Automatic retry logic for API outputs
- 📁 File rotation and size management
- 🏥 Medical system integration via Telegraf → InfluxDB
- 🏥 ICU bed assignment and vital signs mapping
- 📝 Full TypeScript support
- 🚀 Fast, immediate data forwarding
- ✅ Comprehensive test coverage
npm install vital-recorder-listenerimport { VitalRecorderListener } from 'vital-recorder-listener';
const listener = new VitalRecorderListener({
port: 3000,
outputs: [
{
type: 'console',
verbose: true,
colorized: true
}
]
});
await listener.start();In Vital Recorder settings, set:
SERVER_IP=127.0.0.1:3000
{
type: 'console',
verbose?: boolean, // Show detailed output (default: false)
colorized?: boolean // Use colors in output (default: true)
}{
type: 'api',
endpoint: string, // API endpoint URL
headers?: object, // Custom headers
separateRooms?: boolean, // Send each room separately
retryAttempts?: number, // Number of retry attempts (default: 3)
retryDelayMs?: number // Delay between retries (default: 1000)
}{
type: 'file',
filepath: string, // Path to output file
format?: 'json' | 'jsonl', // JSON or JSON Lines format (default: 'json')
prettify?: boolean, // Pretty print JSON (default: false)
rotateSize?: number, // Max file size in MB before rotation
maxFiles?: number, // Max number of rotated files to keep
includeTimestamp?: boolean // Include timestamp in filename
}{
type: 'telegraf',
host: string, // Telegraf host (default: 'localhost')
port: number, // Telegraf HTTP listener port (default: 8094)
endpoint?: string, // HTTP endpoint path (default: '/telegraf')
headers?: object, // Custom HTTP headers
retryAttempts?: number, // Number of retry attempts (default: 3)
retryDelayMs?: number, // Delay between retries (default: 1000)
timeoutMs?: number, // Request timeout (default: 5000)
maxBeds?: number, // Max ICU beds for cycling (default: 20)
assessor?: string // Clinical assessor name (default: 'VitalRecorder')
}The Telegraf output enables integration with medical monitoring systems by converting VitalRecorder data into medical format:
VitalRecorder parameters are automatically mapped to standard vital signs:
HR,PLETH_HR→ Heart RateNIBP_SBP,ART_SBP→ Systolic Blood PressureNIBP_DBP,ART_DBP→ Diastolic Blood PressurePLETH_SPO2,SO2_1,SO2_2→ Oxygen SaturationBT→ Body TemperatureRR,RR_CO2→ Respiratory Rate- Plus many more physiological parameters
Data is automatically assigned to ICU beds (ICU-01, ICU-02, etc.) based on:
- VitalRecorder code numbers
- Room names/numbers
- Timestamp-based cycling
Vital signs data only is sent to InfluxDB via Telegraf:
bed_vitals- Standard vital signs and physiological parameters from VitalRecorder
Note: EMG data and clinical scores (BPS/RASS) are not included in the Telegraf output, as these are expected to be provided to Telegraf separately through other channels.
const listener = new VitalRecorderListener({
port: 3000,
debug: true,
outputs: [
// Send to medical monitoring system
{
type: 'telegraf',
host: 'telegraf-server',
port: 8094,
maxBeds: 20,
assessor: 'ICU_System',
retryAttempts: 5
},
// Local console monitoring
{
type: 'console',
verbose: false,
colorized: true
}
]
});
await listener.start();const listener = new VitalRecorderListener({
port: 3000,
debug: true,
outputs: [
// Console for local monitoring
{
type: 'console',
verbose: false,
colorized: true
},
// Primary API endpoint
{
type: 'api',
endpoint: 'https://api.example.com/vital',
headers: {
'Authorization': 'Bearer token'
},
separateRooms: true,
retryAttempts: 5
},
// File logging with rotation
{
type: 'file',
filepath: './logs/vital-data.json',
format: 'jsonl',
rotateSize: 10, // 10MB
maxFiles: 5
},
// Medical system integration
{
type: 'telegraf',
host: 'localhost',
port: 8094,
maxBeds: 10
}
]
});
await listener.start();// JSON Lines format (recommended for streaming)
{
type: 'file',
filepath: './data/vital-stream.jsonl',
format: 'jsonl'
}
// Pretty JSON with rotation
{
type: 'file',
filepath: './data/vital-data.json',
format: 'json',
prettify: true,
rotateSize: 5, // Rotate after 5MB
maxFiles: 10 // Keep last 10 files
}
// Timestamped files
{
type: 'file',
filepath: './archive/vital.json',
includeTimestamp: true // Creates: vital_2024-01-01T12-00-00-000Z.json
}const listener = new VitalRecorderListener({ port: 3000 });
// Start listener
await listener.start();
// Check status
const status = listener.getStatus();
console.log(status);
// {
// isRunning: true,
// port: 3000,
// connections: 1,
// hasData: true,
// lastUpdate: "2024-01-01T12:00:00.123Z",
// outputsCount: 2
// }
// Get last data
const data = listener.getLastData();
if (data) {
console.log(`Tracks: ${data.allTracks.length}`);
}
// Stop listener
await listener.stop();Create a telegraf.conf file for medical data collection:
[global_tags]
environment = "medical_icu"
facility = "vital_recorder_integration"
[agent]
interval = "1s"
# HTTP Listener for VitalRecorder data
[[inputs.http_listener_v2]]
service_address = ":8094"
paths = ["/telegraf"]
methods = ["POST"]
data_format = "influx"
# Send to InfluxDB
[[outputs.influxdb_v2]]
urls = ["http://influxdb:8086"]
token = "your-influx-token"
organization = "medical_org"
bucket = "medical_data"
namepass = ["bed_vitals"] # Only vital signs from VitalRecorderversion: '3.8'
services:
influxdb:
image: influxdb:2.7
ports:
- "8086:8086"
environment:
- DOCKER_INFLUXDB_INIT_MODE=setup
- DOCKER_INFLUXDB_INIT_USERNAME=admin
- DOCKER_INFLUXDB_INIT_PASSWORD=password123
- DOCKER_INFLUXDB_INIT_ORG=medical_org
- DOCKER_INFLUXDB_INIT_BUCKET=medical_data
telegraf:
image: telegraf:1.28
volumes:
- ./telegraf.conf:/etc/telegraf/telegraf.conf:ro
ports:
- "8094:8094"
depends_on:
- influxdb
vital-listener:
build: .
ports:
- "3000:3000"
depends_on:
- telegrafThe listener provides several REST endpoints for data retrieval:
GET /health- Health check and statusGET /api/data- Get all processed dataGET /api/data/rooms- Get data organized by roomsGET /api/data/tracks- Get all tracks (flattened)
# Clone the repository
git clone https://github.com/yourusername/vital-recorder-listener.git
cd vital-recorder-listener
# Install dependencies
npm install
# Build TypeScript
npm run build# Run all tests
npm test
# Run tests in watch mode
npm run test:watch
# Run tests with coverage
npm run test:coverage
# Run specific test file
npx jest tests/unit/processors/DataProcessor.test.ts
# Run unit tests only
npx jest tests/unit
# Run integration tests only
npx jest tests/integrationThe package includes comprehensive test coverage:
-
Unit Tests: Test individual components in isolation
- DataProcessor: Data decompression and transformation
- FileOutput: File writing and rotation logic
- ConsoleOutput: Console formatting
- ApiOutput: HTTP requests and retry logic
- TelegrafOutput: Medical data mapping and InfluxDB integration
- TimeFormatter: Timestamp conversions
- VitalRecorderListener: Core functionality
-
Integration Tests: End-to-end testing
- Socket.IO communication with real data
- Multiple concurrent connections
- API endpoints functionality
- Output integrations
- Medical system integration
- Error handling and recovery
# Run ESLint
npm run lint
# Fix linting issues
npx eslint . --ext .ts --fix# Run basic example
npx ts-node example.ts basic
# Run multi-output example
npx ts-node example.ts multi
# Run embedded example
npx ts-node example.ts embedded
# Run advanced example
npx ts-node example.ts advanced
# Run Telegraf/medical example
npx ts-node example.ts telegraf{
vrcode?: string, // Vital Recorder code
timestamp: string, // ISO timestamp with milliseconds
rooms: [
{
roomIndex: number,
roomName: string,
tracks: [
{
name: string,
value: string, // Formatted display value
rawValue: any, // Original value
unit: string,
timestamp: string, // ISO timestamp with ms
roomIndex: number,
roomName: string,
trackIndex: number,
recordIndex: number,
type: 'waveform' | 'number' | 'string' | 'other'
}
]
}
],
allTracks: [...] // All tracks flattened
}When using Telegraf output, data is converted to medical format:
bed_vitals,bed_id=ICU-01 heart_rate=75,pleth_hr=76,nibp_sbp=120,nibp_dbp=80,art_sbp=118,art_dbp=78,pleth_spo2=98,rr=16,rr_co2=15,bt=37.2,etco2=35.5
Note: Only vital signs and physiological parameters from VitalRecorder are included. EMG data and clinical assessment scores (BPS/RASS) are intentionally excluded as they are expected to be provided to Telegraf through separate channels.
The Telegraf output automatically maps these VitalRecorder parameters:
Cardiovascular:
- HR, PLETH_HR, PVC
Blood Pressure:
- NIBP_SBP, NIBP_DBP, NIBP_MBP
- ART_SBP, ART_DBP, ART_MBP
Oxygenation & Saturation:
- PLETH_SPO2, SO2_1, SO2_2, SPHB
Respiratory:
- RR, RR_CO2, ETCO2, TV, PEEP, PIP
Temperature:
- BT
Anesthesia & Gas:
- GAS1_AGENT, GAS1_EXPIRED
Perfusion & Flow:
- CO, TOTAL_VOL, FLOW_RATE, PVI, PSI
Neurological:
- SEFL
Waveform Statistics:
- ECG, PLETH, ART, CVP, EEG, CO2 (min, max, mean, std, rms, points)
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
MIT - see LICENSE file for details
For issues, questions, or suggestions, please open an issue on GitHub.