matterbridge-roborock-vacuum-plugin
Version:
Matterbridge Roborock Vacuum Plugin
161 lines • 7.32 kB
JavaScript
import Path from 'node:path';
import { MatterbridgeDynamicPlatform } from 'matterbridge';
import NodePersist from 'node-persist';
import { DEFAULT_REFRESH_INTERVAL_SECONDS, REFRESH_INTERVAL_BUFFER_MS, UNREGISTER_DEVICES_DELAY_MS, } from './constants/index.js';
import { DeviceConfigurator } from './platform/deviceConfigurator.js';
import { DeviceDiscovery } from './platform/deviceDiscovery.js';
// Platform layer imports
import { DeviceRegistry } from './platform/deviceRegistry.js';
import { PlatformConfigManager } from './platform/platformConfigManager.js';
import { PlatformState } from './platform/platformState.js';
import { PlatformRunner } from './platformRunner.js';
import { PLUGIN_NAME } from './settings.js';
import { checkDependencyVersions } from './share/dependency-check.js';
import { FilterLogger } from './share/filterLogger.js';
import { getWssSendSnackbarMessage } from './types/WssSendSnackbarMessage.js';
export default function initializePlugin(matterbridge, log, config) {
return new RoborockMatterbridgePlatform(matterbridge, log, config);
}
/**
* Roborock vacuum platform for Matterbridge.
* Orchestrates device discovery, configuration, and lifecycle management.
*/
export class RoborockMatterbridgePlatform extends MatterbridgeDynamicPlatform {
config;
platformRunner;
persist;
// Platform layer
registry;
configManager;
discovery;
configurator;
state;
rvcInterval;
snackbarMessage;
get roborockService() {
return this.discovery.roborockService;
}
set roborockService(value) {
this.discovery.roborockService = value;
}
get rrHomeId() {
return this.configurator.rrHomeId;
}
set rrHomeId(value) {
this.configurator.rrHomeId = value;
}
constructor(matterbridge, logger, config) {
super(matterbridge, new FilterLogger(logger, config.pluginConfiguration.sanitizeSensitiveLogs), config);
this.config = config;
logger.logLevel = this.config.pluginConfiguration.debug ? "debug" /* LogLevel.DEBUG */ : "info" /* LogLevel.INFO */;
checkDependencyVersions(this);
this.log.info('Initializing platform:', this.config.name);
// Initialize persistence
const persistDir = Path.join(this.matterbridge.matterbridgePluginDirectory, PLUGIN_NAME, 'persist');
this.persist = NodePersist.create({ dir: persistDir });
// Initialize platform layer
this.configManager = PlatformConfigManager.create(config, this.log);
this.registry = new DeviceRegistry();
this.state = new PlatformState();
this.platformRunner = new PlatformRunner(this);
// Create discovery and configurator
this.snackbarMessage = getWssSendSnackbarMessage(this);
this.discovery = new DeviceDiscovery(this, this.configManager, this.registry, () => this.persist, this.snackbarMessage, this.log);
this.configurator = new DeviceConfigurator(this, this.configManager, this.registry, () => this.platformRunner, this.snackbarMessage, this.log);
}
// #region Lifecycle
async onStart(reason) {
this.log.notice('onStart called with reason:', reason ?? 'none');
await this.ready;
await this.clearSelect();
await this.persist.init();
if (this.configManager.isClearStorageOnStartupEnabled) {
return;
}
if (this.configManager.alwaysExecuteAuthentication) {
await this.persist.clear();
}
if (!this.configManager.validateConfig()) {
this.log.error('"username" (email address) is required in the config');
this.snackbarMessage('"username" (email address) is required in the config', 5000, 'error');
this.state.setStartupCompleted(false);
return;
}
const shouldContinue = await this.discovery.discoverDevices();
if (!shouldContinue) {
this.log.error('Device discovery failed to start.');
this.state.setStartupCompleted(false);
return;
}
if (!this.discovery.roborockService) {
this.log.error('Initializing: RoborockService is undefined');
this.state.setStartupCompleted(false);
return;
}
await this.configurator.onConfigureDevice(this.discovery.roborockService);
this.log.notice('onStart finished');
this.state.setStartupCompleted(true);
}
async onConfigure() {
await super.onConfigure();
this.log.notice('onConfigure called');
if (this.configManager.isClearStorageOnStartupEnabled) {
this.log.warn('Clearing persistence storage as per configuration.');
await this.persist
.clear()
.then(() => this.unregisterAllDevices(UNREGISTER_DEVICES_DELAY_MS))
.then(() => {
this.log.notice('Please restart the platform now.');
this.snackbarMessage('Clear persistence storage as per configuration completed. Please restart the platform now.', 5000, 'success');
this.wssSendRestartRequired();
})
.then(() => {
const config = this.configManager.rawConfig;
config.authentication.verificationCode = '';
config.advancedFeature.settings.clearStorageOnStartup = false;
return this.onConfigChanged(config);
})
.catch((error) => {
this.log.error(`Error clearing persistence storage: ${error}`);
});
}
if (!this.state.isStartupCompleted) {
return;
}
const intervalMs = (this.configManager.refreshInterval ?? DEFAULT_REFRESH_INTERVAL_SECONDS) * 1000 + REFRESH_INTERVAL_BUFFER_MS;
this.rvcInterval = setInterval(async () => {
try {
await this.platformRunner.requestHomeData();
}
catch (error) {
this.log.error(`requestHomeData (interval) failed: ${error instanceof Error ? error.message : String(error)}`);
}
}, intervalMs);
this.snackbarMessage('Roborock Vacuum Plugin is ready', 5000, 'success');
if (this.configManager.isEmailNotificationEnabled && this.discovery.roborockService) {
await this.discovery.roborockService.sendTestEmailNotification();
}
}
async onShutdown(reason) {
await super.onShutdown(reason);
this.log.notice('onShutdown called with reason:', reason ?? 'none');
if (this.rvcInterval) {
clearInterval(this.rvcInterval);
this.rvcInterval = undefined;
}
this.platformRunner.burstPolling.stopAllBurstPolling();
if (this.roborockService) {
this.roborockService.stopService();
this.roborockService = undefined;
}
if (this.configManager.unregisterOnShutdown) {
await this.unregisterAllDevices(UNREGISTER_DEVICES_DELAY_MS);
}
this.state.setStartupCompleted(false);
}
async onChangeLoggerLevel(logLevel) {
this.log.notice(`Change ${PLUGIN_NAME} log level: ${logLevel} (was ${this.log.logLevel})`);
this.log.logLevel = logLevel;
}
}
//# sourceMappingURL=module.js.map