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.

130 lines (126 loc) 6.71 kB
// Matterbridge plugin for Dyson robot vacuum and air treatment devices // Copyright © 2025-2026 Alexander Thoukydides import { BasicInformation } from 'matterbridge/matter/clusters'; import { RvcCleanMode360 } from './endpoint-360-behavior.js'; import { Dyson360CleaningStrategy, Dyson360EyePowerMode, Dyson360HeuristPowerMode, Dyson360TimelineEvent } from './dyson-360-types.js'; import { DysonDevice360Base } from './dyson-device-360-base.js'; import { DysonDevice360ZonesMixin } from './dyson-device-360-zones.js'; import { dysonRenderMap360Eye, dysonRenderMap360VisNav } from './dyson-device-360-map.js'; /* eslint-disable max-len */ // Common instructions for compatibility warning messages const DYSON360_COMPATIBILITY_COMMON = `If you are willing to help add support, please follow the detailed instructions in the project README.md for contributing opendyson logs and Proxyman API traces: https://github.com/thoukydides/matterbridge-dyson-robot#reporting-issues (expand the "Reporting Issues with Unsupported or Recently Released Products" section)`; // Device-specific compatibility warning messages const DYSON360_COMPATIBILITY_HEURIST = `Support for Dyson 360 Heurist (RB02) is incomplete. The device is currently treated similarly to a Dyson 360 Eye, with partial updates for known MQTT differences. There is a high likelihood of warnings, errors, or missing functionality. Mapping and zone cleaning are not currently supported. ${DYSON360_COMPATIBILITY_COMMON}`; const DYSON360_COMPATIBILITY_SPOTSCRUB = `Dyson Spot+Scrub Ai (RB05) is not currently supported by this plugin. Initialisation is expected to fail, and no functionality is implemented for this model. This is not a regression and does not indicate a configuration error. ${DYSON360_COMPATIBILITY_COMMON}`; /* eslint-enable max-len */ // A Dyson 360 Eye device export class DysonDevice360Eye extends DysonDevice360Base { static model = { type: 'N223', number: 'RB01', name: '360 Eye' }; getBatteryPartNumber = () => '968734-02'; getProductAppearance = () => ({ finish: BasicInformation.ProductFinish.Polished, primaryColor: BasicInformation.Color.Nickel // (or Fuchsia for Japan limited edition) }); getPowerLevelMaps = () => [ [Dyson360EyePowerMode.Quiet, RvcCleanMode360.Quiet, 'Quiet'], [Dyson360EyePowerMode.Max, RvcCleanMode360.MaxBoost, 'Max'] ]; setPowerLevel = (powerLevel) => this.mqtt.commandSetPowerMode(powerLevel); getPowerLevel = () => this.mqtt.status.defaultVacuumPowerMode; // Retrieve details of a completed clean async getCompletedClean(cleanId) { const { logMapStyle } = this.config; if (!this.api || logMapStyle === 'Off') return 'Unavailable'; // Retrieve details of the specified (or most recent) clean const history = await this.api.getCleaningHistory360(); const clean = history.Entries.find(entry => entry.Clean === cleanId); if (!clean) return 'Not found'; if (clean.IsInterim) return 'Not ready'; const map = await this.api.getMapImage360(cleanId); // Render the Map return dysonRenderMap360Eye(this.log, logMapStyle, clean, map); } } // A Dyson 360 Heurist device export class DysonDevice360Heurist extends DysonDevice360Base { static model = { type: '276', number: 'RB02', name: '360 Heurist' }; getBatteryPartNumber = () => '970049-01'; getProductAppearance = () => ({ finish: BasicInformation.ProductFinish.Satin, primaryColor: BasicInformation.Color.Blue }); getPowerLevelMaps = () => [ [Dyson360HeuristPowerMode.Quiet, RvcCleanMode360.Quiet, 'Quiet'], [Dyson360HeuristPowerMode.High, RvcCleanMode360.High, 'High'], [Dyson360HeuristPowerMode.Max, RvcCleanMode360.MaxBoost, 'Max'] ]; setPowerLevel = (powerLevel) => this.mqtt.commandSetPowerMode(powerLevel); getPowerLevel = () => this.mqtt.status.defaultVacuumPowerMode; get compatibilityWarning() { return DYSON360_COMPATIBILITY_HEURIST; } } // A Dyson 360 Vis Nav device export class DysonDevice360VisNav extends DysonDevice360ZonesMixin(DysonDevice360Base) { static model = { type: '277', number: 'RB03', name: '360 Vis Nav' }; getBatteryPartNumber = () => '967864-02'; getProductAppearance = () => ({ finish: BasicInformation.ProductFinish.Satin, primaryColor: BasicInformation.Color.Blue }); getPowerLevelMaps = () => [ [Dyson360CleaningStrategy.Auto, RvcCleanMode360.Auto, 'Auto'], [Dyson360CleaningStrategy.Quick, RvcCleanMode360.Quick, 'Quick'], [Dyson360CleaningStrategy.Quiet, RvcCleanMode360.Quiet, 'Quiet'], [Dyson360CleaningStrategy.Boost, RvcCleanMode360.MaxBoost, 'Boost'] ]; setPowerLevel = (powerLevel) => this.mqtt.commandSetCleaningStrategy(powerLevel); getPowerLevel = () => this.mqtt.status.defaultCleaningStrategy; // Retrieve details of a completed clean async getCompletedClean(cleanId) { const { logMapStyle } = this.config; if (!this.api || logMapStyle === 'Off') return 'Unavailable'; // Retrieve details of the specified (or most recent) clean const history = await this.api.getCleanMaps360(); const clean = history.find(entry => entry.cleanId === cleanId); if (!clean) return 'Not found'; const interim = clean.cleanTimeline.at(-1)?.eventName !== Dyson360TimelineEvent.RunEnded; if (interim) return 'Not ready'; let persistentMap; if (clean.persistentMap) persistentMap = await this.api.getPersistentMap360(clean.persistentMap.id); // Render the map return dysonRenderMap360VisNav(this.log, logMapStyle, clean, persistentMap); } } // A Dyson 360 Spot+Scrub device export class DysonDevice360SpotScrub extends DysonDevice360Base { static model = { type: 'RB05', number: 'RB05', name: 'Spot+Scrub Ai' }; getBatteryPartNumber = () => '975571-01'; getProductAppearance = () => ({ finish: BasicInformation.ProductFinish.Matte, primaryColor: BasicInformation.Color.Black }); getPowerLevelMaps = () => []; setPowerLevel = (powerLevel) => this.mqtt.commandSetPowerMode(powerLevel); getPowerLevel = () => this.mqtt.status.defaultVacuumPowerMode; get compatibilityWarning() { return DYSON360_COMPATIBILITY_SPOTSCRUB; } } // List of constructors for Dyson robot vacuum devices export const DYSON_DEVICE_TYPES_360 = [ DysonDevice360Eye, DysonDevice360Heurist, DysonDevice360VisNav, DysonDevice360SpotScrub ]; //# sourceMappingURL=dyson-device-360.js.map