meross-iot 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 +30 -0
- package/LICENSE +21 -0
- package/README.md +153 -0
- package/index.d.ts +2344 -0
- package/index.js +131 -0
- package/lib/controller/device.js +1317 -0
- package/lib/controller/features/alarm-feature.js +89 -0
- package/lib/controller/features/child-lock-feature.js +61 -0
- package/lib/controller/features/config-feature.js +54 -0
- package/lib/controller/features/consumption-feature.js +210 -0
- package/lib/controller/features/control-feature.js +62 -0
- package/lib/controller/features/diffuser-feature.js +411 -0
- package/lib/controller/features/digest-timer-feature.js +22 -0
- package/lib/controller/features/digest-trigger-feature.js +22 -0
- package/lib/controller/features/dnd-feature.js +79 -0
- package/lib/controller/features/electricity-feature.js +144 -0
- package/lib/controller/features/encryption-feature.js +259 -0
- package/lib/controller/features/garage-feature.js +337 -0
- package/lib/controller/features/hub-feature.js +687 -0
- package/lib/controller/features/light-feature.js +408 -0
- package/lib/controller/features/presence-sensor-feature.js +297 -0
- package/lib/controller/features/roller-shutter-feature.js +456 -0
- package/lib/controller/features/runtime-feature.js +74 -0
- package/lib/controller/features/screen-feature.js +67 -0
- package/lib/controller/features/sensor-history-feature.js +47 -0
- package/lib/controller/features/smoke-config-feature.js +50 -0
- package/lib/controller/features/spray-feature.js +166 -0
- package/lib/controller/features/system-feature.js +269 -0
- package/lib/controller/features/temp-unit-feature.js +55 -0
- package/lib/controller/features/thermostat-feature.js +804 -0
- package/lib/controller/features/timer-feature.js +507 -0
- package/lib/controller/features/toggle-feature.js +223 -0
- package/lib/controller/features/trigger-feature.js +333 -0
- package/lib/controller/hub-device.js +185 -0
- package/lib/controller/subdevice.js +1537 -0
- package/lib/device-factory.js +463 -0
- package/lib/error-budget.js +138 -0
- package/lib/http-api.js +766 -0
- package/lib/manager.js +1609 -0
- package/lib/model/channel-info.js +79 -0
- package/lib/model/constants.js +119 -0
- package/lib/model/enums.js +819 -0
- package/lib/model/exception.js +363 -0
- package/lib/model/http/device.js +215 -0
- package/lib/model/http/error-codes.js +121 -0
- package/lib/model/http/exception.js +151 -0
- package/lib/model/http/subdevice.js +133 -0
- package/lib/model/push/alarm.js +112 -0
- package/lib/model/push/bind.js +97 -0
- package/lib/model/push/common.js +282 -0
- package/lib/model/push/diffuser-light.js +100 -0
- package/lib/model/push/diffuser-spray.js +83 -0
- package/lib/model/push/factory.js +229 -0
- package/lib/model/push/generic.js +115 -0
- package/lib/model/push/hub-battery.js +59 -0
- package/lib/model/push/hub-mts100-all.js +64 -0
- package/lib/model/push/hub-mts100-mode.js +59 -0
- package/lib/model/push/hub-mts100-temperature.js +62 -0
- package/lib/model/push/hub-online.js +59 -0
- package/lib/model/push/hub-sensor-alert.js +61 -0
- package/lib/model/push/hub-sensor-all.js +59 -0
- package/lib/model/push/hub-sensor-smoke.js +110 -0
- package/lib/model/push/hub-sensor-temphum.js +62 -0
- package/lib/model/push/hub-subdevicelist.js +50 -0
- package/lib/model/push/hub-togglex.js +60 -0
- package/lib/model/push/index.js +81 -0
- package/lib/model/push/online.js +53 -0
- package/lib/model/push/presence-study.js +61 -0
- package/lib/model/push/sensor-latestx.js +106 -0
- package/lib/model/push/timerx.js +63 -0
- package/lib/model/push/togglex.js +78 -0
- package/lib/model/push/triggerx.js +62 -0
- package/lib/model/push/unbind.js +34 -0
- package/lib/model/push/water-leak.js +107 -0
- package/lib/model/states/diffuser-light-state.js +119 -0
- package/lib/model/states/diffuser-spray-state.js +58 -0
- package/lib/model/states/garage-door-state.js +71 -0
- package/lib/model/states/index.js +38 -0
- package/lib/model/states/light-state.js +134 -0
- package/lib/model/states/presence-sensor-state.js +239 -0
- package/lib/model/states/roller-shutter-state.js +82 -0
- package/lib/model/states/spray-state.js +58 -0
- package/lib/model/states/thermostat-state.js +297 -0
- package/lib/model/states/timer-state.js +192 -0
- package/lib/model/states/toggle-state.js +105 -0
- package/lib/model/states/trigger-state.js +155 -0
- package/lib/subscription.js +587 -0
- package/lib/utilities/conversion.js +62 -0
- package/lib/utilities/debug.js +165 -0
- package/lib/utilities/mqtt.js +152 -0
- package/lib/utilities/network.js +53 -0
- package/lib/utilities/options.js +64 -0
- package/lib/utilities/request-queue.js +161 -0
- package/lib/utilities/ssid.js +37 -0
- package/lib/utilities/state-changes.js +66 -0
- package/lib/utilities/stats.js +687 -0
- package/lib/utilities/timer.js +310 -0
- package/lib/utilities/trigger.js +286 -0
- package/package.json +73 -0
|
@@ -0,0 +1,687 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { parsePushNotification } = require('../../model/push');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Push notification namespace to data key mapping for hub features.
|
|
7
|
+
*
|
|
8
|
+
* Maps Meross push notification namespaces to their corresponding data keys in the notification payload.
|
|
9
|
+
*/
|
|
10
|
+
const PUSH_MAP = {
|
|
11
|
+
// Basic hub functionality
|
|
12
|
+
'Appliance.Hub.Online': 'online',
|
|
13
|
+
'Appliance.Hub.ToggleX': 'togglex',
|
|
14
|
+
'Appliance.Hub.Battery': 'battery',
|
|
15
|
+
'Appliance.Hub.Sensor.WaterLeak': 'waterLeak',
|
|
16
|
+
|
|
17
|
+
// Sensor hub functionality
|
|
18
|
+
'Appliance.Hub.Sensor.All': 'all',
|
|
19
|
+
'Appliance.Hub.Sensor.TempHum': 'tempHum',
|
|
20
|
+
'Appliance.Hub.Sensor.Alert': 'alert',
|
|
21
|
+
'Appliance.Hub.Sensor.Smoke': 'smokeAlarm',
|
|
22
|
+
'Appliance.Control.Sensor.LatestX': 'latest',
|
|
23
|
+
|
|
24
|
+
// MTS100 thermostat hub functionality
|
|
25
|
+
'Appliance.Hub.Mts100.All': 'all',
|
|
26
|
+
'Appliance.Hub.Mts100.Mode': 'mode',
|
|
27
|
+
'Appliance.Hub.Mts100.Temperature': 'temperature'
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Hub feature module.
|
|
32
|
+
* Provides functionality for hub devices including sensor management, MTS100 thermostat control,
|
|
33
|
+
* and automatic routing of push notifications to subdevices.
|
|
34
|
+
*/
|
|
35
|
+
module.exports = {
|
|
36
|
+
/**
|
|
37
|
+
* Handles push notifications for hub functionality.
|
|
38
|
+
*
|
|
39
|
+
* Routes notifications to appropriate subdevices based on the namespace. This method is called
|
|
40
|
+
* automatically by the base device when push notifications are received.
|
|
41
|
+
*
|
|
42
|
+
* @param {string} namespace - The namespace of the push notification
|
|
43
|
+
* @param {Object} data - The push notification data
|
|
44
|
+
* @returns {boolean} True if the notification was handled locally, false otherwise
|
|
45
|
+
* @private
|
|
46
|
+
*/
|
|
47
|
+
handlePushNotification(namespace, data) {
|
|
48
|
+
const dataKey = PUSH_MAP[namespace];
|
|
49
|
+
|
|
50
|
+
if (!dataKey) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const payload = data[dataKey];
|
|
55
|
+
if (!payload) {
|
|
56
|
+
const logger = this.cloudInst?.options?.logger || console.warn;
|
|
57
|
+
logger(`${this.constructor.name} could not find ${dataKey} attribute in push notification data: ${JSON.stringify(data)}`);
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const notification = parsePushNotification(namespace, data, this.uuid);
|
|
62
|
+
if (notification && typeof notification.routeToSubdevices === 'function') {
|
|
63
|
+
notification.routeToSubdevices(this);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return true;
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Collects subdevice IDs, separating sensors from MTS100 thermostats.
|
|
71
|
+
*
|
|
72
|
+
* Uses registered subdevices if available, otherwise falls back to subDeviceList array.
|
|
73
|
+
*
|
|
74
|
+
* @returns {{sensorIds: string[], mts100Ids: string[]}} Object containing arrays of sensor and MTS100 IDs
|
|
75
|
+
* @private
|
|
76
|
+
*/
|
|
77
|
+
_collectSubdeviceIds() {
|
|
78
|
+
const subdevices = this.getSubdevices();
|
|
79
|
+
const sensorIds = [];
|
|
80
|
+
const mts100Ids = [];
|
|
81
|
+
|
|
82
|
+
if (subdevices.length > 0) {
|
|
83
|
+
// Use registered subdevices
|
|
84
|
+
for (const sub of subdevices) {
|
|
85
|
+
if (sub.type === 'mts100v3') {
|
|
86
|
+
mts100Ids.push(sub.subdeviceId);
|
|
87
|
+
} else {
|
|
88
|
+
sensorIds.push(sub.subdeviceId);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
} else if (this.subDeviceList && Array.isArray(this.subDeviceList) && this.subDeviceList.length > 0) {
|
|
92
|
+
// Fallback to old array-based approach if subdevices not yet registered
|
|
93
|
+
for (const sub of this.subDeviceList) {
|
|
94
|
+
const subType = sub.subDeviceType || sub.type;
|
|
95
|
+
const subId = sub.subDeviceId || sub.id;
|
|
96
|
+
|
|
97
|
+
if (subType === 'mts100v3') {
|
|
98
|
+
mts100Ids.push(subId);
|
|
99
|
+
} else {
|
|
100
|
+
sensorIds.push(subId);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return { sensorIds, mts100Ids };
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Updates sensor subdevices by fetching sensor data, latest readings, and battery status.
|
|
110
|
+
*
|
|
111
|
+
* @param {string[]} sensorIds - Array of sensor subdevice IDs to update
|
|
112
|
+
* @returns {Promise<void>} Promise that resolves when sensor update is complete
|
|
113
|
+
* @private
|
|
114
|
+
*/
|
|
115
|
+
async _updateSensorSubdevices(sensorIds) {
|
|
116
|
+
if (sensorIds.length === 0) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
await this.getAllSensors(sensorIds);
|
|
121
|
+
|
|
122
|
+
try {
|
|
123
|
+
if (typeof this.getLatestHubSensorReadings === 'function') {
|
|
124
|
+
await this.getLatestHubSensorReadings(sensorIds, ['light', 'temp', 'humi']);
|
|
125
|
+
}
|
|
126
|
+
} catch (latestError) {
|
|
127
|
+
const logger = this.cloudInst?.options?.logger || console.debug;
|
|
128
|
+
logger(`Failed to fetch latest sensor readings: ${latestError.message}`);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
try {
|
|
132
|
+
if (typeof this.getHubBattery === 'function') {
|
|
133
|
+
await this.getHubBattery();
|
|
134
|
+
}
|
|
135
|
+
} catch (batteryError) {
|
|
136
|
+
const logger = this.cloudInst?.options?.logger || console.debug;
|
|
137
|
+
logger(`Failed to update battery data: ${batteryError.message}`);
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Updates MTS100 thermostat subdevices.
|
|
143
|
+
*
|
|
144
|
+
* @param {string[]} mts100Ids - Array of MTS100 subdevice IDs to update
|
|
145
|
+
* @returns {Promise<void>} Promise that resolves when MTS100 update is complete
|
|
146
|
+
* @private
|
|
147
|
+
*/
|
|
148
|
+
async _updateMts100Subdevices(mts100Ids) {
|
|
149
|
+
if (mts100Ids.length === 0) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
await this.getMts100All(mts100Ids);
|
|
154
|
+
},
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Overrides refreshState to update hub subdevices.
|
|
158
|
+
*
|
|
159
|
+
* Calls the parent refreshState implementation and then updates all hub subdevices
|
|
160
|
+
* automatically (sensors and MTS100 thermostats).
|
|
161
|
+
*
|
|
162
|
+
* @returns {Promise<void>} Promise that resolves when state is refreshed
|
|
163
|
+
* @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
|
|
164
|
+
* @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
|
|
165
|
+
*/
|
|
166
|
+
async refreshState() {
|
|
167
|
+
const { sensorIds, mts100Ids } = this._collectSubdeviceIds();
|
|
168
|
+
|
|
169
|
+
try {
|
|
170
|
+
await this._updateSensorSubdevices(sensorIds);
|
|
171
|
+
await this._updateMts100Subdevices(mts100Ids);
|
|
172
|
+
} catch (error) {
|
|
173
|
+
const logger = this.cloudInst?.options?.logger || console.error;
|
|
174
|
+
logger(`Error occurred during hub subdevice update: ${error.message}`);
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
|
|
178
|
+
// ===== Basic Hub Functionality =====
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Gets the hub's battery status.
|
|
182
|
+
*
|
|
183
|
+
* Automatically routes battery data to the appropriate subdevices when the response is received.
|
|
184
|
+
*
|
|
185
|
+
* @returns {Promise<Object>} Promise that resolves with battery data containing `battery` array
|
|
186
|
+
* @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
|
|
187
|
+
* @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
|
|
188
|
+
*/
|
|
189
|
+
async getHubBattery() {
|
|
190
|
+
const payload = { 'battery': [] };
|
|
191
|
+
const response = await this.publishMessage('GET', 'Appliance.Hub.Battery', payload, null);
|
|
192
|
+
|
|
193
|
+
if (response && response.battery && Array.isArray(response.battery)) {
|
|
194
|
+
for (const batteryData of response.battery) {
|
|
195
|
+
const subdeviceId = batteryData.id;
|
|
196
|
+
const subdevice = this.getSubdevice(subdeviceId);
|
|
197
|
+
if (subdevice && typeof subdevice.handleSubdeviceNotification === 'function') {
|
|
198
|
+
await subdevice.handleSubdeviceNotification('Appliance.Hub.Battery', batteryData);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return response;
|
|
204
|
+
},
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Gets the hub's online status.
|
|
208
|
+
*
|
|
209
|
+
* @returns {Promise<Object>} Promise that resolves with online status data
|
|
210
|
+
* @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
|
|
211
|
+
* @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
|
|
212
|
+
*/
|
|
213
|
+
async getHubOnline() {
|
|
214
|
+
return await this.publishMessage('GET', 'Appliance.Hub.Online', {});
|
|
215
|
+
},
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Controls a hub toggleX subdevice (on/off).
|
|
219
|
+
*
|
|
220
|
+
* @param {string} subId - Subdevice ID
|
|
221
|
+
* @param {boolean} onoff - True to turn on, false to turn off
|
|
222
|
+
* @returns {Promise<Object>} Promise that resolves with response data
|
|
223
|
+
* @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
|
|
224
|
+
* @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
|
|
225
|
+
*/
|
|
226
|
+
async setHubToggleX(subId, onoff) {
|
|
227
|
+
const payload = { 'togglex': [{ 'id': subId, 'onoff': onoff ? 1 : 0 }] };
|
|
228
|
+
return await this.publishMessage('SET', 'Appliance.Hub.ToggleX', payload);
|
|
229
|
+
},
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Gets the hub's exception information.
|
|
233
|
+
*
|
|
234
|
+
* @returns {Promise<Object>} Promise that resolves with exception data
|
|
235
|
+
* @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
|
|
236
|
+
* @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
|
|
237
|
+
*/
|
|
238
|
+
async getHubException() {
|
|
239
|
+
return await this.publishMessage('GET', 'Appliance.Hub.Exception', {});
|
|
240
|
+
},
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Gets the hub's report information.
|
|
244
|
+
*
|
|
245
|
+
* @returns {Promise<Object>} Promise that resolves with report data
|
|
246
|
+
* @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
|
|
247
|
+
* @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
|
|
248
|
+
*/
|
|
249
|
+
async getHubReport() {
|
|
250
|
+
return await this.publishMessage('GET', 'Appliance.Hub.Report', {});
|
|
251
|
+
},
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Initiates pairing of a subdevice to the hub.
|
|
255
|
+
*
|
|
256
|
+
* @returns {Promise<Object>} Promise that resolves with response data
|
|
257
|
+
* @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
|
|
258
|
+
* @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
|
|
259
|
+
*/
|
|
260
|
+
async setHubPairSubDev() {
|
|
261
|
+
return await this.publishMessage('SET', 'Appliance.Hub.PairSubDev', {});
|
|
262
|
+
},
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Controls the beep/buzzer of a hub subdevice.
|
|
266
|
+
*
|
|
267
|
+
* @param {string|Array<string>} subIds - Subdevice ID(s) to control
|
|
268
|
+
* @param {boolean} onoff - True to turn on buzzer, false to turn off
|
|
269
|
+
* @returns {Promise<Object>} Promise that resolves with response data
|
|
270
|
+
* @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
|
|
271
|
+
* @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
|
|
272
|
+
*/
|
|
273
|
+
async setHubSubDeviceBeep(subIds, onoff) {
|
|
274
|
+
const payload = { 'alarm': [] };
|
|
275
|
+
const ids = Array.isArray(subIds) ? subIds : [subIds];
|
|
276
|
+
ids.forEach(id => payload.alarm.push({ id, onoff: onoff ? 1 : 0 }));
|
|
277
|
+
return await this.publishMessage('SET', 'Appliance.Hub.SubDevice.Beep', payload);
|
|
278
|
+
},
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Gets the beep/buzzer status of hub subdevices.
|
|
282
|
+
*
|
|
283
|
+
* @param {string|Array<string>} subIds - Subdevice ID(s) to query
|
|
284
|
+
* @returns {Promise<Object>} Promise that resolves with beep status data containing `alarm` array
|
|
285
|
+
* @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
|
|
286
|
+
* @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
|
|
287
|
+
*/
|
|
288
|
+
async getHubSubDeviceBeep(subIds) {
|
|
289
|
+
const payload = { 'alarm': [] };
|
|
290
|
+
const ids = Array.isArray(subIds) ? subIds : [subIds];
|
|
291
|
+
ids.forEach(id => payload.alarm.push({ id }));
|
|
292
|
+
return await this.publishMessage('GET', 'Appliance.Hub.SubDevice.Beep', payload);
|
|
293
|
+
},
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Gets the motor adjustment schedule for hub subdevices.
|
|
297
|
+
*
|
|
298
|
+
* @param {string|Array<string>} subIds - Subdevice ID(s) to query
|
|
299
|
+
* @returns {Promise<Object>} Promise that resolves with motor adjustment data containing `adjust` array
|
|
300
|
+
* @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
|
|
301
|
+
* @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
|
|
302
|
+
*/
|
|
303
|
+
async getHubSubDeviceMotorAdjust(subIds) {
|
|
304
|
+
const payload = { 'adjust': [] };
|
|
305
|
+
const ids = Array.isArray(subIds) ? subIds : [subIds];
|
|
306
|
+
ids.forEach(id => payload.adjust.push({ id }));
|
|
307
|
+
return await this.publishMessage('GET', 'Appliance.Hub.SubDevice.MotorAdjust', payload);
|
|
308
|
+
},
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Controls the motor adjustment schedule for hub subdevices.
|
|
312
|
+
*
|
|
313
|
+
* @param {Object|Array<Object>} adjustData - Motor adjustment data
|
|
314
|
+
* @param {string} [adjustData.id] - Subdevice ID
|
|
315
|
+
* @param {number} [adjustData.days] - Days for schedule
|
|
316
|
+
* @param {number} [adjustData.minutes] - Minutes for schedule
|
|
317
|
+
* @param {boolean} [adjustData.enable] - Enable/disable schedule
|
|
318
|
+
* @returns {Promise<Object>} Promise that resolves with response data
|
|
319
|
+
* @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
|
|
320
|
+
* @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
|
|
321
|
+
*/
|
|
322
|
+
async setHubSubDeviceMotorAdjust(adjustData) {
|
|
323
|
+
const payload = { 'adjust': Array.isArray(adjustData) ? adjustData : [adjustData] };
|
|
324
|
+
return await this.publishMessage('SET', 'Appliance.Hub.SubDevice.MotorAdjust', payload);
|
|
325
|
+
},
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Gets the version information for hub subdevices.
|
|
329
|
+
*
|
|
330
|
+
* @param {string|Array<string>} [subIds=[]] - Subdevice ID(s), empty array gets all
|
|
331
|
+
* @returns {Promise<Object>} Promise that resolves with version data containing `version` array
|
|
332
|
+
* @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
|
|
333
|
+
* @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
|
|
334
|
+
*/
|
|
335
|
+
async getHubSubDeviceVersion(subIds = []) {
|
|
336
|
+
const payload = { 'version': [] };
|
|
337
|
+
if (Array.isArray(subIds) && subIds.length > 0) {
|
|
338
|
+
subIds.forEach(id => payload.version.push({ id }));
|
|
339
|
+
}
|
|
340
|
+
return await this.publishMessage('GET', 'Appliance.Hub.SubDevice.Version', payload);
|
|
341
|
+
},
|
|
342
|
+
|
|
343
|
+
// ===== Sensor Hub Functionality =====
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Gets all sensor data for specified sensor IDs.
|
|
347
|
+
*
|
|
348
|
+
* @param {string|Array<string>} sensorIds - Single sensor ID or array of sensor IDs
|
|
349
|
+
* @returns {Promise<Object>} Promise that resolves with sensor data containing `all` array
|
|
350
|
+
* @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
|
|
351
|
+
* @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
|
|
352
|
+
*/
|
|
353
|
+
async getAllSensors(sensorIds) {
|
|
354
|
+
const payload = { 'all': [] };
|
|
355
|
+
if (Array.isArray(sensorIds)) {
|
|
356
|
+
sensorIds.forEach(id => payload.all.push({ id }));
|
|
357
|
+
} else {
|
|
358
|
+
payload.all.push({ id: sensorIds });
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
const response = await this.publishMessage('GET', 'Appliance.Hub.Sensor.All', payload);
|
|
362
|
+
|
|
363
|
+
if (response && response.all && Array.isArray(response.all)) {
|
|
364
|
+
for (const sensorData of response.all) {
|
|
365
|
+
const subdeviceId = sensorData.id;
|
|
366
|
+
const subdevice = this.getSubdevice(subdeviceId);
|
|
367
|
+
if (subdevice && typeof subdevice.handleSubdeviceNotification === 'function') {
|
|
368
|
+
await subdevice.handleSubdeviceNotification('Appliance.Hub.Sensor.All', sensorData);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
return response;
|
|
374
|
+
},
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Gets latest sensor readings (temperature, humidity, and light/lux) for specified sensor IDs.
|
|
378
|
+
*
|
|
379
|
+
* This method fetches the most recent readings including lux data which is not available
|
|
380
|
+
* in getAllSensors. The data is automatically routed to the appropriate subdevices.
|
|
381
|
+
*
|
|
382
|
+
* @param {string|Array<string>} sensorIds - Single sensor ID or array of sensor IDs
|
|
383
|
+
* @param {Array<string>} [dataTypes=['light', 'temp', 'humi']] - Array of data types to request
|
|
384
|
+
* @returns {Promise<Object>} Promise that resolves with latest sensor data containing `latest` array
|
|
385
|
+
* @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
|
|
386
|
+
* @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
|
|
387
|
+
*/
|
|
388
|
+
async getLatestHubSensorReadings(sensorIds, dataTypes = ['light', 'temp', 'humi']) {
|
|
389
|
+
const payload = { 'latest': [] };
|
|
390
|
+
const sensorIdArray = Array.isArray(sensorIds) ? sensorIds : [sensorIds];
|
|
391
|
+
|
|
392
|
+
sensorIdArray.forEach(subId => {
|
|
393
|
+
payload.latest.push({
|
|
394
|
+
subId,
|
|
395
|
+
channel: 0,
|
|
396
|
+
data: dataTypes
|
|
397
|
+
});
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
const response = await this.publishMessage('GET', 'Appliance.Control.Sensor.LatestX', payload, null);
|
|
401
|
+
|
|
402
|
+
if (response && response.latest && Array.isArray(response.latest)) {
|
|
403
|
+
for (const latestData of response.latest) {
|
|
404
|
+
const subdeviceId = latestData.subId;
|
|
405
|
+
const subdevice = this.getSubdevice(subdeviceId);
|
|
406
|
+
if (subdevice && typeof subdevice.handleSubdeviceNotification === 'function') {
|
|
407
|
+
await subdevice.handleSubdeviceNotification('Appliance.Control.Sensor.LatestX', latestData);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
return response;
|
|
413
|
+
},
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Gets temperature and humidity sensor data for specified sensor IDs.
|
|
417
|
+
*
|
|
418
|
+
* @param {string|Array<string>} sensorIds - Single sensor ID or array of sensor IDs
|
|
419
|
+
* @returns {Promise<Object>} Promise that resolves with temperature/humidity data containing `tempHum` array
|
|
420
|
+
* @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
|
|
421
|
+
* @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
|
|
422
|
+
*/
|
|
423
|
+
async getTempHumSensor(sensorIds) {
|
|
424
|
+
const payload = { 'tempHum': [] };
|
|
425
|
+
if (Array.isArray(sensorIds)) {
|
|
426
|
+
sensorIds.forEach(id => payload.tempHum.push({ id }));
|
|
427
|
+
} else {
|
|
428
|
+
payload.tempHum.push({ id: sensorIds });
|
|
429
|
+
}
|
|
430
|
+
return await this.publishMessage('GET', 'Appliance.Hub.Sensor.TempHum', payload);
|
|
431
|
+
},
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Gets alert sensor data for specified sensor IDs.
|
|
435
|
+
*
|
|
436
|
+
* @param {string|Array<string>} sensorIds - Single sensor ID or array of sensor IDs
|
|
437
|
+
* @returns {Promise<Object>} Promise that resolves with alert sensor data containing `alert` array
|
|
438
|
+
* @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
|
|
439
|
+
* @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
|
|
440
|
+
*/
|
|
441
|
+
async getAlertSensor(sensorIds) {
|
|
442
|
+
const payload = { 'alert': [] };
|
|
443
|
+
if (Array.isArray(sensorIds)) {
|
|
444
|
+
sensorIds.forEach(id => payload.alert.push({ id }));
|
|
445
|
+
} else {
|
|
446
|
+
payload.alert.push({ id: sensorIds });
|
|
447
|
+
}
|
|
448
|
+
return await this.publishMessage('GET', 'Appliance.Hub.Sensor.Alert', payload);
|
|
449
|
+
},
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Gets smoke alarm status for specified smoke detector IDs.
|
|
453
|
+
*
|
|
454
|
+
* The data is automatically routed to the appropriate subdevices.
|
|
455
|
+
*
|
|
456
|
+
* @param {string|Array<string>} sensorIds - Single sensor ID or array of sensor IDs
|
|
457
|
+
* @returns {Promise<Object>} Promise that resolves with smoke alarm status data containing `smokeAlarm` array
|
|
458
|
+
* @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
|
|
459
|
+
* @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
|
|
460
|
+
*/
|
|
461
|
+
async getSmokeAlarmStatus(sensorIds) {
|
|
462
|
+
const payload = { 'smokeAlarm': [] };
|
|
463
|
+
if (Array.isArray(sensorIds)) {
|
|
464
|
+
sensorIds.forEach(id => payload.smokeAlarm.push({ id }));
|
|
465
|
+
} else {
|
|
466
|
+
payload.smokeAlarm.push({ id: sensorIds });
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
const response = await this.publishMessage('GET', 'Appliance.Hub.Sensor.Smoke', payload);
|
|
470
|
+
|
|
471
|
+
if (response && response.smokeAlarm && Array.isArray(response.smokeAlarm)) {
|
|
472
|
+
for (const smokeData of response.smokeAlarm) {
|
|
473
|
+
const subdeviceId = smokeData.id;
|
|
474
|
+
const subdevice = this.getSubdevice(subdeviceId);
|
|
475
|
+
if (subdevice && typeof subdevice.handleSubdeviceNotification === 'function') {
|
|
476
|
+
await subdevice.handleSubdeviceNotification('Appliance.Hub.Sensor.Smoke', smokeData);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
return response;
|
|
482
|
+
},
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Gets water leak sensor data for specified sensor IDs.
|
|
486
|
+
*
|
|
487
|
+
* @param {string|Array<string>} sensorIds - Single sensor ID or array of sensor IDs
|
|
488
|
+
* @returns {Promise<Object>} Promise that resolves with water leak sensor data containing `waterleak` array
|
|
489
|
+
* @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
|
|
490
|
+
* @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
|
|
491
|
+
*/
|
|
492
|
+
async getWaterLeakSensor(sensorIds) {
|
|
493
|
+
const payload = { 'waterleak': [] };
|
|
494
|
+
if (Array.isArray(sensorIds)) {
|
|
495
|
+
sensorIds.forEach(id => payload.waterleak.push({ id }));
|
|
496
|
+
} else {
|
|
497
|
+
payload.waterleak.push({ id: sensorIds });
|
|
498
|
+
}
|
|
499
|
+
return await this.publishMessage('GET', 'Appliance.Hub.Sensor.WaterLeak', payload);
|
|
500
|
+
},
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Gets sensor adjustment (calibration) settings for specified sensor IDs.
|
|
504
|
+
*
|
|
505
|
+
* @param {string|Array<string>} [sensorIds=[]] - Single sensor ID or array of sensor IDs, empty array gets all
|
|
506
|
+
* @returns {Promise<Object>} Promise that resolves with sensor adjustment data containing `adjust` array
|
|
507
|
+
* @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
|
|
508
|
+
* @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
|
|
509
|
+
*/
|
|
510
|
+
async getHubSensorAdjust(sensorIds = []) {
|
|
511
|
+
const payload = { 'adjust': [] };
|
|
512
|
+
if (Array.isArray(sensorIds) && sensorIds.length > 0) {
|
|
513
|
+
sensorIds.forEach(id => payload.adjust.push({ id }));
|
|
514
|
+
}
|
|
515
|
+
return await this.publishMessage('GET', 'Appliance.Hub.Sensor.Adjust', payload);
|
|
516
|
+
},
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* Controls (sets) sensor adjustment (calibration) settings.
|
|
520
|
+
*
|
|
521
|
+
* @param {Object|Array<Object>} adjustData - Sensor adjustment data
|
|
522
|
+
* @param {string} [adjustData.id] - Sensor ID
|
|
523
|
+
* @param {number} [adjustData.temperature] - Temperature adjustment offset
|
|
524
|
+
* @param {number} [adjustData.humidity] - Humidity adjustment offset
|
|
525
|
+
* @returns {Promise<Object>} Promise that resolves with response data
|
|
526
|
+
* @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
|
|
527
|
+
* @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
|
|
528
|
+
*/
|
|
529
|
+
async setHubSensorAdjust(adjustData) {
|
|
530
|
+
const payload = { 'adjust': Array.isArray(adjustData) ? adjustData : [adjustData] };
|
|
531
|
+
return await this.publishMessage('SET', 'Appliance.Hub.Sensor.Adjust', payload);
|
|
532
|
+
},
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Gets door/window sensor data for specified sensor IDs.
|
|
536
|
+
*
|
|
537
|
+
* @param {string|Array<string>} [sensorIds=[]] - Single sensor ID or array of sensor IDs, empty array gets all (max 16)
|
|
538
|
+
* @returns {Promise<Object>} Promise that resolves with door/window sensor data containing `doorWindow` array
|
|
539
|
+
* @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
|
|
540
|
+
* @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
|
|
541
|
+
*/
|
|
542
|
+
async getHubSensorDoorWindow(sensorIds = []) {
|
|
543
|
+
const payload = { 'doorWindow': [] };
|
|
544
|
+
if (Array.isArray(sensorIds) && sensorIds.length > 0) {
|
|
545
|
+
sensorIds.forEach(id => payload.doorWindow.push({ id }));
|
|
546
|
+
}
|
|
547
|
+
return await this.publishMessage('GET', 'Appliance.Hub.Sensor.DoorWindow', payload);
|
|
548
|
+
},
|
|
549
|
+
|
|
550
|
+
/**
|
|
551
|
+
* Controls (sets) door/window sensor synchronization (if supported).
|
|
552
|
+
*
|
|
553
|
+
* Note: This namespace primarily supports GET and PUSH, SET may not be available for all devices.
|
|
554
|
+
*
|
|
555
|
+
* @param {Object|Array<Object>} doorWindowData - Door/window data
|
|
556
|
+
* @returns {Promise<Object>} Promise that resolves with response data
|
|
557
|
+
* @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
|
|
558
|
+
* @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
|
|
559
|
+
*/
|
|
560
|
+
async setHubSensorDoorWindow(doorWindowData) {
|
|
561
|
+
const payload = { 'doorWindow': Array.isArray(doorWindowData) ? doorWindowData : [doorWindowData] };
|
|
562
|
+
return await this.publishMessage('SET', 'Appliance.Hub.Sensor.DoorWindow', payload);
|
|
563
|
+
},
|
|
564
|
+
|
|
565
|
+
// ===== MTS100 Thermostat Hub Functionality =====
|
|
566
|
+
|
|
567
|
+
/**
|
|
568
|
+
* Gets MTS100 thermostat valve data for specified IDs.
|
|
569
|
+
*
|
|
570
|
+
* @param {Array<string>} ids - Array of MTS100 subdevice IDs
|
|
571
|
+
* @returns {Promise<Object>} Promise that resolves with MTS100 data containing `all` array
|
|
572
|
+
* @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
|
|
573
|
+
* @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
|
|
574
|
+
*/
|
|
575
|
+
async getMts100All(ids) {
|
|
576
|
+
const payload = { 'all': [] };
|
|
577
|
+
ids.forEach(id => payload.all.push({ id }));
|
|
578
|
+
return await this.publishMessage('GET', 'Appliance.Hub.Mts100.All', payload, null);
|
|
579
|
+
},
|
|
580
|
+
|
|
581
|
+
/**
|
|
582
|
+
* Controls MTS100 thermostat mode.
|
|
583
|
+
*
|
|
584
|
+
* @param {string} subId - MTS100 subdevice ID
|
|
585
|
+
* @param {number|import('../lib/enums').ThermostatMode} mode - Mode value from ThermostatMode enum
|
|
586
|
+
* @returns {Promise<Object>} Promise that resolves with response data
|
|
587
|
+
* @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
|
|
588
|
+
* @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
|
|
589
|
+
*/
|
|
590
|
+
async setHubMts100Mode(subId, mode) {
|
|
591
|
+
const payload = { 'mode': [{ 'id': subId, 'state': mode }] };
|
|
592
|
+
return await this.publishMessage('SET', 'Appliance.Hub.Mts100.Mode', payload);
|
|
593
|
+
},
|
|
594
|
+
|
|
595
|
+
/**
|
|
596
|
+
* Controls MTS100 thermostat temperature settings.
|
|
597
|
+
*
|
|
598
|
+
* Mutates the temp object by adding the subId property before sending the command.
|
|
599
|
+
*
|
|
600
|
+
* @param {string} subId - MTS100 subdevice ID
|
|
601
|
+
* @param {Object} temp - Temperature object (will be mutated with subId)
|
|
602
|
+
* @param {number} [temp.temperature] - Target temperature
|
|
603
|
+
* @param {number} [temp.min] - Minimum temperature
|
|
604
|
+
* @param {number} [temp.max] - Maximum temperature * @returns {Promise<Object>} Promise that resolves with response data
|
|
605
|
+
* @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
|
|
606
|
+
* @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
|
|
607
|
+
*/
|
|
608
|
+
async setHubMts100Temperature(subId, temp) {
|
|
609
|
+
temp.id = subId;
|
|
610
|
+
const payload = { 'temperature': [temp] };
|
|
611
|
+
return await this.publishMessage('SET', 'Appliance.Hub.Mts100.Temperature', payload);
|
|
612
|
+
},
|
|
613
|
+
|
|
614
|
+
/**
|
|
615
|
+
* Controls MTS100 thermostat adjustment settings.
|
|
616
|
+
*
|
|
617
|
+
* Mutates the adjustData object by adding the subId property before sending the command.
|
|
618
|
+
*
|
|
619
|
+
* @param {string} subId - MTS100 subdevice ID
|
|
620
|
+
* @param {Object} adjustData - Adjustment data object (will be mutated with subId)
|
|
621
|
+
* @returns {Promise<Object>} Promise that resolves with response data
|
|
622
|
+
* @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
|
|
623
|
+
* @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
|
|
624
|
+
*/
|
|
625
|
+
async setHubMts100Adjust(subId, adjustData) {
|
|
626
|
+
adjustData.id = subId;
|
|
627
|
+
const payload = { 'adjust': [adjustData] };
|
|
628
|
+
return await this.publishMessage('SET', 'Appliance.Hub.Mts100.Adjust', payload);
|
|
629
|
+
},
|
|
630
|
+
|
|
631
|
+
/**
|
|
632
|
+
* Gets MTS100 adjustment settings for specified IDs.
|
|
633
|
+
*
|
|
634
|
+
* @param {Array<string>} ids - Array of MTS100 subdevice IDs
|
|
635
|
+
* @returns {Promise<Object>} Promise that resolves with adjustment data containing `adjust` array
|
|
636
|
+
* @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
|
|
637
|
+
* @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
|
|
638
|
+
*/
|
|
639
|
+
async getMts100Adjust(ids) {
|
|
640
|
+
const payload = { 'adjust': [] };
|
|
641
|
+
ids.forEach(id => payload.adjust.push({ id }));
|
|
642
|
+
return await this.publishMessage('GET', 'Appliance.Hub.Mts100.Adjust', payload);
|
|
643
|
+
},
|
|
644
|
+
|
|
645
|
+
/**
|
|
646
|
+
* Gets MTS100 super control data for specified IDs.
|
|
647
|
+
*
|
|
648
|
+
* @param {Array<string>} ids - Array of MTS100 subdevice IDs
|
|
649
|
+
* @returns {Promise<Object>} Promise that resolves with super control data containing `superCtl` array
|
|
650
|
+
* @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
|
|
651
|
+
* @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
|
|
652
|
+
*/
|
|
653
|
+
async getMts100SuperCtl(ids) {
|
|
654
|
+
const payload = { 'superCtl': [] };
|
|
655
|
+
ids.forEach(id => payload.superCtl.push({ id }));
|
|
656
|
+
return await this.publishMessage('GET', 'Appliance.Hub.Mts100.SuperCtl', payload);
|
|
657
|
+
},
|
|
658
|
+
|
|
659
|
+
/**
|
|
660
|
+
* Gets MTS100 schedule B data for specified IDs.
|
|
661
|
+
*
|
|
662
|
+
* @param {Array<string>} ids - Array of MTS100 subdevice IDs
|
|
663
|
+
* @returns {Promise<Object>} Promise that resolves with schedule B data containing `scheduleB` array
|
|
664
|
+
* @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
|
|
665
|
+
* @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
|
|
666
|
+
*/
|
|
667
|
+
async getMts100ScheduleB(ids) {
|
|
668
|
+
const payload = { 'scheduleB': [] };
|
|
669
|
+
ids.forEach(id => payload.scheduleB.push({ id }));
|
|
670
|
+
return await this.publishMessage('GET', 'Appliance.Hub.Mts100.ScheduleB', payload);
|
|
671
|
+
},
|
|
672
|
+
|
|
673
|
+
/**
|
|
674
|
+
* Gets MTS100 configuration for specified IDs.
|
|
675
|
+
*
|
|
676
|
+
* @param {Array<string>} ids - Array of MTS100 subdevice IDs
|
|
677
|
+
* @returns {Promise<Object>} Promise that resolves with configuration data containing `config` array
|
|
678
|
+
* @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
|
|
679
|
+
* @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
|
|
680
|
+
*/
|
|
681
|
+
async getMts100Config(ids) {
|
|
682
|
+
const payload = { 'config': [] };
|
|
683
|
+
ids.forEach(id => payload.config.push({ id }));
|
|
684
|
+
return await this.publishMessage('GET', 'Appliance.Hub.Mts100.Config', payload);
|
|
685
|
+
}
|
|
686
|
+
};
|
|
687
|
+
|