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.
102 lines • 3.81 kB
JavaScript
// Matterbridge plugin for Dyson robot vacuum and air treatment devices
// Copyright © 2025 Alexander Thoukydides
import { setTimeout } from 'node:timers/promises';
import { logError } from './log-error.js';
// Status of the operation
export var PeriodicStatus;
(function (PeriodicStatus) {
PeriodicStatus[PeriodicStatus["Stopped"] = 0] = "Stopped";
PeriodicStatus[PeriodicStatus["Down"] = 1] = "Down";
PeriodicStatus[PeriodicStatus["Up"] = 2] = "Up";
})(PeriodicStatus || (PeriodicStatus = {}));
;
// Perform an operation periodically with watchdog timeout
export class Periodic {
log;
config;
// Is the watchdog being reset before its timeout
status = PeriodicStatus.Stopped;
// Abort signal used to cancel timers
abortInterval;
abortWatchdog;
// Is this periodic operation enabled
enabled = true;
// Timing of the next operation
lastActivityTime = 0;
// The periodic operation loop
runPeriodicPromise;
// Start a new periodic operation
constructor(log, config) {
this.log = log;
this.config = config;
void this.restartWatchdog();
this.runPeriodicPromise = this.runPeriodic();
}
// Stop the periodic operation, waiting for any in-progress operation
async stop() {
// Terminate the periodic operation and wait for it to complete
this.enabled = false;
this.abortInterval?.abort();
await this.runPeriodicPromise;
// Stop the watchdog and set the status to 'Stopped'
this.abortWatchdog?.abort();
this.setStatus(PeriodicStatus.Stopped);
}
// Reset the watchdog and reschedule the next operation
up() {
// Restart the watchdog timer
void this.restartWatchdog();
// Reschedule the next operation
this.lastActivityTime = Date.now();
this.abortInterval?.abort();
// Ensure that the status is 'Up'
this.setStatus(PeriodicStatus.Up);
}
// Set the status
setStatus(status) {
if (this.status !== status) {
this.status = status;
this.config.onStatus(this.status);
}
}
// Perform the operation periodically until stopped
async runPeriodic() {
while (this.enabled) {
try {
// Wait until it is time for the next operation
this.abortInterval = new AbortController();
const { signal } = this.abortInterval;
const timeUntilNextOp = this.lastActivityTime + this.config.interval - Date.now();
await setTimeout(timeUntilNextOp, undefined, { signal });
// Attempt the operation
await this.config.onOp();
// Update the time of the last activity (but leave the watchdog)
this.lastActivityTime = Date.now();
}
catch (err) {
if (!(err instanceof Error && err.name === 'AbortError')) {
logError(this.log, this.config.name, err);
}
}
}
}
// (Re)start the watchdog timer
async restartWatchdog() {
try {
// Abort any existing watchdog
this.abortWatchdog?.abort();
// Start a new watchdog
this.abortWatchdog = new AbortController();
const { signal } = this.abortWatchdog;
await setTimeout(this.config.watchdog, undefined, { signal });
// The timeout has occurred, so change the status to 'Down'
this.setStatus(PeriodicStatus.Down);
}
catch (err) {
if (!(err instanceof Error && err.name === 'AbortError')) {
logError(this.log, this.config.name, err);
}
}
}
}
//# sourceMappingURL=periodic.js.map