matterbridge-dyson-robot 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/LICENSE +14 -0
- package/README.md +365 -0
- package/dist/async-eventemitter.d.ts +9 -0
- package/dist/async-eventemitter.d.ts.map +1 -0
- package/dist/async-eventemitter.js +35 -0
- package/dist/async-eventemitter.js.map +1 -0
- package/dist/check-configuration.d.ts +5 -0
- package/dist/check-configuration.d.ts.map +1 -0
- package/dist/check-configuration.js +35 -0
- package/dist/check-configuration.js.map +1 -0
- package/dist/check-versions.d.ts +3 -0
- package/dist/check-versions.d.ts.map +1 -0
- package/dist/check-versions.js +31 -0
- package/dist/check-versions.js.map +1 -0
- package/dist/config-types.d.ts +48 -0
- package/dist/config-types.d.ts.map +1 -0
- package/dist/config-types.js +4 -0
- package/dist/config-types.js.map +1 -0
- package/dist/decorator-changed.d.ts +16 -0
- package/dist/decorator-changed.d.ts.map +1 -0
- package/dist/decorator-changed.js +62 -0
- package/dist/decorator-changed.js.map +1 -0
- package/dist/dyson-360-msg-types.d.ts +113 -0
- package/dist/dyson-360-msg-types.d.ts.map +1 -0
- package/dist/dyson-360-msg-types.js +4 -0
- package/dist/dyson-360-msg-types.js.map +1 -0
- package/dist/dyson-360-types.d.ts +76 -0
- package/dist/dyson-360-types.d.ts.map +1 -0
- package/dist/dyson-360-types.js +72 -0
- package/dist/dyson-360-types.js.map +1 -0
- package/dist/dyson-air-msg-types.d.ts +99 -0
- package/dist/dyson-air-msg-types.d.ts.map +1 -0
- package/dist/dyson-air-msg-types.js +4 -0
- package/dist/dyson-air-msg-types.js.map +1 -0
- package/dist/dyson-air-sensor-types.d.ts +59 -0
- package/dist/dyson-air-sensor-types.d.ts.map +1 -0
- package/dist/dyson-air-sensor-types.js +4 -0
- package/dist/dyson-air-sensor-types.js.map +1 -0
- package/dist/dyson-air-state-types.d.ts +96 -0
- package/dist/dyson-air-state-types.d.ts.map +1 -0
- package/dist/dyson-air-state-types.js +4 -0
- package/dist/dyson-air-state-types.js.map +1 -0
- package/dist/dyson-air-types.d.ts +325 -0
- package/dist/dyson-air-types.d.ts.map +1 -0
- package/dist/dyson-air-types.js +382 -0
- package/dist/dyson-air-types.js.map +1 -0
- package/dist/dyson-device-360-base.d.ts +35 -0
- package/dist/dyson-device-360-base.d.ts.map +1 -0
- package/dist/dyson-device-360-base.js +233 -0
- package/dist/dyson-device-360-base.js.map +1 -0
- package/dist/dyson-device-360-commands.d.ts +7 -0
- package/dist/dyson-device-360-commands.d.ts.map +1 -0
- package/dist/dyson-device-360-commands.js +129 -0
- package/dist/dyson-device-360-commands.js.map +1 -0
- package/dist/dyson-device-360-faults-table.d.ts +20 -0
- package/dist/dyson-device-360-faults-table.d.ts.map +1 -0
- package/dist/dyson-device-360-faults-table.js +161 -0
- package/dist/dyson-device-360-faults-table.js.map +1 -0
- package/dist/dyson-device-360-faults.d.ts +10 -0
- package/dist/dyson-device-360-faults.d.ts.map +1 -0
- package/dist/dyson-device-360-faults.js +123 -0
- package/dist/dyson-device-360-faults.js.map +1 -0
- package/dist/dyson-device-360.d.ts +38 -0
- package/dist/dyson-device-360.d.ts.map +1 -0
- package/dist/dyson-device-360.js +45 -0
- package/dist/dyson-device-360.js.map +1 -0
- package/dist/dyson-device-air-base.d.ts +41 -0
- package/dist/dyson-device-air-base.d.ts.map +1 -0
- package/dist/dyson-device-air-base.js +446 -0
- package/dist/dyson-device-air-base.js.map +1 -0
- package/dist/dyson-device-air-heat.d.ts +52 -0
- package/dist/dyson-device-air-heat.d.ts.map +1 -0
- package/dist/dyson-device-air-heat.js +71 -0
- package/dist/dyson-device-air-heat.js.map +1 -0
- package/dist/dyson-device-air-quality.d.ts +7 -0
- package/dist/dyson-device-air-quality.d.ts.map +1 -0
- package/dist/dyson-device-air-quality.js +101 -0
- package/dist/dyson-device-air-quality.js.map +1 -0
- package/dist/dyson-device-air.d.ts +216 -0
- package/dist/dyson-device-air.d.ts.map +1 -0
- package/dist/dyson-device-air.js +80 -0
- package/dist/dyson-device-air.js.map +1 -0
- package/dist/dyson-device-base.d.ts +49 -0
- package/dist/dyson-device-base.d.ts.map +1 -0
- package/dist/dyson-device-base.js +46 -0
- package/dist/dyson-device-base.js.map +1 -0
- package/dist/dyson-device.d.ts +5 -0
- package/dist/dyson-device.d.ts.map +1 -0
- package/dist/dyson-device.js +43 -0
- package/dist/dyson-device.js.map +1 -0
- package/dist/dyson-mqtt-360.d.ts +16 -0
- package/dist/dyson-mqtt-360.d.ts.map +1 -0
- package/dist/dyson-mqtt-360.js +83 -0
- package/dist/dyson-mqtt-360.js.map +1 -0
- package/dist/dyson-mqtt-air.d.ts +48 -0
- package/dist/dyson-mqtt-air.d.ts.map +1 -0
- package/dist/dyson-mqtt-air.js +216 -0
- package/dist/dyson-mqtt-air.js.map +1 -0
- package/dist/dyson-mqtt-config.d.ts +6 -0
- package/dist/dyson-mqtt-config.d.ts.map +1 -0
- package/dist/dyson-mqtt-config.js +47 -0
- package/dist/dyson-mqtt-config.js.map +1 -0
- package/dist/dyson-mqtt-connect.d.ts +22 -0
- package/dist/dyson-mqtt-connect.d.ts.map +1 -0
- package/dist/dyson-mqtt-connect.js +145 -0
- package/dist/dyson-mqtt-connect.js.map +1 -0
- package/dist/dyson-mqtt-filter.d.ts +10 -0
- package/dist/dyson-mqtt-filter.d.ts.map +1 -0
- package/dist/dyson-mqtt-filter.js +25 -0
- package/dist/dyson-mqtt-filter.js.map +1 -0
- package/dist/dyson-mqtt-parse.d.ts +16 -0
- package/dist/dyson-mqtt-parse.d.ts.map +1 -0
- package/dist/dyson-mqtt-parse.js +100 -0
- package/dist/dyson-mqtt-parse.js.map +1 -0
- package/dist/dyson-mqtt-subscribe.d.ts +28 -0
- package/dist/dyson-mqtt-subscribe.d.ts.map +1 -0
- package/dist/dyson-mqtt-subscribe.js +85 -0
- package/dist/dyson-mqtt-subscribe.js.map +1 -0
- package/dist/dyson-mqtt.d.ts +51 -0
- package/dist/dyson-mqtt.d.ts.map +1 -0
- package/dist/dyson-mqtt.js +138 -0
- package/dist/dyson-mqtt.js.map +1 -0
- package/dist/dyson-types.d.ts +18 -0
- package/dist/dyson-types.d.ts.map +1 -0
- package/dist/dyson-types.js +20 -0
- package/dist/dyson-types.js.map +1 -0
- package/dist/endpoint-360-behavior.d.ts +55 -0
- package/dist/endpoint-360-behavior.d.ts.map +1 -0
- package/dist/endpoint-360-behavior.js +156 -0
- package/dist/endpoint-360-behavior.js.map +1 -0
- package/dist/endpoint-360-rvc.d.ts +14 -0
- package/dist/endpoint-360-rvc.d.ts.map +1 -0
- package/dist/endpoint-360-rvc.js +149 -0
- package/dist/endpoint-360-rvc.js.map +1 -0
- package/dist/endpoint-360.d.ts +35 -0
- package/dist/endpoint-360.d.ts.map +1 -0
- package/dist/endpoint-360.js +197 -0
- package/dist/endpoint-360.js.map +1 -0
- package/dist/endpoint-air-purifier.d.ts +24 -0
- package/dist/endpoint-air-purifier.d.ts.map +1 -0
- package/dist/endpoint-air-purifier.js +97 -0
- package/dist/endpoint-air-purifier.js.map +1 -0
- package/dist/endpoint-air-quality.d.ts +11 -0
- package/dist/endpoint-air-quality.d.ts.map +1 -0
- package/dist/endpoint-air-quality.js +104 -0
- package/dist/endpoint-air-quality.js.map +1 -0
- package/dist/endpoint-air-thermostat.d.ts +358 -0
- package/dist/endpoint-air-thermostat.d.ts.map +1 -0
- package/dist/endpoint-air-thermostat.js +67 -0
- package/dist/endpoint-air-thermostat.js.map +1 -0
- package/dist/endpoint-air.d.ts +125 -0
- package/dist/endpoint-air.d.ts.map +1 -0
- package/dist/endpoint-air.js +459 -0
- package/dist/endpoint-air.js.map +1 -0
- package/dist/endpoint-base.d.ts +36 -0
- package/dist/endpoint-base.d.ts.map +1 -0
- package/dist/endpoint-base.js +137 -0
- package/dist/endpoint-base.js.map +1 -0
- package/dist/error-360.d.ts +35 -0
- package/dist/error-360.d.ts.map +1 -0
- package/dist/error-360.js +105 -0
- package/dist/error-360.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/logger-filter.d.ts +23 -0
- package/dist/logger-filter.d.ts.map +1 -0
- package/dist/logger-filter.js +104 -0
- package/dist/logger-filter.js.map +1 -0
- package/dist/logger-options.d.ts +18 -0
- package/dist/logger-options.d.ts.map +1 -0
- package/dist/logger-options.js +41 -0
- package/dist/logger-options.js.map +1 -0
- package/dist/logger-prefix.d.ts +12 -0
- package/dist/logger-prefix.d.ts.map +1 -0
- package/dist/logger-prefix.js +37 -0
- package/dist/logger-prefix.js.map +1 -0
- package/dist/periodic.d.ts +31 -0
- package/dist/periodic.d.ts.map +1 -0
- package/dist/periodic.js +102 -0
- package/dist/periodic.js.map +1 -0
- package/dist/platform.d.ts +18 -0
- package/dist/platform.d.ts.map +1 -0
- package/dist/platform.js +138 -0
- package/dist/platform.js.map +1 -0
- package/dist/settings.d.ts +9 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/settings.js +28 -0
- package/dist/settings.js.map +1 -0
- package/dist/ti/config-types-ti.d.ts +16 -0
- package/dist/ti/config-types-ti.d.ts.map +1 -0
- package/dist/ti/config-types-ti.js +65 -0
- package/dist/ti/config-types-ti.js.map +1 -0
- package/dist/ti/config-types.d.ts +37 -0
- package/dist/ti/config-types.d.ts.map +1 -0
- package/dist/ti/config-types.js +11 -0
- package/dist/ti/config-types.js.map +1 -0
- package/dist/ti/dyson-360-msg-types-ti.d.ts +22 -0
- package/dist/ti/dyson-360-msg-types-ti.d.ts.map +1 -0
- package/dist/ti/dyson-360-msg-types-ti.js +134 -0
- package/dist/ti/dyson-360-msg-types-ti.js.map +1 -0
- package/dist/ti/dyson-360-msg-types.d.ts +55 -0
- package/dist/ti/dyson-360-msg-types.d.ts.map +1 -0
- package/dist/ti/dyson-360-msg-types.js +13 -0
- package/dist/ti/dyson-360-msg-types.js.map +1 -0
- package/dist/ti/dyson-360-types-ti.d.ts +17 -0
- package/dist/ti/dyson-360-types-ti.d.ts.map +1 -0
- package/dist/ti/dyson-360-types-ti.js +94 -0
- package/dist/ti/dyson-360-types-ti.js.map +1 -0
- package/dist/ti/dyson-360-types.d.ts +40 -0
- package/dist/ti/dyson-360-types.d.ts.map +1 -0
- package/dist/ti/dyson-360-types.js +11 -0
- package/dist/ti/dyson-360-types.js.map +1 -0
- package/dist/ti/dyson-air-msg-types-ti.d.ts +19 -0
- package/dist/ti/dyson-air-msg-types-ti.d.ts.map +1 -0
- package/dist/ti/dyson-air-msg-types-ti.js +115 -0
- package/dist/ti/dyson-air-msg-types-ti.js.map +1 -0
- package/dist/ti/dyson-air-msg-types.d.ts +46 -0
- package/dist/ti/dyson-air-msg-types.d.ts.map +1 -0
- package/dist/ti/dyson-air-msg-types.js +15 -0
- package/dist/ti/dyson-air-msg-types.js.map +1 -0
- package/dist/ti/dyson-air-sensor-types-ti.d.ts +9 -0
- package/dist/ti/dyson-air-sensor-types-ti.d.ts.map +1 -0
- package/dist/ti/dyson-air-sensor-types-ti.js +68 -0
- package/dist/ti/dyson-air-sensor-types-ti.js.map +1 -0
- package/dist/ti/dyson-air-sensor-types.d.ts +16 -0
- package/dist/ti/dyson-air-sensor-types.d.ts.map +1 -0
- package/dist/ti/dyson-air-sensor-types.js +12 -0
- package/dist/ti/dyson-air-sensor-types.js.map +1 -0
- package/dist/ti/dyson-air-state-types-ti.d.ts +9 -0
- package/dist/ti/dyson-air-state-types-ti.d.ts.map +1 -0
- package/dist/ti/dyson-air-state-types-ti.js +105 -0
- package/dist/ti/dyson-air-state-types-ti.js.map +1 -0
- package/dist/ti/dyson-air-state-types.d.ts +16 -0
- package/dist/ti/dyson-air-state-types.d.ts.map +1 -0
- package/dist/ti/dyson-air-state-types.js +12 -0
- package/dist/ti/dyson-air-state-types.js.map +1 -0
- package/dist/ti/dyson-air-types-ti.d.ts +59 -0
- package/dist/ti/dyson-air-types-ti.d.ts.map +1 -0
- package/dist/ti/dyson-air-types-ti.js +385 -0
- package/dist/ti/dyson-air-types-ti.js.map +1 -0
- package/dist/ti/dyson-air-types.d.ts +166 -0
- package/dist/ti/dyson-air-types.d.ts.map +1 -0
- package/dist/ti/dyson-air-types.js +11 -0
- package/dist/ti/dyson-air-types.js.map +1 -0
- package/dist/ti/dyson-types-ti.d.ts +10 -0
- package/dist/ti/dyson-types-ti.d.ts.map +1 -0
- package/dist/ti/dyson-types-ti.js +29 -0
- package/dist/ti/dyson-types-ti.js.map +1 -0
- package/dist/ti/dyson-types.d.ts +19 -0
- package/dist/ti/dyson-types.d.ts.map +1 -0
- package/dist/ti/dyson-types.js +11 -0
- package/dist/ti/dyson-types.js.map +1 -0
- package/dist/utils.d.ts +24 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +150 -0
- package/dist/utils.js.map +1 -0
- package/matterbridge-dyson-robot.schema.json +359 -0
- package/package.json +93 -0
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
// Matterbridge plugin for Dyson robot vacuum and air treatment devices
|
|
2
|
+
// Copyright © 2025 Alexander Thoukydides
|
|
3
|
+
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
|
|
4
|
+
var useValue = arguments.length > 2;
|
|
5
|
+
for (var i = 0; i < initializers.length; i++) {
|
|
6
|
+
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
|
|
7
|
+
}
|
|
8
|
+
return useValue ? value : void 0;
|
|
9
|
+
};
|
|
10
|
+
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
|
|
11
|
+
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
|
|
12
|
+
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
|
|
13
|
+
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
|
|
14
|
+
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
|
|
15
|
+
var _, done = false;
|
|
16
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
17
|
+
var context = {};
|
|
18
|
+
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
|
|
19
|
+
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
|
|
20
|
+
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
|
|
21
|
+
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
|
|
22
|
+
if (kind === "accessor") {
|
|
23
|
+
if (result === void 0) continue;
|
|
24
|
+
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
|
|
25
|
+
if (_ = accept(result.get)) descriptor.get = _;
|
|
26
|
+
if (_ = accept(result.set)) descriptor.set = _;
|
|
27
|
+
if (_ = accept(result.init)) initializers.unshift(_);
|
|
28
|
+
}
|
|
29
|
+
else if (_ = accept(result)) {
|
|
30
|
+
if (kind === "field") initializers.unshift(_);
|
|
31
|
+
else descriptor[key] = _;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
35
|
+
done = true;
|
|
36
|
+
};
|
|
37
|
+
import { DysonDevice } from './dyson-device-base.js';
|
|
38
|
+
import { DysonMqttAir } from './dyson-mqtt-air.js';
|
|
39
|
+
import { FanControl, ResourceMonitoring } from 'matterbridge/matter/clusters';
|
|
40
|
+
import { assertIsDefined, formatList, tryListener } from './utils.js';
|
|
41
|
+
import { EndpointsAir } from './endpoint-air.js';
|
|
42
|
+
import { PLUGIN_URL, VENDOR_NAME } from './settings.js';
|
|
43
|
+
import { mapDysonAirSensorStatus } from './dyson-device-air-quality.js';
|
|
44
|
+
import { DysonAirAnemometerControlProfile, DysonAirAnemometerControlTilt, DysonAirAutoMode, DysonAirFanAutoPower, DysonAirFanDirection, DysonAirFanPower, DysonAirFanSpeed, DysonAirFanState, DysonAirNightMode, DysonAirOscillation, DysonAirTiltAngle, DysonAirTiltOscillation } from './dyson-air-types.js';
|
|
45
|
+
import { CC, RI } from './logger-options.js';
|
|
46
|
+
import { ifValueChanged } from './decorator-changed.js';
|
|
47
|
+
// Mappings between FanMode and SpeedSetting
|
|
48
|
+
const FAN_MODE_TO_SPEED_LOW = 1;
|
|
49
|
+
const FAN_MODE_TO_SPEED_MEDIUM = 5;
|
|
50
|
+
const FAN_MODE_TO_SPEED_HIGH = 10;
|
|
51
|
+
const SPEED_TO_FAN_MODE_LOW = 3; // 1~3: Low
|
|
52
|
+
const SPEED_TO_FAN_MODE_MEDIUM = 6; // 4~6: Medium, 7~9: High
|
|
53
|
+
// Lifetime of a Pure (Hot+)Cool Link HEPA filter in operational hours
|
|
54
|
+
const PURE_LINK_FILTER_HOURS = 4300;
|
|
55
|
+
// Filter lifetime thresholds
|
|
56
|
+
const FILTER_CRITICAL = 0; // %
|
|
57
|
+
const FILTER_WARNING = 10; // %
|
|
58
|
+
// A Dyson air treatment device
|
|
59
|
+
let DysonDeviceAirBase = (() => {
|
|
60
|
+
let _classSuper = DysonDevice;
|
|
61
|
+
let _instanceExtraInitializers = [];
|
|
62
|
+
let _updateClusterAttributes_decorators;
|
|
63
|
+
return class DysonDeviceAirBase extends _classSuper {
|
|
64
|
+
static {
|
|
65
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
66
|
+
_updateClusterAttributes_decorators = [ifValueChanged];
|
|
67
|
+
__esDecorate(this, null, _updateClusterAttributes_decorators, { kind: "method", name: "updateClusterAttributes", static: false, private: false, access: { has: obj => "updateClusterAttributes" in obj, get: obj => obj.updateClusterAttributes }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
68
|
+
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
69
|
+
}
|
|
70
|
+
// The MQTT client and status update listener
|
|
71
|
+
static mqttConstructor = DysonMqttAir;
|
|
72
|
+
mqttListener = __runInitializers(this, _instanceExtraInitializers);
|
|
73
|
+
// The air purifier device endpoints
|
|
74
|
+
endpoints;
|
|
75
|
+
// Supported features
|
|
76
|
+
hasBreeze;
|
|
77
|
+
hasCarbonFilter;
|
|
78
|
+
hasDirection;
|
|
79
|
+
hasLeftRight;
|
|
80
|
+
hasUpDown;
|
|
81
|
+
// Should FanMode be used (in addition to On/Off) for fan off control
|
|
82
|
+
useFanModeOff = false;
|
|
83
|
+
// Construct a new Dyson device instance
|
|
84
|
+
constructor(...args) {
|
|
85
|
+
super(...args);
|
|
86
|
+
// Identify supported features from the presence of MQTT values
|
|
87
|
+
const { status } = this.mqtt;
|
|
88
|
+
this.hasBreeze = status.ancp !== undefined;
|
|
89
|
+
this.hasCarbonFilter = status.cflr !== undefined;
|
|
90
|
+
this.hasDirection = status.fdir !== undefined;
|
|
91
|
+
this.hasLeftRight = status.oson !== undefined;
|
|
92
|
+
this.hasUpDown = status.oton !== undefined;
|
|
93
|
+
// Prepare a listener for MQTT updates
|
|
94
|
+
this.mqttListener = tryListener(this.mqtt, () => this.updateClusterAttributes(this.mqtt.status));
|
|
95
|
+
}
|
|
96
|
+
// Create the endpoint for this device
|
|
97
|
+
makeEndpoints(validatedNames) {
|
|
98
|
+
// Static configuration of the air purifier clusters
|
|
99
|
+
const endpointOptions = {
|
|
100
|
+
uniqueStorageKey: this.uniqueId,
|
|
101
|
+
matterbridgeDeviceName: this.deviceName,
|
|
102
|
+
validatedNames,
|
|
103
|
+
deviceBasicInformation: {
|
|
104
|
+
nodeLabel: this.deviceName,
|
|
105
|
+
partNumber: this.modelNumber,
|
|
106
|
+
productLabel: this.modelNumber,
|
|
107
|
+
productName: this.modelName,
|
|
108
|
+
productUrl: PLUGIN_URL,
|
|
109
|
+
serialNumber: this.serialNumber,
|
|
110
|
+
softwareVersion: this.mqtt.status.version,
|
|
111
|
+
uniqueId: this.uniqueId,
|
|
112
|
+
vendorName: VENDOR_NAME
|
|
113
|
+
},
|
|
114
|
+
fanControl: {
|
|
115
|
+
rockSupport: {
|
|
116
|
+
rockLeftRight: this.hasLeftRight,
|
|
117
|
+
rockUpDown: this.hasUpDown,
|
|
118
|
+
rockRound: false
|
|
119
|
+
},
|
|
120
|
+
windSupport: {
|
|
121
|
+
sleepWind: true, // Night mode
|
|
122
|
+
naturalWind: this.hasBreeze
|
|
123
|
+
},
|
|
124
|
+
directionSupport: this.hasDirection
|
|
125
|
+
},
|
|
126
|
+
hepaFilter: {
|
|
127
|
+
filterPartNumbers: this.classStatic.filters.hepa
|
|
128
|
+
},
|
|
129
|
+
carbonFilter: this.hasCarbonFilter ? {
|
|
130
|
+
filterPartNumbers: this.classStatic.filters.carbon
|
|
131
|
+
} : undefined,
|
|
132
|
+
sensors: this.sensorSupport
|
|
133
|
+
};
|
|
134
|
+
// Create the endpoint
|
|
135
|
+
return new EndpointsAir(this.log, this.config, endpointOptions);
|
|
136
|
+
}
|
|
137
|
+
// Install handlers
|
|
138
|
+
async installHandlers(endpoints) {
|
|
139
|
+
await endpoints.setFanControlHandlers({
|
|
140
|
+
onOff: onOff => this.setPower(onOff),
|
|
141
|
+
airflowDirection: airflowDirection => this.setDirection(airflowDirection === FanControl.AirflowDirection.Forward),
|
|
142
|
+
fanMode: fanMode => {
|
|
143
|
+
switch (fanMode) {
|
|
144
|
+
case FanControl.FanMode.Auto: return this.setFanAuto();
|
|
145
|
+
case FanControl.FanMode.Off: return this.setFanSpeed(0);
|
|
146
|
+
case FanControl.FanMode.Low: return this.setFanSpeed(FAN_MODE_TO_SPEED_LOW);
|
|
147
|
+
case FanControl.FanMode.Medium: return this.setFanSpeed(FAN_MODE_TO_SPEED_MEDIUM);
|
|
148
|
+
default: return this.setFanSpeed(FAN_MODE_TO_SPEED_HIGH);
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
percentSetting: percentSetting => this.setFanSpeed(Math.ceil(percentSetting / 10)),
|
|
152
|
+
rockSetting: async (rockSetting) => {
|
|
153
|
+
if (this.hasLeftRight)
|
|
154
|
+
await this.setOscillateLeftRight(!!rockSetting.rockLeftRight);
|
|
155
|
+
if (this.hasUpDown)
|
|
156
|
+
await this.setOscillateUpDown(!!rockSetting.rockUpDown);
|
|
157
|
+
},
|
|
158
|
+
speedSetting: speedSetting => this.setFanSpeed(speedSetting),
|
|
159
|
+
windSetting: async (windSetting) => {
|
|
160
|
+
await this.setNightMode(!!windSetting.sleepWind);
|
|
161
|
+
if (this.hasBreeze)
|
|
162
|
+
await this.setOscillateBreeze(!!windSetting.naturalWind);
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
// Determine which optional sensors are supported
|
|
167
|
+
get sensorSupport() {
|
|
168
|
+
const sensors = mapDysonAirSensorStatus(this.log, this.mqtt.status);
|
|
169
|
+
return {
|
|
170
|
+
voc: sensors.voc !== undefined,
|
|
171
|
+
co2: sensors.co2 !== undefined,
|
|
172
|
+
nox: sensors.nox !== undefined,
|
|
173
|
+
hcho: sensors.hcho !== undefined,
|
|
174
|
+
pm25: sensors.pm25 !== undefined,
|
|
175
|
+
pm10: sensors.pm10 !== undefined
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
// List of endpoint function names and descriptions to validate
|
|
179
|
+
getEntities() {
|
|
180
|
+
return [{
|
|
181
|
+
name: 'Air Purifier',
|
|
182
|
+
description: 'Fan speed/oscillation control and filter monitoring'
|
|
183
|
+
}, {
|
|
184
|
+
name: 'Air Quality Sensor',
|
|
185
|
+
description: 'Environmental sensor measurements'
|
|
186
|
+
}, {
|
|
187
|
+
name: 'Composed Air Purifier',
|
|
188
|
+
description: 'Air purifier with integrated thermostat and sensors'
|
|
189
|
+
}, {
|
|
190
|
+
name: 'Humidity Sensor',
|
|
191
|
+
description: 'Relative humidity measurement'
|
|
192
|
+
}, {
|
|
193
|
+
name: 'Temperature Sensor',
|
|
194
|
+
description: 'Temperature measurement'
|
|
195
|
+
}];
|
|
196
|
+
}
|
|
197
|
+
// Retrieve the root device endpoints after validation
|
|
198
|
+
getEndpoints(validatedNames) {
|
|
199
|
+
this.endpoints ??= this.makeEndpoints(validatedNames);
|
|
200
|
+
return this.endpoints.bridgedNodeEndpoints;
|
|
201
|
+
}
|
|
202
|
+
// Start the device after the endpoints are active
|
|
203
|
+
async start() {
|
|
204
|
+
assertIsDefined(this.endpoints);
|
|
205
|
+
this.mqtt.on('status', this.mqttListener);
|
|
206
|
+
await this.installHandlers(this.endpoints);
|
|
207
|
+
await this.updateClusterAttributes(this.mqtt.status);
|
|
208
|
+
}
|
|
209
|
+
// Stop the device when Matterbridge is shutting down
|
|
210
|
+
async stop() {
|
|
211
|
+
this.mqtt.off('status', this.mqttListener);
|
|
212
|
+
await super.stop();
|
|
213
|
+
}
|
|
214
|
+
// Switch the fan on or off (without changing auto mode, if possible)
|
|
215
|
+
async setPower(powerOn) {
|
|
216
|
+
const { fpwr, fmod } = this.mqtt.status;
|
|
217
|
+
const isOn = fpwr ? fpwr !== DysonAirFanPower.Off // Non-Link
|
|
218
|
+
: fmod !== DysonAirFanAutoPower.Off; // Link models
|
|
219
|
+
if (isOn === powerOn) {
|
|
220
|
+
this.log.info(`Fan is already ${powerOn ? 'on' : 'off'}; no action required`);
|
|
221
|
+
}
|
|
222
|
+
else if (powerOn) {
|
|
223
|
+
this.log.info('Switching on');
|
|
224
|
+
await this.setState({}); // (sets an appropriate on state)
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
this.log.info('Switching off');
|
|
228
|
+
await this.setState(fpwr ? { fpwr: DysonAirFanPower.Off } // Non-Link
|
|
229
|
+
: { fmod: DysonAirFanAutoPower.Off }); // Link models
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
// Switch the fan on in auto mode
|
|
233
|
+
async setFanAuto() {
|
|
234
|
+
this.log.info('Enabling auto mode');
|
|
235
|
+
const { auto } = this.mqtt.status;
|
|
236
|
+
await this.setState(auto ? { auto: DysonAirAutoMode.Auto } // Non-Link
|
|
237
|
+
: { fmod: DysonAirFanAutoPower.Auto }); // Link models
|
|
238
|
+
}
|
|
239
|
+
// Set the airflow direction (all except Link models)
|
|
240
|
+
async setDirection(forward) {
|
|
241
|
+
const direction = forward ? 'Forward' : 'Backward';
|
|
242
|
+
this.log.info(`${direction} airflow`);
|
|
243
|
+
await this.setState({ fdir: DysonAirFanDirection[direction] });
|
|
244
|
+
}
|
|
245
|
+
// Set the fan speed
|
|
246
|
+
async setFanSpeed(speed) {
|
|
247
|
+
// Quantize and range check the speed
|
|
248
|
+
const fnsp = Math.min(Math.round(speed), 10);
|
|
249
|
+
if (fnsp < 1) {
|
|
250
|
+
this.log.info('Fan speed set to 0; turning power off');
|
|
251
|
+
this.useFanModeOff = true;
|
|
252
|
+
return this.setPower(false);
|
|
253
|
+
}
|
|
254
|
+
// Set the speed, ensuring that auto mode is disabled
|
|
255
|
+
this.log.info(`Setting fan speed to ${fnsp}`);
|
|
256
|
+
const { auto } = this.mqtt.status;
|
|
257
|
+
await this.setState(auto ? { fnsp, auto: DysonAirAutoMode.Manual } // Non-Link
|
|
258
|
+
: { fnsp, fmod: DysonAirFanAutoPower.Manual }); // Link models
|
|
259
|
+
}
|
|
260
|
+
// Set night mode
|
|
261
|
+
async setNightMode(night) {
|
|
262
|
+
const nightMode = night ? 'Night' : 'Day';
|
|
263
|
+
this.log.info(`${nightMode} mode`);
|
|
264
|
+
await this.setState({ nmod: DysonAirNightMode[nightMode] });
|
|
265
|
+
}
|
|
266
|
+
// Set horizontal oscillation (all except Big+Quiet models)
|
|
267
|
+
async setOscillateLeftRight(oscillate) {
|
|
268
|
+
this.log.info(`${oscillate ? 'Enabling' : 'disabling'} left/right oscillation`);
|
|
269
|
+
// Most models use 'ON'/'OFF', but some use 'OION'/'OIOF' instead
|
|
270
|
+
const { oson } = this.mqtt.status;
|
|
271
|
+
const isOI = oson === DysonAirOscillation.FixedOI
|
|
272
|
+
|| oson === DysonAirOscillation.OscillatingOI;
|
|
273
|
+
const OSON_KEYS = [['Fixed', 'FixedOI'], ['Oscillating', 'OscillatingOI']];
|
|
274
|
+
const key = OSON_KEYS[oscillate ? 1 : 0][isOI ? 1 : 0];
|
|
275
|
+
await this.setState({ oson: DysonAirOscillation[key] });
|
|
276
|
+
}
|
|
277
|
+
// Set vertical oscillation (Big+Quiet models only)
|
|
278
|
+
async setOscillateUpDown(oscillate) {
|
|
279
|
+
this.log.info(`${oscillate ? 'Enabling' : 'disabling'} up/down oscillation`);
|
|
280
|
+
const status = {};
|
|
281
|
+
if (oscillate) {
|
|
282
|
+
// Enable oscillation in breeze mode
|
|
283
|
+
status.oton = DysonAirTiltOscillation.Oscillating;
|
|
284
|
+
status.anct = DysonAirAnemometerControlTilt.Breeze;
|
|
285
|
+
status.otal = DysonAirTiltAngle.Breeze;
|
|
286
|
+
status.otau = DysonAirTiltAngle.Breeze;
|
|
287
|
+
}
|
|
288
|
+
else {
|
|
289
|
+
// Disable oscillation
|
|
290
|
+
status.oton = DysonAirTiltOscillation.Fixed;
|
|
291
|
+
status.anct = DysonAirAnemometerControlTilt.Custom;
|
|
292
|
+
const { otal, otau } = this.mqtt.status;
|
|
293
|
+
if (otal === DysonAirTiltAngle.Breeze || otau === DysonAirTiltAngle.Breeze) {
|
|
294
|
+
// Set an arbitrary tilt angle if breeze mode was enabled
|
|
295
|
+
status.otal = DysonAirTiltAngle.Degrees0;
|
|
296
|
+
status.otau = DysonAirTiltAngle.Degrees0;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
await this.setState(status);
|
|
300
|
+
}
|
|
301
|
+
// Set breeze oscillation and fan speed (Humidify models only)
|
|
302
|
+
async setOscillateBreeze(breeze) {
|
|
303
|
+
this.log.info(`${breeze ? 'Enabling' : 'disabling'} breeze oscillation`);
|
|
304
|
+
const status = {
|
|
305
|
+
oson: DysonAirOscillation.Oscillating
|
|
306
|
+
};
|
|
307
|
+
if (breeze) {
|
|
308
|
+
// Enable oscillation in breeze mode
|
|
309
|
+
status.ancp = DysonAirAnemometerControlProfile.Breeze;
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
// Enable non-breeze oscillation
|
|
313
|
+
const { ancp } = this.mqtt.status;
|
|
314
|
+
if (ancp === DysonAirAnemometerControlProfile.Breeze) {
|
|
315
|
+
// Set an arbitrary oscillation angle if breeze mode was enabled
|
|
316
|
+
status.ancp = DysonAirAnemometerControlProfile.Degrees180;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
await this.setState(status);
|
|
320
|
+
}
|
|
321
|
+
// Send an MQTT command to set the product state
|
|
322
|
+
async setState(productState) {
|
|
323
|
+
// Also switch to an active power state, unless an alternative specified
|
|
324
|
+
const { fpwr, fmod } = this.mqtt.status;
|
|
325
|
+
if (fpwr === DysonAirFanPower.Off)
|
|
326
|
+
productState.fpwr ??= DysonAirFanPower.On; // Non-Link
|
|
327
|
+
if (fmod === DysonAirFanAutoPower.Off)
|
|
328
|
+
productState.fmod ??= DysonAirFanAutoPower.Manual; // Link models
|
|
329
|
+
// Publish the command
|
|
330
|
+
const values = Object.entries(productState).map(([key, value]) => `${CC}${key}=${value}${RI}`);
|
|
331
|
+
this.log.info(`Setting state: ${formatList(values)}`);
|
|
332
|
+
await this.mqtt.commandStateSet(productState);
|
|
333
|
+
// Ensure that the next MQTT status update is processed
|
|
334
|
+
this.changed.flush();
|
|
335
|
+
}
|
|
336
|
+
// Update cluster attributes when the MQTT status is updated
|
|
337
|
+
async updateClusterAttributes(status) {
|
|
338
|
+
const fanStatus = this.mapDysonFanControlStatus(status);
|
|
339
|
+
const filterStatus = this.mapDysonFilterStatus(status);
|
|
340
|
+
const sensorStatus = mapDysonAirSensorStatus(this.log, status);
|
|
341
|
+
await Promise.all([
|
|
342
|
+
this.endpoints?.updateFanControl(fanStatus),
|
|
343
|
+
this.endpoints?.updateFilterMonitoring(filterStatus),
|
|
344
|
+
this.endpoints?.updateSensors(sensorStatus)
|
|
345
|
+
]);
|
|
346
|
+
}
|
|
347
|
+
// Convert the status to On/Off and Fan Control cluster attributes
|
|
348
|
+
mapDysonFanControlStatus(status) {
|
|
349
|
+
const { ancp, auto, fdir, fpwr, fmod, fnsp, fnst, nmod, oson, oton } = status;
|
|
350
|
+
// Start by determining the actual device state
|
|
351
|
+
const onOff = fpwr ? fpwr !== DysonAirFanPower.Off // Non-Link
|
|
352
|
+
: fmod !== DysonAirFanAutoPower.Off; // Link models
|
|
353
|
+
const isAuto = auto === DysonAirAutoMode.Auto // Non-Link
|
|
354
|
+
|| fnsp === DysonAirFanSpeed.Auto; // Link
|
|
355
|
+
const isSpinning = fnst === DysonAirFanState.Running;
|
|
356
|
+
// Link models do not preserve speed setting in auto, so default to max
|
|
357
|
+
let speedSetting = typeof fnsp === 'number' ? fnsp : 10;
|
|
358
|
+
// Start by mapping the speed to a mode
|
|
359
|
+
let fanMode = FanControl.FanMode[speedSetting <= SPEED_TO_FAN_MODE_LOW ? 'Low'
|
|
360
|
+
: speedSetting <= SPEED_TO_FAN_MODE_MEDIUM ? 'Medium' : 'High'];
|
|
361
|
+
let speedCurrent;
|
|
362
|
+
if (!onOff) {
|
|
363
|
+
// Off, fan stopped
|
|
364
|
+
speedCurrent = 0;
|
|
365
|
+
if (this.useFanModeOff) {
|
|
366
|
+
// Fan Control was set to Off or 0 speed via Matter
|
|
367
|
+
fanMode = FanControl.FanMode.Off;
|
|
368
|
+
speedSetting = 0;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
else {
|
|
372
|
+
this.useFanModeOff = false;
|
|
373
|
+
if (isAuto) {
|
|
374
|
+
// Auto mode: assume fan either at maximum speed or stopped
|
|
375
|
+
fanMode = FanControl.FanMode.Auto;
|
|
376
|
+
speedCurrent = isSpinning ? 10 : 0;
|
|
377
|
+
}
|
|
378
|
+
else {
|
|
379
|
+
// Manual mode: the fan is at the requested speed
|
|
380
|
+
speedCurrent = speedSetting;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
// Night mode
|
|
384
|
+
const sleepWind = nmod === DysonAirNightMode.Night;
|
|
385
|
+
// Airflow direction
|
|
386
|
+
let airflowDirection;
|
|
387
|
+
if (this.hasDirection && fdir) {
|
|
388
|
+
// Non-Link models only
|
|
389
|
+
airflowDirection = FanControl.AirflowDirection[fdir === DysonAirFanDirection.Forward ? 'Forward' : 'Reverse'];
|
|
390
|
+
}
|
|
391
|
+
// Various oscillation modes
|
|
392
|
+
let rockLeftRight = false, rockUpDown = false, naturalWind = false;
|
|
393
|
+
if (this.hasLeftRight) {
|
|
394
|
+
// All except Big+Quiet models
|
|
395
|
+
rockLeftRight = oson === DysonAirOscillation.Oscillating
|
|
396
|
+
|| oson === DysonAirOscillation.OscillatingOI;
|
|
397
|
+
}
|
|
398
|
+
if (this.hasUpDown) {
|
|
399
|
+
// Big+Quiet models only
|
|
400
|
+
rockUpDown = oton === DysonAirTiltOscillation.Oscillating;
|
|
401
|
+
}
|
|
402
|
+
if (this.hasBreeze) {
|
|
403
|
+
// Humidify+Cool models only
|
|
404
|
+
naturalWind = ancp === DysonAirAnemometerControlProfile.Breeze;
|
|
405
|
+
}
|
|
406
|
+
// Return the mapped values
|
|
407
|
+
let rockSetting;
|
|
408
|
+
if (this.hasLeftRight || this.hasUpDown)
|
|
409
|
+
rockSetting = { rockLeftRight, rockUpDown };
|
|
410
|
+
return {
|
|
411
|
+
airflowDirection,
|
|
412
|
+
fanMode,
|
|
413
|
+
onOff,
|
|
414
|
+
percentCurrent: speedCurrent * 10,
|
|
415
|
+
percentSetting: speedSetting * 10,
|
|
416
|
+
rockSetting,
|
|
417
|
+
speedCurrent,
|
|
418
|
+
speedSetting,
|
|
419
|
+
windSetting: { sleepWind, naturalWind }
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
// Convert the status to Filter Monitoring cluster attributes
|
|
423
|
+
mapDysonFilterStatus(status) {
|
|
424
|
+
const filterStatus = (percent) => {
|
|
425
|
+
const inPlaceIndicator = typeof percent === 'number';
|
|
426
|
+
const condition = inPlaceIndicator ? percent : 0;
|
|
427
|
+
const changeIndication = ResourceMonitoring.ChangeIndication[condition <= FILTER_CRITICAL ? 'Critical'
|
|
428
|
+
: condition <= FILTER_WARNING ? 'Warning' : 'Ok'];
|
|
429
|
+
return { condition, changeIndication, inPlaceIndicator };
|
|
430
|
+
};
|
|
431
|
+
// HEPA filter remaining life
|
|
432
|
+
let hepaPercent = status.hflr;
|
|
433
|
+
if (status.filf !== undefined) {
|
|
434
|
+
// For Pure (Hot+)Cool Link convert remaining hours to percentage
|
|
435
|
+
hepaPercent = Math.round(status.filf * 100 / PURE_LINK_FILTER_HOURS);
|
|
436
|
+
}
|
|
437
|
+
// Convert the filter status to Matter attribute representation
|
|
438
|
+
return {
|
|
439
|
+
hepa: filterStatus(hepaPercent),
|
|
440
|
+
carbon: this.hasCarbonFilter ? filterStatus(status.cflr) : undefined
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
};
|
|
444
|
+
})();
|
|
445
|
+
export { DysonDeviceAirBase };
|
|
446
|
+
//# sourceMappingURL=dyson-device-air-base.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dyson-device-air-base.js","sourceRoot":"","sources":["../src/dyson-device-air-base.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { EntityName } from './config-types.js';
|
|
2
|
+
import { DysonDeviceAirBase } from './dyson-device-air-base.js';
|
|
3
|
+
import { DysonMqttStatusAir } from './dyson-mqtt-air.js';
|
|
4
|
+
import { DysonMqttStatus } from './dyson-mqtt.js';
|
|
5
|
+
import { EndpointsAir } from './endpoint-air.js';
|
|
6
|
+
import { AbstractConstructor } from './utils.js';
|
|
7
|
+
export declare function DysonDeviceAirWithHeat<TBase extends AbstractConstructor<DysonDeviceAirBase>>(Base: TBase): (abstract new (...args: any[]) => {
|
|
8
|
+
installHandlers(endpoints: EndpointsAir): Promise<void>;
|
|
9
|
+
setTargetTemperature(celsius: number): Promise<void>;
|
|
10
|
+
setHeating(heat: boolean): Promise<void>;
|
|
11
|
+
getEntities(): {
|
|
12
|
+
name: EntityName;
|
|
13
|
+
description: string;
|
|
14
|
+
}[];
|
|
15
|
+
updateClusterAttributes(status: DysonMqttStatus<DysonMqttStatusAir>): Promise<void>;
|
|
16
|
+
mqttListener: () => void;
|
|
17
|
+
endpoints?: EndpointsAir;
|
|
18
|
+
hasBreeze: boolean;
|
|
19
|
+
hasCarbonFilter: boolean;
|
|
20
|
+
hasDirection: boolean;
|
|
21
|
+
hasLeftRight: boolean;
|
|
22
|
+
hasUpDown: boolean;
|
|
23
|
+
useFanModeOff: boolean;
|
|
24
|
+
makeEndpoints(validatedNames: EntityName[]): EndpointsAir;
|
|
25
|
+
readonly sensorSupport: import("./endpoint-air.js").EndpointOptionsAirSensors;
|
|
26
|
+
getEndpoints(validatedNames: EntityName[]): import("matterbridge").MatterbridgeEndpoint[];
|
|
27
|
+
start(): Promise<void>;
|
|
28
|
+
stop(): Promise<void>;
|
|
29
|
+
setPower(powerOn: boolean): Promise<void>;
|
|
30
|
+
setFanAuto(): Promise<void>;
|
|
31
|
+
setDirection(forward: boolean): Promise<void>;
|
|
32
|
+
setFanSpeed(speed: number): Promise<void>;
|
|
33
|
+
setNightMode(night: boolean): Promise<void>;
|
|
34
|
+
setOscillateLeftRight(oscillate: boolean): Promise<void>;
|
|
35
|
+
setOscillateUpDown(oscillate: boolean): Promise<void>;
|
|
36
|
+
setOscillateBreeze(breeze: boolean): Promise<void>;
|
|
37
|
+
setState(productState: import("./dyson-mqtt-air.js").DysonMqttProductState): Promise<void>;
|
|
38
|
+
mapDysonFanControlStatus(status: DysonMqttStatus<DysonMqttStatusAir>): import("./endpoint-air.js").UpdateAirFan;
|
|
39
|
+
mapDysonFilterStatus(status: DysonMqttStatus<DysonMqttStatusAir>): import("./endpoint-air.js").UpdateAirFilterMonitoring;
|
|
40
|
+
changed: import("./decorator-changed.js").Changed;
|
|
41
|
+
readonly log: import("matterbridge/logger").AnsiLogger;
|
|
42
|
+
readonly config: import("./config-types.js").Config;
|
|
43
|
+
readonly device: import("./config-types.js").DeviceConfig;
|
|
44
|
+
readonly mqtt: import("./dyson-mqtt-air.js").DysonMqttAir;
|
|
45
|
+
readonly uniqueId: string;
|
|
46
|
+
readonly classStatic: typeof import("./dyson-device-base.js").DysonDevice;
|
|
47
|
+
readonly modelName: string;
|
|
48
|
+
readonly modelNumber: string;
|
|
49
|
+
readonly deviceName: string;
|
|
50
|
+
readonly serialNumber: string;
|
|
51
|
+
}) & TBase;
|
|
52
|
+
//# sourceMappingURL=dyson-device-air-heat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dyson-device-air-heat.d.ts","sourceRoot":"","sources":["../src/dyson-device-air-heat.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAmB,MAAM,YAAY,CAAC;AASlE,wBAAgB,sBAAsB,CAAC,KAAK,SAAS,mBAAmB,CAAC,kBAAkB,CAAC,EAAE,IAAI,EAAE,KAAK,2BAI5E,GAAG,EAAE;+BAKgB,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;kCAmBlC,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;qBAOnC,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;mBAOtB;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,EAAE;oCASvD,eAAe,CAAC,kBAAkB,CAAC,GAC5C,OAAO,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAkBvB"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// Matterbridge plugin for Dyson robot vacuum and air treatment devices
|
|
2
|
+
// Copyright © 2025 Alexander Thoukydides
|
|
3
|
+
import { Thermostat } from 'matterbridge';
|
|
4
|
+
import { assertIsDefined } from './utils.js';
|
|
5
|
+
import { DysonAirFanState, DysonAirHeatingMode, DysonAirHeatingStatus } from './dyson-air-types.js';
|
|
6
|
+
import { numeric } from './dyson-device-air-quality.js';
|
|
7
|
+
// Mixin to add heating to a Dyson air treatment device
|
|
8
|
+
export function DysonDeviceAirWithHeat(Base) {
|
|
9
|
+
class DysonDeviceAirWithHeat extends Base {
|
|
10
|
+
// Mixin constructor
|
|
11
|
+
constructor(...args) {
|
|
12
|
+
super(...args);
|
|
13
|
+
}
|
|
14
|
+
// Install handlers
|
|
15
|
+
async installHandlers(endpoints) {
|
|
16
|
+
await super.installHandlers(endpoints);
|
|
17
|
+
await endpoints.setThermostatHandlers({
|
|
18
|
+
occupiedHeatingSetpoint: setpoint => this.setTargetTemperature(setpoint / 100),
|
|
19
|
+
systemMode: mode => {
|
|
20
|
+
switch (mode) {
|
|
21
|
+
case Thermostat.SystemMode.Heat:
|
|
22
|
+
case Thermostat.SystemMode.EmergencyHeat:
|
|
23
|
+
return this.setHeating(true);
|
|
24
|
+
case Thermostat.SystemMode.Off:
|
|
25
|
+
default:
|
|
26
|
+
return this.setHeating(false);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
// Set the heating target temperature
|
|
32
|
+
async setTargetTemperature(celsius) {
|
|
33
|
+
this.log.info(`Enabling heating with target temperature ${celsius} °C`);
|
|
34
|
+
const hmod = DysonAirHeatingMode.Heat;
|
|
35
|
+
await this.setState({ hmax: celsius, hmod });
|
|
36
|
+
}
|
|
37
|
+
// Enable or disable heating
|
|
38
|
+
async setHeating(heat) {
|
|
39
|
+
this.log.info(`${heat ? 'Enabling' : 'Disabling'} heating`);
|
|
40
|
+
// Turn power on when enabling heating, but not when disabling
|
|
41
|
+
await this.setState({ hmod: DysonAirHeatingMode[heat ? 'Heat' : 'Cool'] });
|
|
42
|
+
}
|
|
43
|
+
// List of endpoint function names and descriptions to validate
|
|
44
|
+
getEntities() {
|
|
45
|
+
return [...super.getEntities(), {
|
|
46
|
+
name: 'Thermostat',
|
|
47
|
+
description: 'Heating control'
|
|
48
|
+
}];
|
|
49
|
+
}
|
|
50
|
+
// Update cluster attributes when the MQTT status is updated
|
|
51
|
+
async updateClusterAttributes(status) {
|
|
52
|
+
await super.updateClusterAttributes(status);
|
|
53
|
+
const { fnst, hmax, hmod, hsta, tact } = status;
|
|
54
|
+
assertIsDefined(hmax);
|
|
55
|
+
assertIsDefined(tact);
|
|
56
|
+
const heatingMode = hmod === DysonAirHeatingMode.Heat;
|
|
57
|
+
const heat = hsta === DysonAirHeatingStatus.Heating;
|
|
58
|
+
const fan = fnst === DysonAirFanState.Running;
|
|
59
|
+
await this.endpoints?.updateThermostat({
|
|
60
|
+
localTemperature: numeric(tact, 100), // centi-°C
|
|
61
|
+
occupiedHeatingSetpoint: hmax * 100, // centi-°C
|
|
62
|
+
piHeatingDemand: heat ? 100 : 0, // %
|
|
63
|
+
systemMode: Thermostat.SystemMode[heatingMode ? 'Heat' : 'Off'],
|
|
64
|
+
thermostatRunningState: { heat, fan }
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
;
|
|
69
|
+
return DysonDeviceAirWithHeat;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=dyson-device-air-heat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dyson-device-air-heat.js","sourceRoot":"","sources":["../src/dyson-device-air-heat.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { DysonMqttStatusAirSensor } from './dyson-mqtt-air.js';
|
|
2
|
+
import { UpdateAirSensors } from './endpoint-air.js';
|
|
3
|
+
import { AnsiLogger } from 'matterbridge/logger';
|
|
4
|
+
export declare function numeric(value: number | string, factor?: number): number | null;
|
|
5
|
+
export declare function numeric(value?: number | string, factor?: number): number | null | undefined;
|
|
6
|
+
export declare function mapDysonAirSensorStatus(log: AnsiLogger, status: DysonMqttStatusAirSensor): UpdateAirSensors;
|
|
7
|
+
//# sourceMappingURL=dyson-device-air-quality.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dyson-device-air-quality.d.ts","sourceRoot":"","sources":["../src/dyson-device-air-quality.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AA4EjD,wBAAgB,OAAO,CAAC,KAAK,EAAG,MAAM,GAAG,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;AACjF,wBAAgB,OAAO,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;AAQ7F,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,wBAAwB,GAAG,gBAAgB,CAqB3G"}
|