UNPKG

matterbridge-aeg-robot

Version:

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

149 lines 5.75 kB
// Matterbridge plugin for AEG RX9 / Electrolux Pure i9 robot vacuum // Copyright © 2025 Alexander Thoukydides import { BasicInformation } from 'matterbridge/matter/clusters'; import { createHash } from 'node:crypto'; import { formatDateISO8601 } from './utils.js'; // Mapping from API colours to Matter ProductFinish equivalents const COLOUR_MAP = new Map([ ['DARKGOLD', BasicInformation.Color.Gold], ['INDIGOBLUE', BasicInformation.Color.Blue], ['MAHOGANYBRONZE', BasicInformation.Color.Brass], ['SHALEGREY', BasicInformation.Color.Gray], ['SILVER', BasicInformation.Color.Silver], ['SOFTSAND', BasicInformation.Color.Olive], ['SPACETEAL', BasicInformation.Color.Teal] ]); // PNCs for model names const FAMILY_MODEL_PNC = { // Electrolux models 'PURE i9': { 'PI91-5': ['900277343'], 'PI91-5SGM': ['900277252', '900277255', '900277258', '900277261', '900277264'], 'PI91-5MBM': ['900277253'], 'PI91-5SSM': ['900277267', '900277269', '900277271', '900277273', '900277292', '900277293'], 'PI91-5BSM': ['900277254'] }, 'PURE i9.2': { 'PI92-4STN': ['900277466'], 'PI92-4ANM': ['900277469'], 'PI92-6DGM': ['900277470'], 'PI92-6SGM': ['900277494'], 'PI92-6STN': ['900277491'] }, // AEG models 'RX9.1': { 'RX9-1-IBM': ['900277268'], 'RX9-1-SGM': ['900277283'] }, 'RX9.2': { 'RX9-2-6IBM': ['900277480', '900277486'], 'RX9-2-4STN': ['900277484', '900277478'], 'RX9-2-4ANM': ['900277479', '900277485'] } }; ; const PNC_FAMILY_MODEL_LIST = Object.entries(FAMILY_MODEL_PNC).flatMap(([family, models]) => Object.entries(models).flatMap(([model, pncs]) => pncs.map((pnc) => { return [pnc, { family, model }]; }))); const PNC_FAMILY_MODEL = new Map(PNC_FAMILY_MODEL_LIST); if (PNC_FAMILY_MODEL.size !== PNC_FAMILY_MODEL_LIST.length) { throw new Error('Duplicate PNCs in FAMILY_MODEL_PNC'); } // Translation of static appliance information to Matter attributes export class BabelStaticRX9 { log; config; appliance; // Construct a new translator constructor(log, config, appliance) { this.log = log; this.config = config; this.appliance = appliance; } // Generate a human-readable unique storage key get uniqueStorageKey() { // Avoid issues with redacted logs by using an opaque value return this.uniqueId; } // Use the Appliance ID to generate a 32-character opaque unique ID get uniqueId() { const { pnc, applianceId } = this.appliance; const hash = createHash('sha256').update(applianceId).digest('hex'); return `rx9-${pnc}-${hash}`.substring(0, 32); } // Human-readable name of the vendor for the node get vendorName() { return this.appliance.brand; } // Human-readable model name; attempt to map the PNC to its model number get productName() { const { model } = this.familyAndModel; return model ?? this.appliance.applianceType; } // User-defined name for the node (may be updated) get nodeLabel() { return this.appliance.applianceName; } // Version number of the hardware of the node get hardwareVersion() { return this.appliance.platform; } // Version number of the software running on the node get softwareVersion() { return this.appliance.state.firmwareVersion; } // Date that the node was manufactured; approximate using API appliance creation date get manufacturingDate() { const creationDate = new Date(this.appliance.created); return formatDateISO8601(creationDate, ''); } // Human-readable part number get partNumber() { return this.appliance.pnc; } // Human-readable model name; attempt to map the PNC to its family and colour // (this is intended to be a more user-friendly version of productName) get productLabel() { let { family } = this.familyAndModel; const { model, variant } = this.appliance; family ??= `${model.toUpperCase()}/${variant}`; return `${family} ${this.appliance.colour}`; } // Human-readable serial number get serialNumber() { return this.appliance.serialNumber; } // Description of the product's appearance get productAppearance() { // Map known colours to their Matter equivalents const primaryColor = COLOUR_MAP.get(this.appliance.colour); if (primaryColor === undefined) { warnUnrecognisedValue(this.log, 'colour', this.appliance.colour); return; } // Satin is the closest finish description supported by Matter const finish = BasicInformation.ProductFinish.Satin; return { finish, primaryColor }; } // Does the appliance support 'smart' power levels (RX9.2 only) get smartPowerCapable() { return this.appliance.capabilities.includes('PowerLevels'); } // Attempt to map the PNC to the model family and model number get familyAndModel() { const { pnc } = this.appliance; const familyModel = PNC_FAMILY_MODEL.get(pnc); if (!familyModel) warnUnrecognisedValue(this.log, 'PNC', pnc); return familyModel ?? {}; } } // Warn about unrecognised values const unrecognisedValues = new Map(); function warnUnrecognisedValue(log, type, value) { const warnedValues = unrecognisedValues.get(type) ?? new Set(); if (!warnedValues.has(value)) { log.warn(`Unrecognised ${type}: ${value}`); warnedValues.add(value); unrecognisedValues.set(type, warnedValues); } } //# sourceMappingURL=babel-static-rx9.js.map