m2-inno-bedpressure/services/BedHardware.ts
Siwat Sirichai fb87e74ec9 feat: Refactor BedHardware to support both Serial and MQTT implementations
- Added MQTT support to BedHardware, allowing for connection to MQTT brokers.
- Created BedHardwareMQTT and BedHardwareSerial classes to handle respective connections.
- Introduced a unified BedHardwareConfig interface for configuration management.
- Implemented event forwarding from the underlying implementations to the BedHardware class.
- Added MQTT adapter for handling MQTT connections and message subscriptions.
- Updated package.json to include the mqtt library as a dependency.
- Created a singleton MQTTService for managing MQTT client instances.
- Enhanced error handling and logging throughout the BedHardware and MQTT classes.
2025-06-21 14:55:10 +07:00

126 lines
No EOL
3.3 KiB
TypeScript

import { EventEmitter } from 'events';
import { IBedHardware, PinState, PinChange, BedHardwareConfig } from '../types/bedhardware';
import { BedHardwareSerial } from './BedHardwareSerial';
import { BedHardwareMQTT } from './BedHardwareMQTT';
/**
* BedHardware - Factory class for creating bed hardware implementations
*
* Usage:
* // MQTT (connects to broker.hivemq.com with base topic /Jtkcp2N/pressurebed/)
* const hardware = BedHardware.createSimpleMQTT();
*
* // Serial
* const hardware = BedHardware.createSerial('COM3', 9600);
*
* // With custom topics
* const hardware = BedHardware.createMQTT({
* topics: {
* pinState: '/custom/pin/state',
* pinChange: '/custom/pin/change',
* initialization: '/custom/init'
* }
* });
*/
export class BedHardware extends EventEmitter implements IBedHardware {
private implementation: IBedHardware;
constructor(config: BedHardwareConfig) {
super();
if (config.type === 'serial') {
if (!config.serial?.portPath) {
throw new Error('Serial port path is required for serial connection');
}
this.implementation = new BedHardwareSerial(
config.serial.portPath,
config.serial.baudRate || 9600 );
} else if (config.type === 'mqtt') {
this.implementation = new BedHardwareMQTT({
topics: config.mqtt?.topics
});
} else {
throw new Error(`Unsupported hardware type: ${config.type}`);
}
// Forward all events from the implementation
this.forwardEvents();
}
private forwardEvents(): void {
const events = [
'connected',
'disconnected',
'error',
'initialized',
'pinInitialized',
'pinChanged'
];
events.forEach(event => {
this.implementation.on(event, (...args: unknown[]) => {
this.emit(event, ...args);
});
});
// Forward dynamic pin events (pin{number}Changed)
this.implementation.on('pinChanged', (pinChange: PinChange) => {
this.emit(`pin${pinChange.pin}Changed`, pinChange);
});
}
async connect(): Promise<void> {
return this.implementation.connect();
}
async disconnect(): Promise<void> {
return this.implementation.disconnect();
}
getPinState(pin: number): PinState | undefined {
return this.implementation.getPinState(pin);
}
getAllPinStates(): PinState[] {
return this.implementation.getAllPinStates();
}
isConnected(): boolean {
return this.implementation.isConnected();
}
// Static factory methods for convenience
static createSerial(portPath: string, baudRate: number = 9600): BedHardware {
return new BedHardware({
type: 'serial',
serial: { portPath, baudRate }
});
} static createMQTT(config?: {
topics?: {
pinState: string;
pinChange: string;
initialization: string;
};
}): BedHardware {
return new BedHardware({
type: 'mqtt',
mqtt: config
});
}
static createSimpleMQTT(): BedHardware {
return new BedHardware({
type: 'mqtt',
mqtt: {}
});
}
// Static method to list available serial ports (for serial implementation)
static async listSerialPorts(): Promise<string[]> {
return BedHardwareSerial.listPorts();
}
}
// Export all classes for direct access if needed
export { BedHardwareSerial, BedHardwareMQTT };
export * from '../types/bedhardware';