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.
137 lines • 7.9 kB
JavaScript
// Matterbridge plugin for Dyson robot vacuum and air treatment devices
// Copyright © 2025 Alexander Thoukydides
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
var useValue = arguments.length > 2;
for (var i = 0; i < initializers.length; i++) {
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
}
return useValue ? value : void 0;
};
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
var _, done = false;
for (var i = decorators.length - 1; i >= 0; i--) {
var context = {};
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
if (kind === "accessor") {
if (result === void 0) continue;
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
if (_ = accept(result.get)) descriptor.get = _;
if (_ = accept(result.set)) descriptor.set = _;
if (_ = accept(result.init)) initializers.unshift(_);
}
else if (_ = accept(result)) {
if (kind === "field") initializers.unshift(_);
else descriptor[key] = _;
}
}
if (target) Object.defineProperty(target, contextIn.name, descriptor);
done = true;
};
import { MatterbridgeEndpoint } from 'matterbridge';
import { BridgedDeviceBasicInformation } from 'matterbridge/matter/clusters';
import { BridgedDeviceBasicInformationServer } from 'matterbridge/matter/behaviors';
import { Changed, ifValueChanged } from './decorator-changed.js';
import { AN, AV, CN, RI } from './logger-options.js';
// A Matterbridge endpoint with a Bridged Device Basic Information cluster
let EndpointBase = (() => {
let _classSuper = MatterbridgeEndpoint;
let _instanceExtraInitializers = [];
let _updateReachable_decorators;
return class EndpointBase extends _classSuper {
static {
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
_updateReachable_decorators = [ifValueChanged];
__esDecorate(this, null, _updateReachable_decorators, { kind: "method", name: "updateReachable", static: false, private: false, access: { has: obj => "updateReachable" in obj, get: obj => obj.updateReachable }, metadata: _metadata }, null, _instanceExtraInitializers);
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
}
config = __runInitializers(this, _instanceExtraInitializers);
// Decorator support
changed;
// Construct a new endpoint
constructor(log, config, options, definition) {
const { uniqueStorageKey } = options;
const debug = config.debugFeatures.includes('Log Endpoint Debug');
super(definition, { uniqueStorageKey }, debug);
this.config = config;
// Use supplied logger instead of the one created by the base class
this.log = log;
// Create the basic clusters required on all endpoints
this.createDefaultIdentifyClusterServer()
.createBridgedDeviceBasicInformationClusterServer(options.deviceBasicInformation);
// Prepare the decorator support
this.changed = new Changed(log);
// Matterbridge requires a unique name for each endpoint
this.deviceName = options.matterbridgeDeviceName;
// Identify the device
this.addCommandHandler('identify', () => {
this.log.info(`${CN}Identify device${RI}`);
});
}
// Create the Bridged Device Basic Information cluster
createBridgedDeviceBasicInformationClusterServer(options) {
const parseOptionalNumber = (value) => value === undefined ? undefined : parseInt(value, 10);
// Copy of values (possibly) required by Matterbridge
// (Do NOT use the nodeLabel for deviceName; it might not be unique)
this.hardwareVersion = parseOptionalNumber(options.hardwareVersion);
this.hardwareVersionString = options.hardwareVersion;
this.productId = options.productId;
this.productName = options.productName;
this.serialNumber = options.serialNumber;
this.softwareVersion = parseOptionalNumber(options.softwareVersion);
this.softwareVersionString = options.softwareVersion;
this.uniqueId = options.uniqueId;
this.vendorId = options.vendorId;
this.vendorName = options.vendorName;
// Create the cluster
this.behaviors.require(BridgedDeviceBasicInformationServer.enable({
events: {
leave: true,
reachableChanged: true
}
}), {
// Mandatory attributes
reachable: true,
uniqueId: options.uniqueId.substring(0, 32),
// Optional attributes
hardwareVersion: parseOptionalNumber(options.hardwareVersion),
hardwareVersionString: options.hardwareVersion?.substring(0, 64),
manufacturingDate: options.manufacturingDate?.substring(0, 16),
nodeLabel: options.nodeLabel?.substring(0, 32),
partNumber: options.partNumber?.substring(0, 32),
productAppearance: options.productAppearance,
productId: options.productId,
productLabel: options.productLabel?.substring(0, 64),
productName: options.productName?.substring(0, 32),
productUrl: options.partNumber?.substring(0, 256),
serialNumber: options.serialNumber?.substring(0, 32),
softwareVersion: parseOptionalNumber(options.softwareVersion),
softwareVersionString: options.softwareVersion?.substring(0, 64),
vendorId: options.vendorId,
vendorName: options.vendorName?.substring(0, 32)
});
return this;
}
// Update the Bridged Device Basic Information cluster attributes
async updateReachable(reachable) {
const clusterId = BridgedDeviceBasicInformation.Cluster.id;
this.log.info(`${AN}Reachable${RI}: ${AV}${reachable}${RI}`);
await this.updateAttribute(clusterId, 'reachable', reachable, this.log);
const payload = { reachableNewValue: reachable };
await this.triggerEvent(clusterId, 'reachableChanged', payload, this.log);
}
};
})();
export { EndpointBase };
// Format an enum value for logging
export function formatEnumLog(enumMap, value) {
const label = enumMap[value];
return `${AV}${label}${RI} (${AV}${value}${RI})`;
}
//# sourceMappingURL=endpoint-base.js.map