UNPKG

matterbridge-aeg-robot

Version:

A Matterbridge plugin that connects AEG RX 9 / Electrolux Pure i9 robot vacuums to the Matter smart home ecosystem.

184 lines 7.99 kB
// Matterbridge plugin for AEG RX9 / Electrolux Pure i9 robot vacuum // 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-rx9.js'; import { assertIsDefined, assertIsInstanceOf, logError } from './utils.js'; // Robot Vacuum Cleaner Run Mode cluster modes export var RvcRunModeRX9; (function (RvcRunModeRX9) { RvcRunModeRX9[RvcRunModeRX9["Idle"] = 0] = "Idle"; RvcRunModeRX9[RvcRunModeRX9["Cleaning"] = 1] = "Cleaning"; })(RvcRunModeRX9 || (RvcRunModeRX9 = {})); // Robot Vacuum Cleaner Clean Mode cluster modes export var RvcCleanModeRX9; (function (RvcCleanModeRX9) { RvcCleanModeRX9[RvcCleanModeRX9["Quiet"] = 0] = "Quiet"; RvcCleanModeRX9[RvcCleanModeRX9["Smart"] = 1] = "Smart"; RvcCleanModeRX9[RvcCleanModeRX9["Power"] = 2] = "Power"; RvcCleanModeRX9[RvcCleanModeRX9["QuietSpot"] = 3] = "QuietSpot"; RvcCleanModeRX9[RvcCleanModeRX9["SmartSpot"] = 4] = "SmartSpot"; RvcCleanModeRX9[RvcCleanModeRX9["PowerSpot"] = 5] = "PowerSpot"; })(RvcCleanModeRX9 || (RvcCleanModeRX9 = {})); // Robot Vacuum Cleaner Operational State cluster operational states export var RvcOperationalStateRX9; (function (RvcOperationalStateRX9) { // 0x00~0x3F: General (Operational State) states RvcOperationalStateRX9[RvcOperationalStateRX9["Stopped"] = 0] = "Stopped"; RvcOperationalStateRX9[RvcOperationalStateRX9["Running"] = 1] = "Running"; RvcOperationalStateRX9[RvcOperationalStateRX9["Paused"] = 2] = "Paused"; RvcOperationalStateRX9[RvcOperationalStateRX9["Error"] = 3] = "Error"; // 0x40~0x7F: Derived cluster (RVC Operational State) states RvcOperationalStateRX9[RvcOperationalStateRX9["SeekingCharger"] = 64] = "SeekingCharger"; RvcOperationalStateRX9[RvcOperationalStateRX9["Charging"] = 65] = "Charging"; RvcOperationalStateRX9[RvcOperationalStateRX9["Docked"] = 66] = "Docked"; // 0x80~0xBF: Manufacturer states RvcOperationalStateRX9[RvcOperationalStateRX9["ManualSteering"] = 128] = "ManualSteering"; RvcOperationalStateRX9[RvcOperationalStateRX9["FirmwareUpgrade"] = 129] = "FirmwareUpgrade"; })(RvcOperationalStateRX9 || (RvcOperationalStateRX9 = {})); // OperationalStatus manufacturer error export const VENDOR_ERROR_RX9 = 0x80; // Command handling behaviour for the endpoint export class BehaviorDeviceRX9 { 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 BehaviorRX9 extends Behavior { static id = 'rx9'; } // eslint-disable-next-line @typescript-eslint/no-namespace (function (BehaviorRX9) { class State { device; } BehaviorRX9.State = State; })(BehaviorRX9 || (BehaviorRX9 = {})); // Implement command handlers for the RVC Run Mode cluster export class RvcRunModeServerRX9 extends RvcRunModeBehavior { // ChangeToMode command handler async changeToMode({ newMode }) { const { device } = this.agent.get(BehaviorRX9).state; const { log } = device; try { // Check whether it is a valid request log.info(`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 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 RvcCleanModeServerRX9 extends RvcCleanModeBehavior { // ChangeToMode command handler async changeToMode({ newMode }) { const { device } = this.agent.get(BehaviorRX9).state; const { log } = device; try { // Check whether it is a valid request log.info(`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 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 RvcOperationalStateServerRX9 extends RvcOperationalStateBehavior { static { const schema = RvcOperationalStateServerRX9.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 manufacturer-specific OperationalState values extendEnum('OperationalStateEnum', [ FieldElement({ name: 'ManualSteering', id: RvcOperationalStateRX9.ManualSteering, conformance: 'O', description: 'The device is being steered manually' }), FieldElement({ name: 'FirmwareUpgrade', id: RvcOperationalStateRX9.FirmwareUpgrade, conformance: 'O', description: 'The device firmware is being upgraded' }) ]); // Add manufacturer-specific ErrorState values extendEnum('ErrorStateEnum', [ FieldElement({ name: 'OtherError', id: VENDOR_ERROR_RX9, 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(BehaviorRX9).state; const { log } = device; try { log.info(`RVC Operational State command: ${command}`); await device.executeCommand(command); 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=behavior-rx9.js.map