UNPKG

matterbridge-dyson-robot

Version:

A Matterbridge plugin that connects Dyson robot vacuums and air treatment devices to the Matter smart home ecosystem via their local or cloud MQTT APIs.

156 lines 6.55 kB
// Matterbridge plugin for Dyson robot vacuum and air treatment devices // Copyright © 2025 Alexander Thoukydides import { Behavior } from 'matterbridge/matter'; import { ClusterModel, FieldElement } from 'matterbridge/matter'; import { RvcOperationalState } from 'matterbridge/matter/clusters'; import { RvcCleanModeBehavior, RvcOperationalStateBehavior, RvcRunModeBehavior } from 'matterbridge/matter/behaviors'; import { ChangeToModeError, RvcOperationalStateError } from './error-360.js'; import { assertIsDefined, assertIsInstanceOf, logError } from './utils.js'; // Robot Vacuum Cleaner Run Mode cluster modes export var RvcRunMode360; (function (RvcRunMode360) { RvcRunMode360[RvcRunMode360["Idle"] = 0] = "Idle"; RvcRunMode360[RvcRunMode360["Cleaning"] = 1] = "Cleaning"; RvcRunMode360[RvcRunMode360["Mapping"] = 2] = "Mapping"; })(RvcRunMode360 || (RvcRunMode360 = {})); // Robot Vacuum Cleaner Clean Mode cluster modes export var RvcCleanMode360; (function (RvcCleanMode360) { RvcCleanMode360[RvcCleanMode360["Quiet"] = 0] = "Quiet"; RvcCleanMode360[RvcCleanMode360["Quick"] = 1] = "Quick"; RvcCleanMode360[RvcCleanMode360["High"] = 2] = "High"; RvcCleanMode360[RvcCleanMode360["MaxBoost"] = 3] = "MaxBoost"; RvcCleanMode360[RvcCleanMode360["Auto"] = 4] = "Auto"; // Vis Nav: Auto })(RvcCleanMode360 || (RvcCleanMode360 = {})); // OperationalStatus manufacturer error export const VENDOR_ERROR_360 = 0x80; // Command handling behaviour for the endpoint export class BehaviorDevice360 { log; // Registered command handlers commands = {}; // Construct new command handling behaviour constructor(log) { this.log = log; } // Set a command handler setCommandHandler(command, handler) { if (this.commands[command]) throw new Error(`Handler already registered for command ${command}`); this.commands[command] = handler; } // Execute a command handler async executeCommand(command, ...args) { const handler = this.commands[command]; if (!handler) throw new Error(`${command} not implemented`); await handler(...args); } } export class Behavior360 extends Behavior { static id = 'dyson-rvc'; } // eslint-disable-next-line @typescript-eslint/no-namespace (function (Behavior360) { class State { device; } Behavior360.State = State; })(Behavior360 || (Behavior360 = {})); // Implement command handlers for the RVC Run Mode cluster export class RvcRunModeServer360 extends RvcRunModeBehavior { // ChangeToMode command handler async changeToMode({ newMode }) { const { device } = this.agent.get(Behavior360).state; const { log } = device; try { // Check whether it is a valid request log.debug(`RVC Run Mode command: ChangeToMode ${newMode}...`); const supported = this.state.supportedModes.some(({ mode }) => mode === newMode); if (!supported) throw new ChangeToModeError.UnsupportedMode; // Attempt to change the mode await device.executeCommand('ChangeRunMode', newMode); // Success log.debug(`RVC Run Mode command: ChangeToMode ${newMode} - OK`); return ChangeToModeError.toResponse(); } catch (err) { logError(log, 'RVC Run Mode ChangeToMode', err); return ChangeToModeError.toResponse(err); } } } // Implement command handlers for the RVC Clean Mode cluster export class RvcCleanModeServer360 extends RvcCleanModeBehavior { // ChangeToMode command handler async changeToMode({ newMode }) { const { device } = this.agent.get(Behavior360).state; const { log } = device; try { // Check whether it is a valid request log.debug(`RVC Clean Mode command: ChangeToMode ${newMode}...`); const supported = this.state.supportedModes.some(({ mode }) => mode === newMode); if (!supported) throw new ChangeToModeError.UnsupportedMode; // Attempt to change the mode await device.executeCommand('ChangeCleanMode', newMode); // Success log.debug(`RVC Clean Mode command: ChangeToMode ${newMode} - OK`); return ChangeToModeError.toResponse(); } catch (err) { logError(log, 'RVC Clean Mode ChangeToMode', err); return ChangeToModeError.toResponse(err); } } } // Implement command handlers for the RVC Operational State cluster export class RvcOperationalStateServer360 extends RvcOperationalStateBehavior { static { const schema = RvcOperationalStateServer360.schema; assertIsInstanceOf(schema, ClusterModel); const extendEnum = (name, values) => { const element = schema.datatypes.find(e => e.name === name); assertIsDefined(element); element.children = [...element.children, ...values]; }; // Add a manufacturer-specific ErrorState value extendEnum('ErrorStateEnum', [ FieldElement({ name: 'OtherError', id: VENDOR_ERROR_360, conformance: 'O', description: 'The device has an error that is not covered by the Matter-defined error states' }) ]); } // Common command handler async command(command, defaultErrorId) { const { device } = this.agent.get(Behavior360).state; const { log } = device; try { log.debug(`RVC Operational State command: ${command}...`); await device.executeCommand(command); log.debug(`RVC Operational State command: ${command} - OK`); return RvcOperationalStateError.toResponse(); } catch (err) { logError(log, `RVC Operational State ${command}`, err); return RvcOperationalStateError.toResponse(err, defaultErrorId); } } // Pause command handler pause() { return this.command('Pause', RvcOperationalState.ErrorState.CommandInvalidInState); } // Resume command handler resume() { return this.command('Resume', RvcOperationalState.ErrorState.UnableToStartOrResume); } // GoHome command handler goHome() { return this.command('GoHome', RvcOperationalState.ErrorState.CommandInvalidInState); } } //# sourceMappingURL=endpoint-360-behavior.js.map