matterbridge-roborock-vacuum-plugin
Version:
Matterbridge Roborock Vacuum Plugin
131 lines • 7.06 kB
JavaScript
import { RoboticVacuumCleaner } from 'matterbridge/devices';
import { debugStringify } from 'matterbridge/logger';
import { RvcOperationalState } from 'matterbridge/matter/clusters';
import { CommandNames } from '../behaviors/BehaviorDeviceGeneric.js';
import { baseRunModeConfigs, getRunModeOptions } from '../behaviors/roborock.vacuum/core/runModeConfig.js';
import { getOperationalStates, getSupportedAreas, getSupportedCleanModes, getSupportedRoutines, } from '../initialData/index.js';
export class RoborockVacuumCleaner extends RoboticVacuumCleaner {
device;
homeInFo;
dockStationStatus;
cleanModeSetting;
/**
* Create a new Roborock Vacuum Cleaner device.
* Initializes the device with supported cleaning modes, run modes, areas, and routines.
*/
constructor(device, homeInFo, configManager, roborockService, log) {
const deviceConfig = RoborockVacuumCleaner.initializeDeviceConfiguration(device, homeInFo, configManager, roborockService, log);
super(deviceConfig.deviceName, device.sn ?? device.duid, deviceConfig.bridgeMode, deviceConfig.runModeConfigs[0].mode, deviceConfig.runModeConfigs, deviceConfig.cleanModes[0].mode, deviceConfig.cleanModes, undefined, undefined, RvcOperationalState.OperationalState.Docked, deviceConfig.operationalState, deviceConfig.supportedAreaAndRoutines, undefined, deviceConfig.supportedAreas[0].areaId, deviceConfig.supportedMaps);
this.device = device;
this.homeInFo = homeInFo;
log.debug(`Creating RoborockVacuumCleaner for device: ${deviceConfig.deviceName},
model: ${device.specs.model},
forceRunAtDefault: ${configManager.forceRunAtDefault}
bridgeMode: ${deviceConfig.bridgeMode},
Supported Clean Modes: ${debugStringify(deviceConfig.cleanModes)},
Supported Areas: ${debugStringify(deviceConfig.supportedAreas)},
Supported Maps: ${debugStringify(deviceConfig.supportedMaps)}
Supported Areas and Routines: ${debugStringify(deviceConfig.supportedAreaAndRoutines)},
Supported Operational States: ${debugStringify(deviceConfig.operationalState)}`);
}
/**
* Configure command handlers for the vacuum device.
* Sets up handlers for identify, area selection, mode changes, and cleaning operations.
*/
configureHandler(behaviorHandler) {
this.addCommandHandlerWithErrorHandling(CommandNames.IDENTIFY, async ({ request, cluster, attributes, endpoint }) => {
this.log.info(`Identify command received for endpoint ${endpoint}, cluster ${cluster}, attributes ${debugStringify(attributes)}, request: ${JSON.stringify(request)}`);
behaviorHandler.executeCommand(CommandNames.IDENTIFY, request.identifyTime ?? 5);
});
this.addCommandHandlerWithErrorHandling(CommandNames.SELECT_AREAS, async ({ request }) => {
const { newAreas } = request;
if (!newAreas || newAreas.length === 0) {
this.log.info('selectAreas called with empty or undefined areas, it means selecting no areas or all areas, ignoring.');
return;
}
this.log.info(`Selecting areas: ${newAreas.join(', ')}`);
behaviorHandler.executeCommand(CommandNames.SELECT_AREAS, newAreas);
});
this.addCommandHandlerWithErrorHandling(CommandNames.CHANGE_TO_MODE, async ({ request }) => {
const { newMode } = request;
this.log.info(`Changing to mode: ${newMode}`);
behaviorHandler.executeCommand(CommandNames.CHANGE_TO_MODE, newMode);
});
this.addCommandHandlerWithErrorHandling(CommandNames.PAUSE, async () => {
this.log.info('Pause command received');
behaviorHandler.executeCommand(CommandNames.PAUSE);
});
this.addCommandHandlerWithErrorHandling(CommandNames.RESUME, async () => {
this.log.info('Resume command received');
behaviorHandler.executeCommand(CommandNames.RESUME);
});
this.addCommandHandlerWithErrorHandling(CommandNames.GO_HOME, async () => {
this.log.info('GoHome command received');
behaviorHandler.executeCommand(CommandNames.GO_HOME);
});
this.addCommandHandlerWithErrorHandling(CommandNames.STOP, async () => {
this.log.info('Stop command received');
behaviorHandler.executeCommand(CommandNames.STOP);
});
}
/**
* Initialize device configuration including modes, areas, and maps.
*/
static initializeDeviceConfiguration(device, homeInFo, configManager, roborockService, log) {
const cleanModes = getSupportedCleanModes(device.specs.model, configManager);
const operationalState = getOperationalStates();
const result = getSupportedAreas(homeInFo, log);
const supportedMaps = result.supportedMaps;
let supportedAreas = result.supportedAreas;
const runModeConfigs = getRunModeOptions(baseRunModeConfigs);
const bridgeMode = configManager.isServerModeEnabled ? 'server' : 'matter';
const firstSupportedMap = supportedMaps.length > 0 ? supportedMaps[0] : undefined;
if (!configManager.isMultipleMapEnabled) {
supportedMaps.splice(1); // Keep only the first map
supportedAreas = supportedAreas.filter((area) => area.mapId === firstSupportedMap?.mapId);
}
let routineAsRooms = [];
if (configManager.showRoutinesAsRoom) {
routineAsRooms = getSupportedRoutines(device.scenes ?? [], log);
roborockService.setSupportedRoutines(device.duid, routineAsRooms);
}
// temporary use map id 999 for routine
if (routineAsRooms.length > 0) {
const mapForRoutine = { mapId: 999, name: 'Routine' };
supportedMaps.push(mapForRoutine);
routineAsRooms.forEach((rt) => {
rt.mapId = 999;
});
}
roborockService.setSupportedAreas(device.duid, result.supportedAreas);
roborockService.setSupportedAreaIndexMap(device.duid, result.roomIndexMap);
const supportedAreaAndRoutines = [...supportedAreas, ...routineAsRooms];
const deviceName = device.name;
return {
deviceName,
bridgeMode,
cleanModes,
runModeConfigs,
supportedAreas,
supportedMaps,
supportedAreaAndRoutines,
operationalState,
};
}
/**
* Helper method to add command handler with error handling.
* Wraps handler logic in try-catch to avoid code duplication.
*/
addCommandHandlerWithErrorHandling(commandName, handler) {
this.addCommandHandler(commandName, async (context) => {
try {
await handler(context);
}
catch (error) {
this.log.error(`Error executing ${commandName} command: ${error}`);
throw error;
}
});
}
}
//# sourceMappingURL=roborockVacuumCleaner.js.map