matterbridge-aeg-robot
Version:
A Matterbridge plugin that connects AEG RX 9 / Electrolux Pure i9 robot vacuums to the Matter smart home ecosystem.
252 lines • 11.3 kB
JavaScript
// Matterbridge plugin for AEG RX9 / Electrolux Pure i9 robot vacuum
// Copyright © 2025 Alexander Thoukydides
import { bridgedNode, MatterbridgeEndpoint, powerSource, roboticVacuumCleaner } from 'matterbridge';
import { BridgedDeviceBasicInformationServer, PowerSourceServer } from 'matterbridge/matter/behaviors';
import { PowerSource, RvcCleanMode, RvcRunMode } from 'matterbridge/matter/clusters';
import { BehaviorDeviceRX9, BehaviorRX9, RvcCleanModeRX9, RvcCleanModeServerRX9, RvcOperationalStateRX9, RvcOperationalStateServerRX9, RvcRunModeRX9, RvcRunModeServerRX9 } from './behavior-rx9.js';
import { PLUGIN_URL } from './settings.js';
import { RvcOperationalStateError } from './error-rx9.js';
// A Matterbridge endpoint with robot vacuum cleaner clusters
export class EndpointRX9 extends MatterbridgeEndpoint {
config;
information;
// Command handlers
behaviorDeviceRX9;
// Construct a new endpoint
constructor(log, config, information) {
const definition = [roboticVacuumCleaner, bridgedNode, powerSource];
const debug = config.debugFeatures.includes('Log Endpoint Debug');
super(definition, { uniqueStorageKey: information.uniqueStorageKey }, debug);
this.config = config;
this.information = information;
// Use supplied logger instead of the one created by the base class
this.log = log;
// Create the clusters
this.createDefaultIdentifyClusterServer()
.createBridgedDeviceBasicInformationClusterServer()
.createPowerSourceClusterServer()
.createRvcRunModeClusterServer()
.createRvcCleanModeClusterServer()
.createRvcOperationalStateClusterServer();
// Add a command handler behavior
this.behaviorDeviceRX9 = new BehaviorDeviceRX9(this.log);
this.behaviors.require(BehaviorRX9, { device: this.behaviorDeviceRX9 });
}
// Create the Bridged Device Basic Information cluster
createBridgedDeviceBasicInformationClusterServer() {
// Copy of values (possibly) required by Matterbridge
this.deviceName = this.information.nodeLabel;
this.serialNumber = this.information.serialNumber;
this.uniqueId = this.information.uniqueId;
this.productId = undefined;
this.productName = this.information.productName;
this.vendorId = undefined;
this.vendorName = this.information.vendorName;
this.softwareVersion = parseInt(this.information.softwareVersion, 10);
this.softwareVersionString = this.information.softwareVersion;
this.hardwareVersion = parseInt(this.information.hardwareVersion, 10);
this.hardwareVersionString = this.information.hardwareVersion;
// Create the cluster
this.behaviors.require(BridgedDeviceBasicInformationServer.enable({
events: {
leave: true,
reachableChanged: true
}
}), {
// Constant attributes
uniqueId: this.information.uniqueId.substring(0, 32),
vendorName: this.information.vendorName.substring(0, 32),
productName: this.information.productName.substring(0, 32),
nodeLabel: this.information.nodeLabel.substring(0, 32),
hardwareVersion: parseInt(this.information.hardwareVersion, 10),
hardwareVersionString: this.information.hardwareVersion.substring(0, 64),
manufacturingDate: this.information.manufacturingDate,
partNumber: this.information.partNumber.substring(0, 32),
productUrl: PLUGIN_URL,
productLabel: this.information.productLabel.substring(0, 64),
serialNumber: this.information.serialNumber.substring(0, 32),
productAppearance: this.information.productAppearance,
// Variable attributes
reachable: true,
softwareVersion: parseInt(this.information.softwareVersion, 10),
softwareVersionString: this.information.softwareVersion.substring(0, 64),
// Unsupported attributes (no certified AEG/Electrolux Matter products)
vendorId: undefined,
productId: undefined
});
return this;
}
// Create the Power Source cluster for the rechargeable battery
createPowerSourceClusterServer() {
this.behaviors.require(PowerSourceServer.withFeatures(PowerSource.Feature.Battery, PowerSource.Feature.Rechargeable, PowerSource.Feature.Replaceable), {
// Constant attributes
order: 0,
description: 'Primary Batteries',
batReplacementNeeded: false,
batPresent: true,
batReplaceability: PowerSource.BatReplaceability.UserReplaceable,
batReplacementDescription: 'Electrolux OSBP72L125 / AEG OSBP72LI (2 × 7.2V Li-ion)',
batApprovedChemistry: PowerSource.BatApprovedChemistry.LithiumIon,
batCapacity: 2500, // 18Wh at 7.2V = 2.5Ah
batQuantity: 2,
batFunctionalWhileCharging: false,
endpointList: [],
// Variable attributes (with dummy defaults)
status: PowerSource.PowerSourceStatus.Active,
batPercentRemaining: null,
batChargeLevel: PowerSource.BatChargeLevel.Ok,
batChargeState: PowerSource.BatChargeState.Unknown,
// Unsupported attributes
batVoltage: null,
batTimeRemaining: undefined,
activeBatFaults: undefined,
batCommonDesignation: undefined,
batAnsiDesignation: undefined,
batIecDesignation: undefined,
batTimeToFullCharge: undefined,
batChargingCurrent: undefined,
activeBatChargeFaults: undefined
});
return this;
}
// Create the RVC Run Mode cluster
createRvcRunModeClusterServer() {
this.behaviors.require(RvcRunModeServerRX9.enable({
commands: {
changeToMode: true
}
}), {
// Constant attributes
supportedModes: [{
label: 'Idle',
mode: RvcRunModeRX9.Idle,
modeTags: [{ value: RvcRunMode.ModeTag.Idle }]
}, {
label: 'Cleaning',
mode: RvcRunModeRX9.Cleaning,
modeTags: [{ value: RvcRunMode.ModeTag.Cleaning }]
}],
// Variable attributes (with dummy defaults)
currentMode: RvcRunModeRX9.Idle
});
return this;
}
// Create the RVC Clean Mode cluster
createRvcCleanModeClusterServer() {
const tag = RvcCleanMode.ModeTag;
this.behaviors.require(RvcCleanModeServerRX9.enable({
commands: {
changeToMode: true
}
}), {
// Constant attributes
supportedModes: [{
label: 'Quiet Cleaning',
mode: RvcCleanModeRX9.Quiet,
modeTags: [
{ value: tag.Vacuum },
{ value: tag.Quiet },
{ value: tag.LowNoise },
{ value: tag.LowEnergy },
{ value: tag.Min }
]
}, {
label: 'Smart Cleaning',
mode: RvcCleanModeRX9.Smart,
modeTags: [
{ value: tag.Vacuum },
{ value: tag.Auto }
]
}, {
label: 'Power Cleaning',
mode: RvcCleanModeRX9.Power,
modeTags: [
{ value: tag.Vacuum },
{ value: tag.Max },
{ value: tag.DeepClean }
]
}, {
label: 'Quiet Spot Cleaning',
mode: RvcCleanModeRX9.QuietSpot,
modeTags: [
{ value: tag.Vacuum },
{ value: tag.Quick },
{ value: tag.Quiet },
{ value: tag.LowNoise },
{ value: tag.LowEnergy },
{ value: tag.Min }
]
}, {
label: 'Smart Spot Cleaning',
mode: RvcCleanModeRX9.SmartSpot,
modeTags: [
{ value: tag.Vacuum },
{ value: tag.Quick },
{ value: tag.Auto }
]
}, {
label: 'Power Spot Cleaning',
mode: RvcCleanModeRX9.PowerSpot,
modeTags: [
{ value: tag.Vacuum },
{ value: tag.Quick },
{ value: tag.Max },
{ value: tag.DeepClean }
]
}].filter(mode => this.information.smartPowerCapable || mode.modeTags.some(t => t.value !== tag.Auto)),
// Variable attributes (with dummy defaults)
currentMode: RvcCleanModeRX9.Quiet
});
return this;
}
// Create the RVC Operational State cluster
createRvcOperationalStateClusterServer() {
this.behaviors.require(RvcOperationalStateServerRX9.enable({
events: {
operationalError: true,
operationCompletion: true
}, commands: {
pause: true,
resume: true,
goHome: true
}
}), {
// Constant attributes
operationalStateList: [{
operationalStateId: RvcOperationalStateRX9.Stopped
}, {
operationalStateId: RvcOperationalStateRX9.Running
}, {
operationalStateId: RvcOperationalStateRX9.Paused
}, {
operationalStateId: RvcOperationalStateRX9.Error
}, {
operationalStateId: RvcOperationalStateRX9.SeekingCharger
}, {
operationalStateId: RvcOperationalStateRX9.Charging
}, {
operationalStateId: RvcOperationalStateRX9.Docked
}, {
operationalStateId: RvcOperationalStateRX9.ManualSteering,
operationalStateLabel: 'Manual Steering'
}, {
operationalStateId: RvcOperationalStateRX9.FirmwareUpgrade,
operationalStateLabel: 'Firmware Upgrade'
}],
// Variable attributes (with dummy defaults)
operationalState: RvcOperationalStateRX9.Stopped,
operationalError: RvcOperationalStateError.toStruct(),
// Unsupported attributes
phaseList: null,
currentPhase: null,
countdownTime: null
});
return this;
}
// Set a command handler
setCommandHandlerRX9(command, handler) {
this.behaviorDeviceRX9.setCommandHandler(command, handler);
return this;
}
}
//# sourceMappingURL=endpoint-rx9.js.map