Advanced Usage & Patterns
Advanced implementation patterns, real-world integration examples, and best practices for using the BT Management module in production healthcare applications.
Overview
This guide covers advanced usage patterns for the BT Management module, including complex integration scenarios, performance optimization techniques, error recovery strategies, and production deployment considerations.
Production Integration Patterns
Healthcare Application Architecture
Complete healthcare application integration with patient management, measurement storage, and clinical workflows.
import React from "react";
import {
BTProvider,
DeviceStatus,
MeasurementTypeKey,
IntegratedDevices,
} from "@ovok/native";
import {
PatientManager,
MeasurementStore,
ClinicalWorkflow,
} from "@healthcare/core";
interface HealthcareAppState {
currentPatient: Patient | null;
activeDevices: Map<IntegratedDevices, DeviceConnection>;
measurementSession: MeasurementSession | null;
clinicalContext: ClinicalContext;
}
class HealthcareApplication extends React.Component<{}, HealthcareAppState> {
private measurementStore = new MeasurementStore();
private clinicalWorkflow = new ClinicalWorkflow();
private deviceConnections = new Map<IntegratedDevices, IBaseDevice>();
constructor(props: {}) {
super(props);
this.state = {
currentPatient: null,
activeDevices: new Map(),
measurementSession: null,
clinicalContext: {
locationId: "ward-1",
providerId: "nurse-123",
sessionType: "routine-vitals",
},
};
}
// Device discovery with intelligent routing
handleDeviceFound = async (
device: IBaseDevice,
scanInstance: ScanManagerImplementation,
) => {
try {
// Stop scanning during connection
scanInstance.stopScan();
// Clinical validation
if (!this.validateDeviceForPatient(device)) {
throw new Error("Device not authorized for current patient");
}
// Connect with timeout (connect() auto-subscribes internally)
await this.connectWithTimeout(device, 30000);
// Register device in active session
this.registerDeviceInSession(device);
// Update UI state
this.setState((prevState) => ({
activeDevices: new Map(prevState.activeDevices).set(device.deviceName, {
device: device.deviceData,
connectedAt: new Date(),
lastActivity: new Date(),
status: DeviceStatus.Connected,
measurementCount: 0,
}),
}));
// Resume scanning for additional devices
setTimeout(() => scanInstance.startScan(), 1000);
} catch (error) {
console.error("Device connection failed:", error);
this.handleConnectionError(device, error as Error);
}
};
// Measurement processing with clinical validation
handleResult = async (data: { deviceData: DeviceData; data: any }) => {
const { deviceData: device, data: measurement } = data;
try {
// Clinical validation
const validationResult = await this.clinicalWorkflow.validateMeasurement(
measurement,
this.state.currentPatient,
this.state.clinicalContext,
);
if (!validationResult.isValid) {
this.showClinicalAlert(validationResult.alerts);
return;
}
// Enrich measurement with clinical context
const enrichedMeasurement = {
...measurement,
patientId: this.state.currentPatient?.id,
sessionId: this.state.measurementSession?.id,
deviceInfo: {
name: device.name,
serialNumber: device.sn,
model: device.model.deviceName,
},
clinicalContext: this.state.clinicalContext,
timestamp: new Date().toISOString(),
providerId: this.state.clinicalContext.providerId,
locationId: this.state.clinicalContext.locationId,
};
// Store measurement
await this.measurementStore.saveMeasurement(enrichedMeasurement);
// Update workflow state
await this.clinicalWorkflow.processMeasurement(enrichedMeasurement);
// Update device activity
this.updateDeviceActivity(device.name);
// Check for clinical alerts
await this.checkClinicalAlerts(enrichedMeasurement);
} catch (error) {
console.error("Measurement processing failed:", error);
this.handleMeasurementError(measurement, device, error as Error);
}
};
// Device status management with clinical implications
handleDeviceStatusChanged = (data: {
deviceData: DeviceData;
status: DeviceStatus;
measurementTypeKey?: MeasurementTypeKey;
}) => {
const { deviceData: device, status, measurementTypeKey: measurementType } = data;
switch (status) {
case DeviceStatus.Connected:
this.onDeviceConnected(device);
break;
case DeviceStatus.Measuring:
this.onMeasurementStarted(device, measurementType);
break;
case DeviceStatus.Disconnected:
this.onDeviceDisconnected(device);
break;
case DeviceStatus.LowBattery:
this.onLowBattery(device);
break;
}
// Update device state
this.setState((prevState) => {
const activeDevices = new Map(prevState.activeDevices);
const deviceConnection = activeDevices.get(device.name);
if (deviceConnection) {
activeDevices.set(device.name, {
...deviceConnection,
status,
lastActivity: new Date(),
measuring:
status === DeviceStatus.Measuring ? measurementType : undefined,
});
}
return { activeDevices };
});
};
// Error handling with clinical escalation
handleError = async (data: { error: string; deviceData?: DeviceData }) => {
const { error, deviceData: device } = data;
const errorContext = {
deviceName: device?.name,
patientId: this.state.currentPatient?.id,
sessionId: this.state.measurementSession?.id,
error,
timestamp: new Date().toISOString(),
};
// Log clinical incident
await this.clinicalWorkflow.logIncident(errorContext);
// Determine error severity
const severity = this.assessErrorSeverity(error, device);
if (severity === "critical") {
// Escalate to clinical staff
await this.escalateError(errorContext);
} else {
// Handle locally
this.handleLocalError(error, device);
}
};
// Access permission monitoring
handleAccessPermissionChanged = (granted: boolean) => {
if (!granted) {
console.warn("Bluetooth permissions revoked");
this.handlePermissionRevoked();
}
};
// Helper methods for clinical integration
private validateDeviceForPatient(device: IBaseDevice): boolean {
if (!this.state.currentPatient) return false;
// Check device authorization for patient
const patientProfile = this.state.currentPatient.profile;
const requiredMeasurements = patientProfile.requiredMeasurements;
return device.deviceData.supportedMeasurementTypeKeys.some((type) =>
requiredMeasurements.includes(type),
);
}
private async connectWithTimeout(
device: IBaseDevice,
timeout: number,
): Promise<void> {
return Promise.race([
device.connect(),
new Promise<never>((_, reject) =>
setTimeout(() => reject(new Error("Connection timeout")), timeout),
),
]);
}
private registerDeviceInSession(device: IBaseDevice): void {
if (this.state.measurementSession) {
this.state.measurementSession.connectedDevices.push({
deviceName: device.deviceName,
deviceId: device.deviceId,
connectedAt: new Date(),
});
}
}
private async checkClinicalAlerts(
measurement: EnrichedMeasurement,
): Promise<void> {
const alerts = await this.clinicalWorkflow.generateAlerts(
measurement,
this.state.currentPatient,
);
if (alerts.length > 0) {
for (const alert of alerts) {
await this.processAlert(alert);
}
}
}
render() {
return (
<BTProvider
bleManager={this.props.bleManager}
acceptedDevices={this.props.acceptedDevices}
onDeviceFound={this.handleDeviceFound}
onError={this.handleError}
onResult={this.handleResult}
onDeviceStatusChanged={this.handleDeviceStatusChanged}
onAccessPermissionChanged={this.handleAccessPermissionChanged}
>
<ClinicalDashboard
patient={this.state.currentPatient}
activeDevices={this.state.activeDevices}
measurementSession={this.state.measurementSession}
/>
</BTProvider>
);
}
}
Multi-Device Coordination
Coordinating multiple devices for comprehensive patient monitoring.
import React from "react";
import {
BTProvider,
DeviceStatus,
MeasurementTypeKey,
} from "@ovok/native";
interface MultiDeviceCoordinator {
deviceGroups: Map<string, DeviceGroup>;
measurementProtocols: Map<string, MeasurementProtocol>;
activeWorkflows: Map<string, Workflow>;
}
class MultiDeviceCoordinator extends React.Component {
private deviceOrchestrator = new DeviceOrchestrator();
private protocolManager = new ProtocolManager();
// Coordinated device discovery
handleDeviceFound = async (
device: IBaseDevice,
scanInstance: ScanManagerImplementation,
) => {
// Determine device role in measurement protocol
const deviceRole = this.protocolManager.getDeviceRole(device.deviceName);
if (!deviceRole) {
console.log(
`Device ${device.deviceName} not required for current protocol`,
);
return;
}
// Check if device group is complete
const deviceGroup = this.deviceOrchestrator.addDevice(device, deviceRole);
if (deviceGroup.isComplete()) {
// Start coordinated measurement protocol
await this.startCoordinatedMeasurement(deviceGroup);
}
};
// Synchronized measurement collection
private async startCoordinatedMeasurement(
deviceGroup: DeviceGroup,
): Promise<void> {
const protocol = this.protocolManager.getProtocol(deviceGroup.protocolId);
try {
// Step 1: Prepare all devices
await this.prepareDevices(deviceGroup.devices);
// Step 2: Execute measurement sequence
for (const step of protocol.steps) {
await this.executeProtocolStep(step, deviceGroup);
// Wait for step completion
await this.waitForStepCompletion(step, deviceGroup);
}
// Step 3: Collect and correlate results
const correlatedResults = await this.correlateResults(deviceGroup);
// Step 4: Generate comprehensive report
await this.generateComprehensiveReport(correlatedResults);
} catch (error) {
console.error("Coordinated measurement failed:", error);
await this.handleProtocolFailure(deviceGroup, error as Error);
}
}
// Protocol step execution
private async executeProtocolStep(
step: ProtocolStep,
deviceGroup: DeviceGroup,
): Promise<void> {
const targetDevices = deviceGroup.devices.filter((device) =>
step.deviceTypes.includes(device.deviceName),
);
// Execute step on all target devices simultaneously
const stepPromises = targetDevices.map(async (device) => {
switch (step.action) {
case "measure":
return this.triggerMeasurement(device);
case "calibrate":
return this.calibrateDevice(device);
case "sync":
return this.syncDeviceTime(device);
default:
throw new Error(`Unknown step action: ${step.action}`);
}
});
await Promise.all(stepPromises);
}
// Result correlation across devices
private async correlateResults(
deviceGroup: DeviceGroup,
): Promise<CorrelatedResults> {
const measurements = deviceGroup.devices.map(
(device) => device.lastMeasurement,
);
const correlationRules = this.protocolManager.getCorrelationRules(
deviceGroup.protocolId,
);
return {
primaryMeasurements: measurements,
correlatedData: this.applyCorrelationRules(
measurements,
correlationRules,
),
timestamp: new Date(),
deviceGroup: deviceGroup.id,
protocolId: deviceGroup.protocolId,
};
}
}
// Device orchestration classes
class DeviceOrchestrator {
private deviceGroups = new Map<string, DeviceGroup>();
private activeProtocols = new Map<string, Protocol>();
addDevice(device: IBaseDevice, role: DeviceRole): DeviceGroup {
const groupId = this.determineDeviceGroup(device, role);
if (!this.deviceGroups.has(groupId)) {
this.deviceGroups.set(groupId, new DeviceGroup(groupId));
}
const group = this.deviceGroups.get(groupId)!;
group.addDevice(device, role);
return group;
}
private determineDeviceGroup(device: IBaseDevice, role: DeviceRole): string {
// Group devices based on measurement protocol
if (role.protocol === "cardiac-assessment") {
return "cardiac-group-" + Date.now();
} else if (role.protocol === "diabetes-monitoring") {
return "diabetes-group-" + Date.now();
} else {
return "general-group-" + Date.now();
}
}
}
class DeviceGroup {
public readonly id: string;
public readonly devices: IBaseDevice[] = [];
public readonly deviceRoles = new Map<string, DeviceRole>();
public protocolId: string;
constructor(id: string) {
this.id = id;
}
addDevice(device: IBaseDevice, role: DeviceRole): void {
this.devices.push(device);
this.deviceRoles.set(device.deviceId, role);
this.protocolId = role.protocol;
}
isComplete(): boolean {
const requiredRoles = this.getRequiredRoles();
const currentRoles = Array.from(this.deviceRoles.values()).map(
(role) => role.type,
);
return requiredRoles.every((role) => currentRoles.includes(role));
}
private getRequiredRoles(): string[] {
// Define required device roles for different protocols
switch (this.protocolId) {
case "cardiac-assessment":
return ["blood-pressure", "ecg", "weight"];
case "diabetes-monitoring":
return ["glucose", "weight", "blood-pressure"];
default:
return [];
}
}
}
Real-Time Monitoring Dashboard
Advanced real-time monitoring with multiple device streams.
import React from "react";
import { BTProvider, DeviceStatus } from "@ovok/native";
interface MonitoringDashboardState {
realTimeData: Map<string, RealTimeStream>;
alerts: Alert[];
trends: Map<string, TrendData>;
deviceMetrics: Map<string, DeviceMetrics>;
}
class MonitoringDashboard extends React.Component<
{},
MonitoringDashboardState
> {
private streamManager = new StreamManager();
private alertEngine = new AlertEngine();
private trendAnalyzer = new TrendAnalyzer();
constructor(props: {}) {
super(props);
this.state = {
realTimeData: new Map(),
alerts: [],
trends: new Map(),
deviceMetrics: new Map(),
};
}
// Real-time data processing via onResult
handleResult = (data: { deviceData: DeviceData; data: any }) => {
const { deviceData: device, data: measurement } = data;
// Process real-time stream
const streamData = this.streamManager.processStreamData(
measurement,
device,
);
// Update real-time state
this.setState((prevState) => ({
realTimeData: new Map(prevState.realTimeData).set(
device.name,
streamData,
),
}));
// Analyze for immediate alerts
const immediateAlerts = this.alertEngine.analyzeRealTimeData(streamData);
if (immediateAlerts.length > 0) {
this.handleImmediateAlerts(immediateAlerts);
}
// Update trends
this.updateTrendAnalysis(device.name, streamData);
// Update device metrics
this.updateDeviceMetrics(device.name, streamData);
};
// Trend analysis with machine learning
private updateTrendAnalysis(
deviceName: string,
streamData: RealTimeStream,
): void {
const trends = this.trendAnalyzer.updateTrends(deviceName, streamData);
this.setState((prevState) => ({
trends: new Map(prevState.trends).set(deviceName, trends),
}));
// Check for trend-based alerts
const trendAlerts = this.alertEngine.analyzeTrends(trends);
if (trendAlerts.length > 0) {
this.handleTrendAlerts(trendAlerts);
}
}
// Device performance monitoring
private updateDeviceMetrics(
deviceName: string,
streamData: RealTimeStream,
): void {
const currentMetrics = this.state.deviceMetrics.get(deviceName) || {
connectionQuality: 0,
dataQuality: 0,
batteryLevel: 100,
signalStrength: 0,
errorRate: 0,
lastUpdate: new Date(),
};
const updatedMetrics = {
...currentMetrics,
connectionQuality: this.calculateConnectionQuality(streamData),
dataQuality: this.calculateDataQuality(streamData),
signalStrength: streamData.signalQuality || currentMetrics.signalStrength,
lastUpdate: new Date(),
};
this.setState((prevState) => ({
deviceMetrics: new Map(prevState.deviceMetrics).set(
deviceName,
updatedMetrics,
),
}));
}
render() {
return (
<BTProvider
bleManager={this.props.bleManager}
acceptedDevices={this.props.acceptedDevices}
onDeviceFound={this.handleDeviceFound}
onError={this.handleError}
onResult={this.handleResult}
onDeviceStatusChanged={this.handleDeviceStatusChanged}
onAccessPermissionChanged={this.handleAccessPermissionChanged}
>
<DashboardLayout>
<RealTimeStreams data={this.state.realTimeData} />
<AlertPanel alerts={this.state.alerts} />
<TrendCharts trends={this.state.trends} />
<DeviceStatusGrid metrics={this.state.deviceMetrics} />
</DashboardLayout>
</BTProvider>
);
}
}
// Stream management classes
class StreamManager {
private streamBuffers = new Map<string, CircularBuffer<StreamPoint>>();
private streamProcessors = new Map<MeasurementTypeKey, StreamProcessor>();
constructor() {
this.initializeProcessors();
}
processStreamData(
measurement: Measurement,
device: DeviceData,
): RealTimeStream {
const processor = this.streamProcessors.get(measurement.measurementTypeKey);
if (!processor) {
throw new Error(
`No processor for measurement type: ${measurement.measurementTypeKey}`,
);
}
// Get or create buffer for device
if (!this.streamBuffers.has(device.id)) {
this.streamBuffers.set(device.id, new CircularBuffer<StreamPoint>(1000));
}
const buffer = this.streamBuffers.get(device.id)!;
// Process and add to buffer
const streamPoint = processor.process(measurement);
buffer.add(streamPoint);
return {
deviceId: device.id,
deviceName: device.name,
measurementType: measurement.measurementTypeKey,
currentValue: streamPoint.value,
trend: this.calculateTrend(buffer),
quality: this.calculateQuality(buffer),
timestamp: new Date(),
buffer: buffer.getRecent(100), // Last 100 points for display
};
}
private initializeProcessors(): void {
this.streamProcessors.set(
MeasurementTypeKey.bloodOxygenPulseRate,
new PulseOximeterStreamProcessor(),
);
this.streamProcessors.set(MeasurementTypeKey.ecg, new EcgStreamProcessor());
this.streamProcessors.set(
MeasurementTypeKey.temperature,
new TemperatureStreamProcessor(),
);
}
}
// Alert engine for real-time monitoring
class AlertEngine {
private alertRules = new Map<MeasurementTypeKey, AlertRule[]>();
private trendRules = new Map<string, TrendRule[]>();
constructor() {
this.initializeAlertRules();
}
analyzeRealTimeData(streamData: RealTimeStream): Alert[] {
const rules = this.alertRules.get(streamData.measurementType) || [];
const alerts: Alert[] = [];
for (const rule of rules) {
if (rule.evaluate(streamData)) {
alerts.push({
id: this.generateAlertId(),
type: rule.type,
severity: rule.severity,
message: rule.generateMessage(streamData),
deviceName: streamData.deviceName,
timestamp: new Date(),
data: streamData.currentValue,
});
}
}
return alerts;
}
analyzeTrends(trends: TrendData): Alert[] {
const rules = this.trendRules.get(trends.measurementType) || [];
const alerts: Alert[] = [];
for (const rule of rules) {
if (rule.evaluate(trends)) {
alerts.push({
id: this.generateAlertId(),
type: "trend",
severity: rule.severity,
message: rule.generateMessage(trends),
deviceName: trends.deviceName,
timestamp: new Date(),
data: trends,
});
}
}
return alerts;
}
private initializeAlertRules(): void {
// Blood oxygen saturation rules
this.alertRules.set(MeasurementTypeKey.bloodOxygenPulseRate, [
{
type: "low-oxygen",
severity: "critical",
evaluate: (stream: RealTimeStream) =>
stream.currentValue.bloodOxygen < 90,
generateMessage: (stream: RealTimeStream) =>
`Critical: Blood oxygen ${stream.currentValue.bloodOxygen}% is below 90%`,
},
{
type: "high-pulse",
severity: "warning",
evaluate: (stream: RealTimeStream) =>
stream.currentValue.pulseRate > 120,
generateMessage: (stream: RealTimeStream) =>
`Warning: Pulse rate ${stream.currentValue.pulseRate} bpm is elevated`,
},
]);
// Temperature rules
this.alertRules.set(MeasurementTypeKey.temperature, [
{
type: "fever",
severity: "warning",
evaluate: (stream: RealTimeStream) =>
stream.currentValue.bodyTemp > 38.0,
generateMessage: (stream: RealTimeStream) =>
`Warning: Temperature ${stream.currentValue.bodyTemp}°C indicates fever`,
},
]);
}
}
Performance Optimization
Connection Pool Management
Efficient management of device connections to prevent resource exhaustion.
class ConnectionPoolManager {
private connectionPool = new Map<IntegratedDevices, ConnectionPool>();
private globalConnectionLimit = 5;
private deviceConnectionLimits = new Map<IntegratedDevices, number>();
constructor() {
this.initializeConnectionLimits();
}
async acquireConnection(
deviceType: IntegratedDevices,
device: IBaseDevice,
): Promise<Connection> {
const pool = this.getOrCreatePool(deviceType);
if (pool.activeConnections >= this.getConnectionLimit(deviceType)) {
throw new Error(`Connection limit reached for ${deviceType}`);
}
const connection = await this.createConnection(device);
pool.activeConnections++;
pool.connections.set(device.deviceId, connection);
return connection;
}
async releaseConnection(
deviceType: IntegratedDevices,
deviceId: string,
): Promise<void> {
const pool = this.connectionPool.get(deviceType);
if (!pool) return;
const connection = pool.connections.get(deviceId);
if (connection) {
await connection.disconnect();
pool.connections.delete(deviceId);
pool.activeConnections--;
}
}
private getOrCreatePool(deviceType: IntegratedDevices): ConnectionPool {
if (!this.connectionPool.has(deviceType)) {
this.connectionPool.set(deviceType, {
deviceType,
connections: new Map(),
activeConnections: 0,
lastCleanup: new Date(),
});
}
return this.connectionPool.get(deviceType)!;
}
private getConnectionLimit(deviceType: IntegratedDevices): number {
return this.deviceConnectionLimits.get(deviceType) || 1;
}
private initializeConnectionLimits(): void {
// Most devices should only have 1 connection
this.deviceConnectionLimits.set(IntegratedDevices.F4, 1);
this.deviceConnectionLimits.set(IntegratedDevices.BP2, 1);
this.deviceConnectionLimits.set(IntegratedDevices.SPO2, 1);
// Some devices might support multiple connections
this.deviceConnectionLimits.set(IntegratedDevices.COSINUSS, 2);
}
// Periodic cleanup of stale connections
async performCleanup(): Promise<void> {
const now = new Date();
const cleanupThreshold = 5 * 60 * 1000; // 5 minutes
for (const [deviceType, pool] of this.connectionPool) {
if (now.getTime() - pool.lastCleanup.getTime() > cleanupThreshold) {
await this.cleanupPool(pool);
pool.lastCleanup = now;
}
}
}
private async cleanupPool(pool: ConnectionPool): Promise<void> {
const staleConnections: string[] = [];
for (const [deviceId, connection] of pool.connections) {
if (connection.isStale()) {
staleConnections.push(deviceId);
}
}
for (const deviceId of staleConnections) {
await this.releaseConnection(pool.deviceType, deviceId);
}
}
}
Data Processing Optimization
Optimized data processing for high-frequency measurements.
class OptimizedDataProcessor {
private processingQueues = new Map<string, ProcessingQueue>();
private batchProcessor = new BatchProcessor();
private compressionService = new CompressionService();
// High-frequency data processing with batching
processHighFrequencyData(
measurements: Measurement[],
device: DeviceData,
): ProcessedDataBatch {
const queueKey = `${device.name}-${measurements[0]?.measurementTypeKey}`;
if (!this.processingQueues.has(queueKey)) {
this.processingQueues.set(
queueKey,
new ProcessingQueue({
maxBatchSize: 100,
maxWaitTime: 1000, // 1 second
processor: this.batchProcessor,
}),
);
}
const queue = this.processingQueues.get(queueKey)!;
// Add measurements to batch processing queue
measurements.forEach((measurement) => {
queue.enqueue({
measurement,
device,
timestamp: new Date(),
});
});
return queue.getProcessedData();
}
// Efficient ECG data processing
processEcgStream(ecgPoints: number[], device: DeviceData): ProcessedEcgData {
// Use WebAssembly for intensive signal processing if available
if (this.isWebAssemblyAvailable()) {
return this.processEcgWithWasm(ecgPoints, device);
}
// Fallback to optimized JavaScript
return this.processEcgOptimized(ecgPoints, device);
}
private processEcgOptimized(
ecgPoints: number[],
device: DeviceData,
): ProcessedEcgData {
// Use typed arrays for better performance
const float32Points = new Float32Array(ecgPoints);
// Apply filters using optimized algorithms
const filtered = this.applyOptimizedFilters(float32Points);
// Detect features using efficient algorithms
const features = this.detectEcgFeatures(filtered);
// Compress data for storage
const compressed = this.compressionService.compressEcgData(filtered);
return {
rawPoints: ecgPoints,
filteredPoints: Array.from(filtered),
features,
compressed,
processingTime: this.getProcessingTime(),
deviceName: device.name,
};
}
private applyOptimizedFilters(data: Float32Array): Float32Array {
// Optimized cascaded filtering
let filtered = new Float32Array(data.length);
// High-pass filter (baseline removal)
this.applyHighPassFilter(data, filtered, 0.5);
// Low-pass filter (noise reduction)
this.applyLowPassFilter(filtered, filtered, 40);
// Notch filter (power line interference)
this.applyNotchFilter(filtered, filtered, 50);
return filtered;
}
private detectEcgFeatures(data: Float32Array): EcgFeatures {
// Efficient R-peak detection
const rPeaks = this.detectRPeaks(data);
// Calculate intervals
const rrIntervals = this.calculateRRIntervals(rPeaks);
// Heart rate variability
const hrv = this.calculateHRV(rrIntervals);
return {
rPeaks,
rrIntervals,
heartRate: this.calculateHeartRate(rrIntervals),
hrv,
quality: this.assessSignalQuality(data),
};
}
}
// Batch processing for improved throughput
class BatchProcessor {
private processingWorkers: Worker[] = [];
private workerIndex = 0;
constructor() {
this.initializeWorkers();
}
async processBatch(items: ProcessingItem[]): Promise<ProcessedDataBatch> {
// Distribute work across multiple workers
const workerPromises = this.distributeWork(items);
// Wait for all workers to complete
const results = await Promise.all(workerPromises);
// Merge results
return this.mergeResults(results);
}
private distributeWork(items: ProcessingItem[]): Promise<ProcessedData>[] {
const chunkSize = Math.ceil(items.length / this.processingWorkers.length);
const promises: Promise<ProcessedData>[] = [];
for (let i = 0; i < items.length; i += chunkSize) {
const chunk = items.slice(i, i + chunkSize);
const worker =
this.processingWorkers[
this.workerIndex % this.processingWorkers.length
];
promises.push(this.processChunk(worker, chunk));
this.workerIndex++;
}
return promises;
}
private async processChunk(
worker: Worker,
chunk: ProcessingItem[],
): Promise<ProcessedData> {
return new Promise((resolve, reject) => {
worker.postMessage({ type: "PROCESS_CHUNK", payload: chunk });
worker.onmessage = (event) => {
if (event.data.type === "CHUNK_PROCESSED") {
resolve(event.data.payload);
}
};
worker.onerror = reject;
});
}
private initializeWorkers(): void {
const workerCount = navigator.hardwareConcurrency || 4;
for (let i = 0; i < workerCount; i++) {
const worker = new Worker("/workers/data-processor.js");
this.processingWorkers.push(worker);
}
}
}
Memory Management
Efficient memory management for long-running applications.
class MemoryManager {
private memoryMonitor = new MemoryMonitor();
private dataRetentionPolicies = new Map<string, RetentionPolicy>();
private compressionThresholds = new Map<string, number>();
constructor() {
this.initializeRetentionPolicies();
this.startMemoryMonitoring();
}
// Automatic memory cleanup based on usage patterns
async performMemoryOptimization(): Promise<void> {
const memoryStats = await this.memoryMonitor.getStats();
if (memoryStats.usagePercentage > 80) {
// Aggressive cleanup
await this.performAggressiveCleanup();
} else if (memoryStats.usagePercentage > 60) {
// Normal cleanup
await this.performNormalCleanup();
}
}
private async performAggressiveCleanup(): Promise<void> {
// Compress old measurement data
await this.compressOldMeasurements();
// Clear cached data
await this.clearCachedData();
// Optimize image cache
await this.optimizeImageCache();
// Force garbage collection if available
if (global.gc) {
global.gc();
}
}
private async compressOldMeasurements(): Promise<void> {
const oldMeasurements = await this.getOldMeasurements();
for (const measurement of oldMeasurements) {
if (
measurement.type === MeasurementTypeKey.ecg &&
measurement.data.length > 1000
) {
// Compress ECG data
const compressed = await this.compressEcgData(measurement.data);
await this.updateMeasurement(measurement.id, {
compressedData: compressed,
});
}
}
}
// Smart data retention based on clinical value
applyRetentionPolicy(
measurement: Measurement,
device: DeviceData,
): RetentionDecision {
const policy = this.dataRetentionPolicies.get(
measurement.measurementTypeKey,
);
if (!policy) {
return { retain: true, duration: "1year" };
}
// Clinical value assessment
const clinicalValue = this.assessClinicalValue(measurement);
// Apply retention based on value and policy
return policy.apply(measurement, clinicalValue);
}
private assessClinicalValue(measurement: Measurement): ClinicalValue {
// Assess clinical importance of measurement
const factors = {
abnormalValues: this.hasAbnormalValues(measurement),
criticalAlert: this.triggeredCriticalAlert(measurement),
diagnosticSignificance: this.hasDiagnosticSignificance(measurement),
researchValue: this.hasResearchValue(measurement),
};
let score = 0;
if (factors.abnormalValues) score += 3;
if (factors.criticalAlert) score += 5;
if (factors.diagnosticSignificance) score += 4;
if (factors.researchValue) score += 2;
return {
score,
category: score >= 7 ? "high" : score >= 4 ? "medium" : "low",
factors,
};
}
private initializeRetentionPolicies(): void {
// ECG data - high clinical value, compress after 30 days
this.dataRetentionPolicies.set(MeasurementTypeKey.ecg, {
apply: (measurement, clinicalValue) => ({
retain: true,
duration: clinicalValue.category === "high" ? "7years" : "2years",
compress: true,
compressionDelay: "30days",
}),
});
// Blood pressure - retain all, compress after 90 days
this.dataRetentionPolicies.set(MeasurementTypeKey.bloodPressure, {
apply: (measurement, clinicalValue) => ({
retain: true,
duration: "5years",
compress: clinicalValue.category !== "high",
compressionDelay: "90days",
}),
});
// Temperature - retain based on clinical value
this.dataRetentionPolicies.set(MeasurementTypeKey.temperature, {
apply: (measurement, clinicalValue) => ({
retain: clinicalValue.score >= 2,
duration: clinicalValue.category === "high" ? "2years" : "6months",
compress: true,
compressionDelay: "30days",
}),
});
}
}
// Memory monitoring service
class MemoryMonitor {
private monitoringInterval: NodeJS.Timeout | null = null;
private memoryCallbacks: ((stats: MemoryStats) => void)[] = [];
startMonitoring(interval: number = 30000): void {
this.monitoringInterval = setInterval(async () => {
const stats = await this.getStats();
this.notifyCallbacks(stats);
}, interval);
}
async getStats(): Promise<MemoryStats> {
// Get memory statistics
const jsHeapSizeLimit = (performance as any).memory?.jsHeapSizeLimit || 0;
const totalJSHeapSize = (performance as any).memory?.totalJSHeapSize || 0;
const usedJSHeapSize = (performance as any).memory?.usedJSHeapSize || 0;
return {
totalMemory: jsHeapSizeLimit,
usedMemory: usedJSHeapSize,
freeMemory: jsHeapSizeLimit - totalJSHeapSize,
usagePercentage: (usedJSHeapSize / jsHeapSizeLimit) * 100,
timestamp: new Date(),
};
}
onMemoryUpdate(callback: (stats: MemoryStats) => void): void {
this.memoryCallbacks.push(callback);
}
private notifyCallbacks(stats: MemoryStats): void {
this.memoryCallbacks.forEach((callback) => callback(stats));
}
}
Error Recovery & Resilience
Comprehensive Error Recovery
Advanced error recovery with automatic retry and fallback mechanisms.
class ErrorRecoveryManager {
private retryPolicies = new Map<string, RetryPolicy>();
private circuitBreakers = new Map<string, CircuitBreaker>();
private fallbackStrategies = new Map<string, FallbackStrategy>();
constructor() {
this.initializeRetryPolicies();
this.initializeCircuitBreakers();
this.initializeFallbackStrategies();
}
async executeWithRecovery<T>(
operation: () => Promise<T>,
context: OperationContext,
): Promise<T> {
const circuitBreaker = this.getCircuitBreaker(context.operationType);
if (circuitBreaker.isOpen()) {
// Circuit is open, try fallback
return this.executeFallback(context);
}
try {
const result = await this.executeWithRetry(operation, context);
circuitBreaker.recordSuccess();
return result;
} catch (error) {
circuitBreaker.recordFailure();
if (circuitBreaker.isOpen()) {
// Circuit opened, use fallback
return this.executeFallback(context);
}
throw error;
}
}
private async executeWithRetry<T>(
operation: () => Promise<T>,
context: OperationContext,
): Promise<T> {
const retryPolicy = this.retryPolicies.get(context.operationType);
if (!retryPolicy) {
return operation();
}
let lastError: Error;
for (let attempt = 1; attempt <= retryPolicy.maxAttempts; attempt++) {
try {
const result = await operation();
if (attempt > 1) {
console.log(`Operation succeeded on attempt ${attempt}`);
}
return result;
} catch (error) {
lastError = error as Error;
if (!retryPolicy.shouldRetry(error as Error, attempt)) {
break;
}
if (attempt < retryPolicy.maxAttempts) {
const delay = retryPolicy.calculateDelay(attempt);
console.log(
`Retrying operation in ${delay}ms (attempt ${attempt + 1})`,
);
await this.delay(delay);
}
}
}
throw lastError!;
}
private async executeFallback<T>(context: OperationContext): Promise<T> {
const fallback = this.fallbackStrategies.get(context.operationType);
if (!fallback) {
throw new Error(`No fallback available for ${context.operationType}`);
}
console.log(`Executing fallback strategy for ${context.operationType}`);
return fallback.execute(context);
}
private initializeRetryPolicies(): void {
// Device connection retry policy
this.retryPolicies.set("device-connection", {
maxAttempts: 3,
shouldRetry: (error: Error, attempt: number) => {
// Retry connection errors but not authentication errors
return error.message.includes("Connection") && attempt < 3;
},
calculateDelay: (attempt: number) => Math.pow(2, attempt) * 1000, // Exponential backoff
});
// Scanning retry policy
this.retryPolicies.set("device-scanning", {
maxAttempts: 5,
shouldRetry: (error: Error, attempt: number) => {
// Retry most scanning errors
return !error.message.includes("Permission") && attempt < 5;
},
calculateDelay: (attempt: number) => attempt * 2000, // Linear backoff
});
// Data transmission retry policy
this.retryPolicies.set("data-transmission", {
maxAttempts: 3,
shouldRetry: (error: Error, attempt: number) => {
// Retry network and timeout errors
return (
(error.message.includes("timeout") ||
error.message.includes("network")) &&
attempt < 3
);
},
calculateDelay: (attempt: number) =>
Math.min(Math.pow(2, attempt) * 500, 5000), // Capped exponential
});
}
private initializeCircuitBreakers(): void {
// Device connection circuit breaker
this.circuitBreakers.set(
"device-connection",
new CircuitBreaker({
failureThreshold: 3,
successThreshold: 2,
timeout: 60000, // 1 minute
monitoringPeriod: 10000, // 10 seconds
}),
);
// Data processing circuit breaker
this.circuitBreakers.set(
"data-processing",
new CircuitBreaker({
failureThreshold: 5,
successThreshold: 3,
timeout: 30000, // 30 seconds
monitoringPeriod: 5000, // 5 seconds
}),
);
}
private initializeFallbackStrategies(): void {
// Device connection fallback
this.fallbackStrategies.set("device-connection", {
execute: async (context: OperationContext) => {
// Try to use cached device information
const cachedDevice = await this.getCachedDevice(context.deviceId);
if (cachedDevice) {
console.log("Using cached device data as fallback");
return cachedDevice;
}
// Use mock device for testing
if (context.isTestMode) {
console.log("Using mock device as fallback");
return this.createMockDevice(context);
}
throw new Error("No fallback available for device connection");
},
});
// Data processing fallback
this.fallbackStrategies.set("data-processing", {
execute: async (context: OperationContext) => {
// Use simplified processing algorithm
console.log("Using simplified data processing as fallback");
return this.processDataSimplified(context.data);
},
});
}
private delay(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
}
// Circuit breaker implementation
class CircuitBreaker {
private state: "closed" | "open" | "half-open" = "closed";
private failureCount = 0;
private successCount = 0;
private lastFailureTime = 0;
private config: CircuitBreakerConfig;
constructor(config: CircuitBreakerConfig) {
this.config = config;
}
isOpen(): boolean {
if (this.state === "open") {
// Check if timeout has passed
if (Date.now() - this.lastFailureTime > this.config.timeout) {
this.state = "half-open";
this.successCount = 0;
return false;
}
return true;
}
return false;
}
recordSuccess(): void {
this.failureCount = 0;
if (this.state === "half-open") {
this.successCount++;
if (this.successCount >= this.config.successThreshold) {
this.state = "closed";
}
}
}
recordFailure(): void {
this.failureCount++;
this.lastFailureTime = Date.now();
if (this.failureCount >= this.config.failureThreshold) {
this.state = "open";
}
}
}
Security & Privacy
Data Encryption and Security
Comprehensive security implementation for medical device data.
class SecurityManager {
private encryptionService = new EncryptionService();
private authenticationService = new AuthenticationService();
private auditLogger = new AuditLogger();
// Secure device pairing
async secureDevicePairing(
device: IBaseDevice,
userCredentials: UserCredentials,
): Promise<SecurePairingResult> {
try {
// Authenticate user
const authResult =
await this.authenticationService.authenticate(userCredentials);
if (!authResult.success) {
throw new Error("User authentication failed");
}
// Validate device certificate
const deviceValidation = await this.validateDeviceCertificate(device);
if (!deviceValidation.isValid) {
throw new Error("Device certificate validation failed");
}
// Generate secure pairing key
const pairingKey = await this.generatePairingKey(device, authResult.user);
// Store encrypted pairing information
const encryptedPairingData = await this.encryptionService.encrypt({
deviceId: device.deviceId,
deviceName: device.deviceName,
pairingKey,
userId: authResult.user.id,
timestamp: new Date(),
});
await this.storeSecurePairingData(device.deviceId, encryptedPairingData);
// Log audit event
await this.auditLogger.log({
event: "device_paired",
userId: authResult.user.id,
deviceId: device.deviceId,
timestamp: new Date(),
success: true,
});
return {
success: true,
pairingKey,
expiresAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000), // 30 days
};
} catch (error) {
await this.auditLogger.log({
event: "device_pairing_failed",
deviceId: device.deviceId,
error: (error as Error).message,
timestamp: new Date(),
success: false,
});
throw error;
}
}
// Secure measurement data handling
async secureMeasurementProcessing(
measurement: Measurement,
device: DeviceData,
user: User,
): Promise<SecuredMeasurement> {
// Validate measurement integrity
const integrityCheck = this.validateMeasurementIntegrity(
measurement,
device,
);
if (!integrityCheck.isValid) {
throw new Error("Measurement integrity validation failed");
}
// Encrypt sensitive measurement data
const encryptedMeasurement =
await this.encryptionService.encryptMeasurement(measurement);
// Add security metadata
const securedMeasurement: SecuredMeasurement = {
...encryptedMeasurement,
securityMetadata: {
encryptionAlgorithm: "AES-256-GCM",
keyId: await this.encryptionService.getCurrentKeyId(),
checksum: this.calculateChecksum(measurement),
timestamp: new Date(),
userId: user.id,
deviceId: device.id,
},
};
// Log measurement processing
await this.auditLogger.log({
event: "measurement_processed",
userId: user.id,
deviceId: device.id,
measurementType: measurement.measurementTypeKey,
timestamp: new Date(),
success: true,
});
return securedMeasurement;
}
// Privacy-preserving data sharing
async createPrivacyPreservingShare(
measurements: SecuredMeasurement[],
shareRequest: ShareRequest,
): Promise<PrivacyPreservingShare> {
// Validate share request permissions
const permissionCheck = await this.validateSharePermissions(shareRequest);
if (!permissionCheck.isValid) {
throw new Error("Insufficient permissions for data sharing");
}
// Apply differential privacy
const privateMeasurements = await this.applyDifferentialPrivacy(
measurements,
shareRequest.privacyLevel,
);
// Remove direct identifiers
const deidentifiedMeasurements =
this.removeDirectIdentifiers(privateMeasurements);
// Create share package
const sharePackage: PrivacyPreservingShare = {
id: this.generateShareId(),
measurements: deidentifiedMeasurements,
privacyLevel: shareRequest.privacyLevel,
shareType: shareRequest.shareType,
expiresAt: new Date(Date.now() + shareRequest.validityPeriod),
createdBy: shareRequest.userId,
createdAt: new Date(),
accessControl: {
allowedRecipients: shareRequest.recipients,
accessConditions: shareRequest.conditions,
},
};
// Log sharing event
await this.auditLogger.log({
event: "data_shared",
userId: shareRequest.userId,
shareId: sharePackage.id,
recipientCount: shareRequest.recipients.length,
measurementCount: measurements.length,
privacyLevel: shareRequest.privacyLevel,
timestamp: new Date(),
success: true,
});
return sharePackage;
}
private async validateDeviceCertificate(
device: IBaseDevice,
): Promise<ValidationResult> {
// Implement device certificate validation
// This would typically involve checking against a certificate authority
return {
isValid: true,
certificate: "device-cert-data",
validUntil: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000),
};
}
private validateMeasurementIntegrity(
measurement: Measurement,
device: DeviceData,
): ValidationResult {
// Check measurement data consistency
const checks = [
this.checkValueRanges(measurement),
this.checkTimestampValidity(measurement),
this.checkDeviceCompatibility(measurement, device),
];
return {
isValid: checks.every((check) => check.isValid),
details: checks,
};
}
private async applyDifferentialPrivacy(
measurements: SecuredMeasurement[],
privacyLevel: PrivacyLevel,
): Promise<SecuredMeasurement[]> {
const noiseLevel = this.getNoiseLevel(privacyLevel);
return measurements.map((measurement) => ({
...measurement,
// Add calibrated noise to protect individual privacy
data: this.addDifferentialPrivacyNoise(measurement.data, noiseLevel),
}));
}
private removeDirectIdentifiers(
measurements: SecuredMeasurement[],
): SecuredMeasurement[] {
return measurements.map((measurement) => ({
...measurement,
// Remove or hash direct identifiers
userId: this.hashIdentifier(measurement.userId),
deviceId: this.hashIdentifier(measurement.deviceId),
// Remove precise timestamps
timestamp: this.coarsenTimestamp(measurement.timestamp),
}));
}
}
// Encryption service for medical data
class EncryptionService {
private keyManagement = new KeyManagementService();
async encryptMeasurement(
measurement: Measurement,
): Promise<EncryptedMeasurement> {
const key = await this.keyManagement.getCurrentEncryptionKey();
const iv = this.generateIV();
const serializedData = JSON.stringify(measurement);
const encryptedData = await this.encrypt(serializedData, key, iv);
return {
encryptedData,
iv: iv.toString("base64"),
algorithm: "AES-256-GCM",
keyId: key.id,
};
}
async decryptMeasurement(
encryptedMeasurement: EncryptedMeasurement,
): Promise<Measurement> {
const key = await this.keyManagement.getEncryptionKey(
encryptedMeasurement.keyId,
);
const iv = Buffer.from(encryptedMeasurement.iv, "base64");
const decryptedData = await this.decrypt(
encryptedMeasurement.encryptedData,
key,
iv,
);
return JSON.parse(decryptedData);
}
private async encrypt(
data: string,
key: CryptoKey,
iv: Buffer,
): Promise<string> {
// Implement AES-256-GCM encryption
const encoder = new TextEncoder();
const dataBuffer = encoder.encode(data);
const encrypted = await crypto.subtle.encrypt(
{
name: "AES-GCM",
iv: iv,
},
key,
dataBuffer,
);
return Buffer.from(encrypted).toString("base64");
}
private generateIV(): Buffer {
return crypto.getRandomValues(new Uint8Array(12)) as any;
}
}
Dependencies
react-native-ble-plx: BLE communication@ovok/core: Core measurement typesreact-native-permissions: Permission managementreact-native: Core platform functionality
Related Documentation
BTProvider: React provider componentDevice Services: Core service implementationsDevice Types: Medical device configurationsTypes: TypeScript type definitions