Node.js Plugin Development

The Node.js implementation provides an event-driven, asynchronous interface to the DroneEngage DataBus. It’s ideal for web-integrated solutions, real-time applications, and rapid prototyping.

Features

  • Event-driven Architecture - Built on Node.js EventEmitter

  • Async/Await Support - Modern JavaScript patterns

  • NPM Package - Easy installation and dependency management

  • Complete API Reference - Comprehensive documentation

  • Cross-platform - Works on Windows, macOS, and Linux

  • Real-time Communication - Low-latency UDP messaging

  • Binary Data Support - Handle images, files, and streams

  • Message Filtering - Subscribe to specific message types

Quick Start

Installation

cd nodejs
npm install

Basic Usage

node client.js --help               # Show comprehensive help
node client.js MyModule 60000 61234   # Run with all arguments  
node client.js MyModule              # Uses default ports

Architecture

The Node.js library follows the same layered architecture as other implementations:

Library Components

┌─────────────────────┐
│  Your Application   │
│  (client.js)        │
└──────────┬──────────┘
           │
           ↓
┌─────────────────────┐
│  CFacade_Base       │  ← High-level API
│  (de_facade_base.js)│
└──────────┬──────────┘
           │
           ↓
┌─────────────────────┐
│  CModule            │  ← Module management & routing
│  (de_module.js)     │  ← EventEmitter for async ops
└──────────┬──────────┘
           │
           ↓
┌─────────────────────┐
│  CUDPClient         │  ← UDP transport with chunking
│  (udpClient.js)     │  ← EventEmitter for data events
└──────────┬──────────┘
           │
           ↓
┌─────────────────────┐
│  de_comm            │  ← DroneEngage Communicator
│  (Port 60000)       │
└─────────────────────┘

Key Classes

CModule (EventEmitter)

  • Module registration and management

  • Message routing and filtering

  • Event emission for async operations

CUDPClient (EventEmitter)

  • UDP communication with chunking

  • Automatic message reassembly

  • Periodic module identification

CFacade_Base

  • Simplified API for response generation

  • Command handling and validation

  • Error handling and logging

AndruavMessageParserBase

  • JSON and binary message parsing

  • Command dispatch and routing

  • Message validation and filtering

Usage Examples

Basic Module Setup

const { CModule, CFacade_Base } = require('./de_module');
const { CUDPClient } = require('./udpClient');

class MyFacade extends CFacade_Base {
    handleCommand(request) {
        return {
            status: 'success',
            data: { message: 'Command processed' }
        };
    }
}

// Create module instance
const module = CModule.getInstance();
const facade = new MyFacade();

// Define module properties
module.defineModule('MyModule', '1.0.0', facade);

// Start communication
module.start();

Event-driven Message Handling

const module = CModule.getInstance();

// Listen for incoming messages
module.on('message', (message) => {
    console.log('Received:', message);
});

// Listen for connection events
module.on('connected', () => {
    console.log('Connected to DroneEngage communicator');
});

module.on('disconnected', () => {
    console.log('Disconnected from communicator');
});

Binary Data Transmission

const fs = require('fs');

// Read image file
const imageData = fs.readFileSync('image.jpg');

// Send binary data
module.sendBinaryData('target_module', imageData, {
    type: 'image',
    format: 'jpeg'
});

Message Filtering

// Filter messages by type
module.setMessageFilter(['telemetry', 'command']);

// Custom message handler
module.on('telemetry', (data) => {
    processTelemetryData(data);
});

API Reference

CModule Class

class CModule extends EventEmitter {
    // Singleton access
    static getInstance();
    
    // Module management
    defineModule(name, version, facade);
    start();
    stop();
    
    // Messaging
    sendMessage(target, message);
    sendBinaryData(target, data, metadata);
    
    // Configuration
    setMessageFilter(filters);
    setJsonId(jsonId);
    
    // Events
    on('message', callback);
    on('connected', callback);
    on('disconnected', callback);
    on('error', callback);
}

CUDPClient Class

class CUDPClient extends EventEmitter {
    constructor(callback);
    
    // Network operations
    initialize(port);
    sendMessage(data);
    close();
    
    // Events
    on('data', callback);
    on('error', callback);
    on('listening', callback);
}

CFacade_Base Class

class CFacade_Base {
    // Abstract method to implement
    handleCommand(request);
    
    // Helper methods
    generateResponse(status, data);
    generateError(message, code);
    validateRequest(request);
}

Package Configuration

package.json

{
  "name": "droneengage-databus-nodejs",
  "version": "1.0.0",
  "description": "Node.js client for DroneEngage DataBus",
  "main": "client.js",
  "dependencies": {},
  "engines": {
    "node": ">=12.0.0"
  },
  "scripts": {
    "start": "node client.js",
    "test": "node test.js"
  }
}

Code Style

  • Variables: camelCase (e.g., moduleName, messageData)

  • Classes: PascalCase (e.g., CModule, CUDPClient)

  • Constants: UPPER_SNAKE_CASE (e.g., DEFAULT_PORT, MAX_PACKET_SIZE)

  • Files: snake_case (e.g., de_module.js, udp_client.js)

  • Functions: camelCase (e.g., sendMessage, handleCommand)

Error Handling

Comprehensive error handling with proper event emission:

try {
    await module.sendMessage(target, message);
} catch (error) {
    console.error('Failed to send message:', error);
    module.emit('error', error);
}

// Handle network errors
udpClient.on('error', (error) => {
    console.error('UDP Client error:', error);
    // Implement reconnection logic
});

Performance Considerations

Memory Management

  • Stream processing for large binary data

  • Buffer pooling for frequent allocations

  • Garbage collection optimization

Event Loop Optimization

  • Non-blocking I/O operations

  • Efficient event handling

  • Proper error propagation

Network Optimization

  • UDP buffer tuning

  • Chunk size optimization

  • Connection pooling

Debugging and Logging

Logging

Built-in colored console output:

const colors = require('./colors');

console.log(colors.info('Info message'));
console.log(colors.error('Error message'));
console.log(colors.success('Success message'));

Debug Mode

Enable debug output:

DEBUG=* node client.js MyModule

Integration Examples

Sensor Module Integration

const CModule = require('./de_module');
const { CMyFacade } = require('./my_facade');
const { TYPE_AndruavMessage_ServoChannel, NOTIFICATION_TYPE_INFO } = require('./messages');

class SensorFacade extends CMyFacade {
    constructor() {
        super();
        this.sensorData = {
            temperature: 0,
            humidity: 0,
            pressure: 0
        };
    }
    
    readSensorData() {
        // Simulate sensor reading
        this.sensorData.temperature = Math.random() * 30 + 20;
        this.sensorData.humidity = Math.random() * 40 + 30;
        this.sensorData.pressure = Math.random() * 50 + 1000;
        
        return this.sensorData;
    }
    
    sendTelemetry() {
        const data = this.readSensorData();
        this.sendJMSG('', {
            sensor_type: 'environmental',
            data: data,
            timestamp: Date.now()
        }, TYPE_AndruavMessage_ServoChannel, true);
    }
}

// Module setup
const cModule = new CModule();
const sensorFacade = new SensorFacade();
sensorFacade.setModule(cModule);

// Define module
cModule.defineModule(
    'gen',                    // MODULE_CLASS_GENERIC
    'EnvironmentalSensor',
    '123456789012',
    '1.0.0',
    [TYPE_AndruavMessage_ServoChannel]
);

// Add module features
cModule.addModuleFeatures('T');  // MODULE_FEATURE_SENDING_TELEMETRY
cModule.addModuleFeatures('R');  // MODULE_FEATURE_RECEIVING_TELEMETRY

// Initialize communication
cModule.init('0.0.0.0', 60000, '0.0.0.0', 61234, 8192);

// Start sensor data transmission
setInterval(() => {
    sensorFacade.sendTelemetry();
}, 1000);

console.log('Environmental Sensor Module RUNNING');

Servo Control Module

const CModule = require('./de_module');
const { CMyFacade } = require('./my_facade');
const { TYPE_AndruavMessage_ServoChannel, TYPE_AndruavMessage_RemoteExecute } = require('./messages');

class ServoFacade extends CMyFacade {
    constructor() {
        super();
        this.servoPositions = new Array(8).fill(1500); // 8 channels, center position
    }
    
    setServoChannel(channel, position) {
        if (channel >= 0 && channel < 8 && position >= 1000 && position <= 2000) {
            this.servoPositions[channel] = position;
            
            // Send servo command to drone
            this.sendJMSG('', {
                command: 'servo',
                channel: channel,
                position: position
            }, TYPE_AndruavMessage_ServoChannel, true);
            
            console.log(`Servo Channel ${channel} set to ${position}μs`);
        }
    }
    
    handleCommand(request) {
        if (request.command === 'set_servo') {
            this.setServoChannel(request.channel, request.position);
            return { status: 'success', message: 'Servo command executed' };
        }
        return { status: 'error', message: 'Unknown command' };
    }
}

// Module setup
const cModule = new CModule();
const servoFacade = new ServoFacade();
servoFacade.setModule(cModule);

// Define module
cModule.defineModule(
    'gen',                    // MODULE_CLASS_GENERIC
    'ServoController',
    '123456789013',
    '1.0.0',
    [TYPE_AndruavMessage_ServoChannel, TYPE_AndruavMessage_RemoteExecute]
);

// Add module features
cModule.addModuleFeatures('T');  // MODULE_FEATURE_SENDING_TELEMETRY
cModule.addModuleFeatures('R');  // MODULE_FEATURE_RECEIVING_TELEMETRY

// Initialize communication
cModule.init('0.0.0.0', 60000, '0.0.0.0', 61235, 8192);

// Example: Control servos based on commands
cModule.on('message', (message) => {
    if (message.type === TYPE_AndruavMessage_RemoteExecute) {
        servoFacade.handleCommand(message.data);
    }
});

console.log('Servo Control Module RUNNING');

See Also