dt-common-device
v13.3.5
Published
A secure and robust device management library for IoT applications
Maintainers
Readme
dt-common-device
A comprehensive TypeScript library for device management, supporting both cloud and local device operations with advanced event handling, queue management, and audit logging.
Installation
npm install dt-common-deviceEnvironment Variables Required
The following environment variables are REQUIRED for the library to function:
AWS Configuration
AWS_SECRET_ACCESS_KEY— Your AWS secret access keyAWS_REGION— Your AWS regionAWS_ACCESS_KEY_ID— Your AWS access key IDEVENT_BUS_NAME— Your AWS EventBridge event bus name
Database Configuration
ADMIN_DB_URI— PostgreSQL database connection URIMONGODB_URI— MongoDB database connection URI
Redis Configuration
REDIS_HOST— Redis server hostREDIS_PORT— Redis server port
Audit Logging
POSTHOG_API_KEY— Your PostHog API keyPOSTHOG_HOST— The PostHog host URL
SQS Configuration
SQS_QUEUE_URL— AWS SQS queue URL (configured during initialization)
Example .env file:
# AWS Configuration
AWS_SECRET_ACCESS_KEY=your_secret_key
AWS_REGION=us-east-1
AWS_ACCESS_KEY_ID=your_access_key
EVENT_BUS_NAME=your-event-bus
# Database Configuration
ADMIN_DB_URI=postgres://username:password@host:port/database
MONGODB_URI=mongodb://username:password@host:port/database
# Redis Configuration
REDIS_HOST=localhost
REDIS_PORT=6379
# Audit Logging
POSTHOG_API_KEY=your_posthog_key
POSTHOG_HOST=https://app.posthog.com
# SQS Configuration (will be set during initialization)
SQS_QUEUE_URL=https://sqs.region.amazonaws.com/account/queue-nameThe library will throw clear errors if any required environment variables are missing.
Initialization (Required)
Before using any service, you must call initialize() in your main entry file with the required configuration:
import { initialize } from "dt-common-device";
// Create a logger instance
const logger = {
info: (message: string, ...args: any[]) => console.log(message, ...args),
warn: (message: string, ...args: any[]) => console.warn(message, ...args),
error: (message: string, ...args: any[]) => console.error(message, ...args),
};
// Initialize the library
await initialize({
SOURCE: "ADMIN_SERVICE", // or "ACCESS_SERVICE" or "ENERGY_SERVICE"
SQS_QUEUE_URL: "https://sqs.region.amazonaws.com/account/queue-name",
DEVICE_SERVICE: "https://api.example.com/device", // Optional
ADMIN_SERVICE: "https://api.example.com/admin", // Optional
ACCESS_SERVICE: "https://api.example.com/access", // Optional
ENERGY_SERVICE: "https://api.example.com/energy", // Optional
INTERNAL_EVENT_HANDLER: {
// Your event handler implementation
handleEvent: async (event) => {
// Handle internal events
console.log("Handling event:", event);
},
},
LOGGER: logger,
});Configuration Options
SOURCE: Required. Must be one of:"ADMIN_SERVICE","ACCESS_SERVICE", or"ENERGY_SERVICE"SQS_QUEUE_URL: Required. Your AWS SQS queue URLDEVICE_SERVICE,ADMIN_SERVICE,ACCESS_SERVICE,ENERGY_SERVICE: Optional service URLsINTERNAL_EVENT_HANDLER: Required. Your event handler implementationLOGGER: Required. Logger instance with info, warn, and error methods
Available Services
Local Device Service
import { LocalDeviceService } from "dt-common-device";
const deviceService = new LocalDeviceService();
// Create a device
const device = await deviceService.createDevice(deviceBody);
// Get a device
const device = await deviceService.getDevice(deviceId);
// Get multiple devices
const devices = await deviceService.getDevices(deviceIds);
// Get devices by property
const propertyDevices = await deviceService.getPropertyDevices(propertyId);
// Update a device
await deviceService.updateDevice(deviceId, updateBody);
// Delete a device
await deviceService.deleteDevice(deviceId);
// State management
const state = await deviceService.getState(deviceId);
await deviceService.setState(deviceId, newState);
// Status management
const status = await deviceService.getStatus(deviceId);
await deviceService.setStatus(
deviceId,
newStatus,
"heartbeat",
"Device went offline due to network connectivity issues"
);
// Battery management
const battery = await deviceService.getBatteryLevel(deviceId);
await deviceService.setBatteryLevel(deviceId, batteryLevel, "heartbeat");
// Metadata management
const metadata = await deviceService.getMetaData(deviceId);
await deviceService.setMetaData(deviceId, metadata);
// Query operations
const devices = await deviceService.queryDevices(query);
const count = await deviceService.queryCount(query);
await deviceService.deleteDevices(query);Local Hub Service
import { LocalHubService } from "dt-common-device";
const hubService = new LocalHubService();
// Add a hub
const hub = await hubService.addHub(hubBody);
// Get hubs
const hubs = await hubService.getHubs(hubIds);
// Get a single hub
const hub = await hubService.getHub(hubId);
// Update a hub
await hubService.updateHub(hubId, updateBody);
// Get hub status
const status = await hubService.getStatus(hubId);
// Delete a hub
await hubService.deleteHub(hubId);
// Delete multiple hubs
await hubService.deleteAllHubs(hubIds);Local Schedule Service
import { LocalScheduleService } from "dt-common-device";
const scheduleService = new LocalScheduleService();
// Get a schedule
const schedule = await scheduleService.getSchedule(scheduleId);
// Set a schedule
await scheduleService.setSchedule(scheduleId, schedule);
// Get schedule by zone
const zoneSchedule = await scheduleService.getScheduleByZone(zoneId);Local Connection Service
import { LocalConnectionService } from "dt-common-device";
const connectionService = new LocalConnectionService();
// Create a connection
const connection = await connectionService.createConnection({
connectionName: "My Connection",
connectionRefId: "ref-123",
propertyId: "prop-456",
connectionProvider: "Sensibo",
});
// Get a connection
const connection = await connectionService.getConnection(connectionId);
// Update a connection
await connectionService.updateConnection(connectionId, updateData);Cloud Device Service
import { CloudDeviceService, DeviceFactory } from "dt-common-device";
const cloudService = new CloudDeviceService();
const deviceFactory = new DeviceFactory();
// Get cloud devices (must implement in your project)
// await cloudService.getDevices(connection);
// Get device using factory
const device = await deviceFactory.getDevice(deviceId);Property Service
import { PropertyService } from "dt-common-device";
const propertyService = new PropertyService();
// Property operations (implementation specific)
// await propertyService.getProperty(propertyId);Event System
The library includes a comprehensive event handling system:
import {
EventHandler,
EventProcessingService,
DeviceEventHandler,
EventHandlerOrchestrator,
} from "dt-common-device";
// Event handler for device operations
const eventHandler = new EventHandler();
// Device-specific event handler
const deviceEventHandler = new DeviceEventHandler();
// Event processing service
const eventProcessingService = new EventProcessingService();
// Event handler orchestrator
const orchestrator = new EventHandlerOrchestrator();Queue System
The library provides a hybrid HTTP queue system for managing HTTP requests:
import { QueueService } from "dt-common-device";
const queueService = new QueueService();
// Make a rate-limited HTTP request
const response = await queueService.request({
method: "GET",
url: "https://api.example.com/data",
headers: { "Content-Type": "application/json" },
queueOptions: {
connectionId: "connection-123",
connectionProvider: "Sensibo",
microservice: "smart-energy",
},
});Features
- Rate Limiting: Automatic rate limiting per provider and connection
- Retry Logic: Exponential backoff with configurable retry attempts
- Audit Logging: Automatic audit logging for all requests
- Queue Management: Redis-based queue with BullMQ
- Error Handling: Comprehensive error handling and logging
Alert and Issue Management
import {
AlertService,
IssueService,
AlertBuilder,
IssueBuilder,
} from "dt-common-device";
// Alert service
const alertService = new AlertService();
// Issue service
const issueService = new IssueService();
// Build alerts
const alert = new AlertBuilder()
.setTitle("Device Offline")
.setDescription("Device has been offline for more than 24 hours")
.setSeverity("HIGH")
.build();
// Build issues
const issue = new IssueBuilder()
.setTitle("Connection Failed")
.setDescription("Failed to connect to device")
.setPriority("HIGH")
.build();Graceful Shutdown
import { shutdown } from "dt-common-device";
// Gracefully shutdown the library
await shutdown();Importing Types and Interfaces
All types and interfaces are available as named exports:
import {
IDevice,
IHub,
IConnection,
ISchedule,
IProperty,
IAlert,
IIssue,
} from "dt-common-device";Dependencies
The library requires the following major dependencies:
axios: HTTP clientbullmq: Queue managementdt-audit-library: Audit loggingdt-pub-sub: Event publishing/subscribingioredis: Redis clientmongoose: MongoDB ODMpg: PostgreSQL clienttypedi: Dependency injection
Notes
- You must call
initialize()before using any service. If not, you will get a runtime error. - You must set
POSTHOG_API_KEYandPOSTHOG_HOSTin your environment before using any local device service. - You do not need to call
initializeAudit()
Rate Limiting
The queue system now implements intelligent rate limiting that delays requests instead of dropping them when rate limits are exceeded.
How it works
Rate Limit Check: Before processing each HTTP request, the system checks if the rate limit for the provider/connection combination has been exceeded.
Delay Instead of Drop: If the rate limit is exceeded, instead of immediately failing the request, the system:
- Calculates when the next request can be processed (after the rate limit window expires)
- Delays the job execution by the calculated time
- Re-checks the rate limit after the delay
- Only fails if still rate limited after the delay
Example Scenario:
Rate Limit: 5 requests per 60 seconds Timeline: 0s: Request 1 (processed immediately) 10s: Request 2 (processed immediately) 20s: Request 3 (processed immediately) 30s: Request 4 (processed immediately) 40s: Request 5 (processed immediately) 45s: Request 6 (delayed by 15s, processed at 60s) 50s: Request 7 (delayed by 10s, processed at 60s)
Configuration
Rate limits are configured per provider in src/queue/utils/rateLimit.utils.ts:
configs.set("Sensibo", {
maxRequests: 5, // Maximum requests allowed
windowMs: 60000, // Time window in milliseconds
provider: "Sensibo",
});Benefits
- No Lost Requests: Requests are delayed rather than dropped
- Automatic Recovery: System automatically processes delayed requests when rate limits reset
- Better User Experience: Users don't see immediate failures due to rate limits
- Audit Trail: All rate limit events are logged for monitoring
