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
JavaScript
// 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