UNPKG

matterbridge-roborock-vacuum-plugin

Version:
161 lines 7.32 kB
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