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.
Files changed (99) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/LICENSE +21 -0
  3. package/README.md +153 -0
  4. package/index.d.ts +2344 -0
  5. package/index.js +131 -0
  6. package/lib/controller/device.js +1317 -0
  7. package/lib/controller/features/alarm-feature.js +89 -0
  8. package/lib/controller/features/child-lock-feature.js +61 -0
  9. package/lib/controller/features/config-feature.js +54 -0
  10. package/lib/controller/features/consumption-feature.js +210 -0
  11. package/lib/controller/features/control-feature.js +62 -0
  12. package/lib/controller/features/diffuser-feature.js +411 -0
  13. package/lib/controller/features/digest-timer-feature.js +22 -0
  14. package/lib/controller/features/digest-trigger-feature.js +22 -0
  15. package/lib/controller/features/dnd-feature.js +79 -0
  16. package/lib/controller/features/electricity-feature.js +144 -0
  17. package/lib/controller/features/encryption-feature.js +259 -0
  18. package/lib/controller/features/garage-feature.js +337 -0
  19. package/lib/controller/features/hub-feature.js +687 -0
  20. package/lib/controller/features/light-feature.js +408 -0
  21. package/lib/controller/features/presence-sensor-feature.js +297 -0
  22. package/lib/controller/features/roller-shutter-feature.js +456 -0
  23. package/lib/controller/features/runtime-feature.js +74 -0
  24. package/lib/controller/features/screen-feature.js +67 -0
  25. package/lib/controller/features/sensor-history-feature.js +47 -0
  26. package/lib/controller/features/smoke-config-feature.js +50 -0
  27. package/lib/controller/features/spray-feature.js +166 -0
  28. package/lib/controller/features/system-feature.js +269 -0
  29. package/lib/controller/features/temp-unit-feature.js +55 -0
  30. package/lib/controller/features/thermostat-feature.js +804 -0
  31. package/lib/controller/features/timer-feature.js +507 -0
  32. package/lib/controller/features/toggle-feature.js +223 -0
  33. package/lib/controller/features/trigger-feature.js +333 -0
  34. package/lib/controller/hub-device.js +185 -0
  35. package/lib/controller/subdevice.js +1537 -0
  36. package/lib/device-factory.js +463 -0
  37. package/lib/error-budget.js +138 -0
  38. package/lib/http-api.js +766 -0
  39. package/lib/manager.js +1609 -0
  40. package/lib/model/channel-info.js +79 -0
  41. package/lib/model/constants.js +119 -0
  42. package/lib/model/enums.js +819 -0
  43. package/lib/model/exception.js +363 -0
  44. package/lib/model/http/device.js +215 -0
  45. package/lib/model/http/error-codes.js +121 -0
  46. package/lib/model/http/exception.js +151 -0
  47. package/lib/model/http/subdevice.js +133 -0
  48. package/lib/model/push/alarm.js +112 -0
  49. package/lib/model/push/bind.js +97 -0
  50. package/lib/model/push/common.js +282 -0
  51. package/lib/model/push/diffuser-light.js +100 -0
  52. package/lib/model/push/diffuser-spray.js +83 -0
  53. package/lib/model/push/factory.js +229 -0
  54. package/lib/model/push/generic.js +115 -0
  55. package/lib/model/push/hub-battery.js +59 -0
  56. package/lib/model/push/hub-mts100-all.js +64 -0
  57. package/lib/model/push/hub-mts100-mode.js +59 -0
  58. package/lib/model/push/hub-mts100-temperature.js +62 -0
  59. package/lib/model/push/hub-online.js +59 -0
  60. package/lib/model/push/hub-sensor-alert.js +61 -0
  61. package/lib/model/push/hub-sensor-all.js +59 -0
  62. package/lib/model/push/hub-sensor-smoke.js +110 -0
  63. package/lib/model/push/hub-sensor-temphum.js +62 -0
  64. package/lib/model/push/hub-subdevicelist.js +50 -0
  65. package/lib/model/push/hub-togglex.js +60 -0
  66. package/lib/model/push/index.js +81 -0
  67. package/lib/model/push/online.js +53 -0
  68. package/lib/model/push/presence-study.js +61 -0
  69. package/lib/model/push/sensor-latestx.js +106 -0
  70. package/lib/model/push/timerx.js +63 -0
  71. package/lib/model/push/togglex.js +78 -0
  72. package/lib/model/push/triggerx.js +62 -0
  73. package/lib/model/push/unbind.js +34 -0
  74. package/lib/model/push/water-leak.js +107 -0
  75. package/lib/model/states/diffuser-light-state.js +119 -0
  76. package/lib/model/states/diffuser-spray-state.js +58 -0
  77. package/lib/model/states/garage-door-state.js +71 -0
  78. package/lib/model/states/index.js +38 -0
  79. package/lib/model/states/light-state.js +134 -0
  80. package/lib/model/states/presence-sensor-state.js +239 -0
  81. package/lib/model/states/roller-shutter-state.js +82 -0
  82. package/lib/model/states/spray-state.js +58 -0
  83. package/lib/model/states/thermostat-state.js +297 -0
  84. package/lib/model/states/timer-state.js +192 -0
  85. package/lib/model/states/toggle-state.js +105 -0
  86. package/lib/model/states/trigger-state.js +155 -0
  87. package/lib/subscription.js +587 -0
  88. package/lib/utilities/conversion.js +62 -0
  89. package/lib/utilities/debug.js +165 -0
  90. package/lib/utilities/mqtt.js +152 -0
  91. package/lib/utilities/network.js +53 -0
  92. package/lib/utilities/options.js +64 -0
  93. package/lib/utilities/request-queue.js +161 -0
  94. package/lib/utilities/ssid.js +37 -0
  95. package/lib/utilities/state-changes.js +66 -0
  96. package/lib/utilities/stats.js +687 -0
  97. package/lib/utilities/timer.js +310 -0
  98. package/lib/utilities/trigger.js +286 -0
  99. package/package.json +73 -0
@@ -0,0 +1,50 @@
1
+ 'use strict';
2
+
3
+ const { normalizeChannel } = require('../../utilities/options');
4
+
5
+ /**
6
+ * Smoke sensor configuration feature module.
7
+ * Provides control over smoke sensor settings including detection and do-not-disturb modes.
8
+ */
9
+ module.exports = {
10
+ /**
11
+ * Gets the smoke sensor configuration from the device.
12
+ *
13
+ * @param {Object} [options={}] - Get options
14
+ * @param {number} [options.channel=0] - Channel to get config for (default: 0)
15
+ * @param {string} [options.subId=null] - Optional subdevice ID
16
+ * @returns {Promise<Object>} Response containing smoke sensor configuration with `config` array
17
+ * @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
18
+ * @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
19
+ */
20
+ async getSmokeConfig(options = {}) {
21
+ const channel = normalizeChannel(options);
22
+ const payload = {
23
+ config: [{
24
+ channel
25
+ }]
26
+ };
27
+ if (options.subId) {
28
+ payload.config[0].subId = options.subId;
29
+ }
30
+ return await this.publishMessage('GET', 'Appliance.Control.Smoke.Config', payload);
31
+ },
32
+
33
+ /**
34
+ * Controls the smoke sensor configuration.
35
+ *
36
+ * @param {Object|Array<Object>} configData - Config data object or array of config items
37
+ * @param {number} [configData.channel] - Channel to configure
38
+ * @param {string} [configData.subId] - Optional subdevice ID
39
+ * @param {boolean} [configData.dnd] - Do not disturb mode
40
+ * @param {boolean} [configData.detect] - Detection enabled
41
+ * @returns {Promise<Object>} Response from the device
42
+ * @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
43
+ * @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
44
+ */
45
+ async setSmokeConfig(configData) {
46
+ const payload = { config: Array.isArray(configData) ? configData : [configData] };
47
+ return await this.publishMessage('SET', 'Appliance.Control.Smoke.Config', payload);
48
+ }
49
+ };
50
+
@@ -0,0 +1,166 @@
1
+ 'use strict';
2
+
3
+ const SprayState = require('../../model/states/spray-state');
4
+ const { SprayMode } = require('../../model/enums');
5
+ const { normalizeChannel } = require('../../utilities/options');
6
+
7
+ /**
8
+ * Spray feature module.
9
+ * Provides control over spray/mist functionality for devices that support it.
10
+ */
11
+ module.exports = {
12
+ /**
13
+ * Controls the spray mode.
14
+ *
15
+ * Supports both SprayMode enum objects and numeric values. If an enum object is provided,
16
+ * extracts the numeric value automatically.
17
+ *
18
+ * @param {Object} options - Spray options
19
+ * @param {number} [options.channel=0] - Channel to control (default: 0)
20
+ * @param {number|import('../lib/enums').SprayMode} options.mode - Spray mode value or SprayMode enum
21
+ * @returns {Promise<Object>} Response from the device containing the updated spray state
22
+ * @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
23
+ * @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
24
+ */
25
+ async setSpray(options = {}) {
26
+ if (options.mode === undefined) {
27
+ throw new Error('mode is required');
28
+ }
29
+ const channel = normalizeChannel(options);
30
+ const modeValue = options.mode || 0;
31
+
32
+ const payload = { 'spray': { channel, 'mode': modeValue } };
33
+ const response = await this.publishMessage('SET', 'Appliance.Control.Spray', payload);
34
+
35
+ if (response && response.spray) {
36
+ this._updateSprayState(response.spray, 'response');
37
+ this._lastFullUpdateTimestamp = Date.now();
38
+ } else {
39
+ this._updateSprayState({ channel, mode: modeValue }, 'response');
40
+ this._lastFullUpdateTimestamp = Date.now();
41
+ }
42
+
43
+ return response;
44
+ },
45
+
46
+ /**
47
+ * Gets the current spray state from the device.
48
+ *
49
+ * Use {@link getCachedSprayState} to get cached state without making a request.
50
+ * @param {Object} [options={}] - Get options
51
+ * @returns {Promise<Object>} Response containing spray state with `spray` object
52
+ * @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
53
+ * @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
54
+ */
55
+ async getSprayState(_options = {}) {
56
+ const response = await this.publishMessage('GET', 'Appliance.Control.Spray', {});
57
+ if (response && response.spray) {
58
+ this._updateSprayState(response.spray, 'response');
59
+ this._lastFullUpdateTimestamp = Date.now();
60
+ }
61
+ return response;
62
+ },
63
+
64
+ /**
65
+ * Gets the cached spray state for the specified channel.
66
+ *
67
+ * Returns cached state without making a request. Use {@link getSprayState} to fetch
68
+ * fresh state from the device. State is automatically updated when commands are sent or
69
+ * push notifications are received.
70
+ *
71
+ * @param {number} [channel=0] - Channel to get state for (default: 0)
72
+ * @returns {import('../lib/model/states/spray-state').SprayState|undefined} Cached spray state or undefined if not available
73
+ * @throws {Error} If state has not been initialized (call refreshState() first)
74
+ */
75
+ getCachedSprayState(channel = 0) {
76
+ this.validateState();
77
+ return this._sprayStateByChannel.get(channel);
78
+ },
79
+
80
+ /**
81
+ * Gets the current spray mode for the specified channel (cached).
82
+ *
83
+ * Returns the spray mode enum from cached state. Use {@link getRawSprayMode} to get
84
+ * the raw numeric value.
85
+ *
86
+ * @param {number} [channel=0] - Channel to get mode for (default: 0)
87
+ * @returns {import('../lib/enums').SprayMode|undefined} SprayMode enum object (e.g., SprayMode.OFF) or undefined if not available
88
+ * @throws {Error} If state has not been initialized (call refreshState() first)
89
+ * @see getRawSprayMode
90
+ */
91
+ getCurrentSprayMode(channel = 0) {
92
+ this.validateState();
93
+ const sprayState = this._sprayStateByChannel.get(channel);
94
+ if (sprayState && sprayState.mode !== undefined && sprayState.mode !== null) {
95
+ const enumKey = Object.keys(SprayMode).find(key => SprayMode[key] === sprayState.mode);
96
+ return enumKey ? SprayMode[enumKey] : undefined;
97
+ }
98
+ return undefined;
99
+ },
100
+
101
+ /**
102
+ * Gets the raw numeric spray mode value for the specified channel (cached).
103
+ *
104
+ * Returns the raw numeric mode value. For enum object, use {@link getCurrentSprayMode} instead.
105
+ *
106
+ * @param {number} [channel=0] - Channel to get mode for (default: 0)
107
+ * @returns {number|undefined} Raw numeric mode value or undefined if not available
108
+ * @throws {Error} If state has not been initialized (call refreshState() first)
109
+ * @see getCurrentSprayMode
110
+ */
111
+ getRawSprayMode(channel = 0) {
112
+ this.validateState();
113
+ const sprayState = this._sprayStateByChannel.get(channel);
114
+ if (sprayState) {
115
+ return sprayState.mode;
116
+ }
117
+ return undefined;
118
+ },
119
+
120
+ /**
121
+ * Updates the cached spray state from spray data.
122
+ *
123
+ * Called automatically when spray push notifications are received or commands complete.
124
+ * Handles both single objects and arrays of spray data.
125
+ *
126
+ * @param {Object|Array} sprayData - Spray data (single object or array)
127
+ * @param {string} [source='response'] - Source of the update ('push' | 'poll' | 'response')
128
+ * @private
129
+ */
130
+ _updateSprayState(sprayData, source = 'response') {
131
+ if (!sprayData) {return;}
132
+
133
+ const sprayArray = Array.isArray(sprayData) ? sprayData : [sprayData];
134
+
135
+ for (const sprayItem of sprayArray) {
136
+ const channelIndex = sprayItem.channel;
137
+ if (channelIndex === undefined || channelIndex === null) {continue;}
138
+
139
+ const oldState = this._sprayStateByChannel.get(channelIndex);
140
+ const oldValue = oldState ? {
141
+ mode: oldState.mode
142
+ } : undefined;
143
+
144
+ let state = this._sprayStateByChannel.get(channelIndex);
145
+ if (!state) {
146
+ state = new SprayState(sprayItem);
147
+ this._sprayStateByChannel.set(channelIndex, state);
148
+ } else {
149
+ state.update(sprayItem);
150
+ }
151
+
152
+ const newValue = { mode: state.mode };
153
+ if (oldValue === undefined || oldValue.mode !== state.mode) {
154
+ this.emit('stateChange', {
155
+ type: 'spray',
156
+ channel: channelIndex,
157
+ value: newValue,
158
+ oldValue,
159
+ source,
160
+ timestamp: Date.now()
161
+ });
162
+ }
163
+ }
164
+ }
165
+ };
166
+
@@ -0,0 +1,269 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * System feature module.
5
+ * Provides access to device system information including hardware, firmware, online status, and configuration.
6
+ */
7
+ module.exports = {
8
+ /**
9
+ * Gets all system data from the device.
10
+ *
11
+ * Returns comprehensive system information including hardware, firmware, and online status.
12
+ * Automatically extracts and caches MAC address, LAN IP, MQTT host/port, and online status
13
+ * from the response.
14
+ *
15
+ * @returns {Promise<Object>} Response containing all system data
16
+ * @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
17
+ * @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
18
+ */
19
+ async getSystemAllData() {
20
+ const response = await this.publishMessage('GET', 'Appliance.System.All', {});
21
+
22
+ if (response && response.all && response.all.system) {
23
+ const { system } = response.all;
24
+
25
+ if (system.hardware && system.hardware.macAddress) {
26
+ this.updateMacAddress(system.hardware.macAddress);
27
+ }
28
+
29
+ if (system.firmware) {
30
+ const { firmware } = system;
31
+ if (firmware.innerIp) {
32
+ this._lanIp = firmware.innerIp;
33
+ }
34
+ if (firmware.server) {
35
+ this._mqttHost = firmware.server;
36
+ }
37
+ if (firmware.port) {
38
+ this._mqttPort = firmware.port;
39
+ }
40
+ this._lastFullUpdateTimestamp = Date.now();
41
+ }
42
+ if (system.online) {
43
+ const onlineStatus = system.online.status;
44
+ this._updateOnlineStatus(onlineStatus);
45
+ }
46
+ }
47
+
48
+ return response;
49
+ },
50
+
51
+ /**
52
+ * Gets system debug information from the device.
53
+ *
54
+ * @returns {Promise<Object>} Response containing debug information
55
+ * @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
56
+ * @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
57
+ */
58
+ async getSystemDebug() {
59
+ return await this.publishMessage('GET', 'Appliance.System.Debug', {});
60
+ },
61
+
62
+ /**
63
+ * Gets the device abilities (supported namespaces).
64
+ *
65
+ * Automatically updates the internal abilities cache when the response is received.
66
+ *
67
+ * @returns {Promise<Object>} Response containing device abilities
68
+ * @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
69
+ * @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
70
+ */
71
+ async getSystemAbilities() {
72
+ const response = await this.publishMessage('GET', 'Appliance.System.Ability', {});
73
+ if (response && response.ability) {
74
+ this.updateAbilities(response.ability);
75
+ }
76
+ return response;
77
+ },
78
+
79
+ /**
80
+ * Gets encryption suite information from the device.
81
+ *
82
+ * @returns {Promise<Object>} Response containing encryption suite info
83
+ * @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
84
+ * @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
85
+ */
86
+ async getEncryptSuite() {
87
+ return await this.publishMessage('GET', 'Appliance.Encrypt.Suite', {});
88
+ },
89
+
90
+ /**
91
+ * Gets ECDHE encryption information from the device.
92
+ *
93
+ * @returns {Promise<Object>} Response containing ECDHE encryption info
94
+ * @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
95
+ * @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
96
+ */
97
+ async getEncryptECDHE() {
98
+ return await this.publishMessage('GET', 'Appliance.Encrypt.ECDHE', {});
99
+ },
100
+
101
+ /**
102
+ * Gets the online status from the device.
103
+ *
104
+ * @returns {Promise<Object>} Response containing online status
105
+ * @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
106
+ * @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
107
+ */
108
+ async getOnlineStatus() {
109
+ return await this.publishMessage('GET', 'Appliance.System.Online', {});
110
+ },
111
+
112
+ /**
113
+ * Gets the WiFi list configuration from the device.
114
+ *
115
+ * Automatically decodes SSIDs from base64 encoding in the response.
116
+ *
117
+ * @returns {Promise<Object>} Response containing WiFi list with decoded SSIDs
118
+ * @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
119
+ * @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
120
+ */
121
+ async getConfigWifiList() {
122
+ const response = await this.publishMessage('GET', 'Appliance.Config.WifiList', {});
123
+
124
+ if (response && response.wifiList) {
125
+ const { decodeSSID } = require('../../utilities/ssid');
126
+ const wifiList = Array.isArray(response.wifiList) ? response.wifiList : [response.wifiList];
127
+ wifiList.forEach(wifi => {
128
+ if (wifi.ssid) {
129
+ wifi.ssid = decodeSSID(wifi.ssid);
130
+ }
131
+ });
132
+ }
133
+
134
+ return response;
135
+ },
136
+
137
+ /**
138
+ * Gets trace configuration from the device.
139
+ *
140
+ * Automatically decodes SSID from base64 encoding in the response.
141
+ *
142
+ * @returns {Promise<Object>} Response containing trace config with decoded SSID
143
+ * @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
144
+ * @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
145
+ */
146
+ async getConfigTrace() {
147
+ const response = await this.publishMessage('GET', 'Appliance.Config.Trace', {});
148
+
149
+ if (response && response.trace && response.trace.ssid) {
150
+ const { decodeSSID } = require('../../utilities/ssid');
151
+ response.trace.ssid = decodeSSID(response.trace.ssid);
152
+ }
153
+
154
+ return response;
155
+ },
156
+
157
+ /**
158
+ * Gets system hardware information from the device.
159
+ *
160
+ * Automatically updates the MAC address cache if available in the response.
161
+ *
162
+ * @returns {Promise<Object>} Response containing hardware information
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 getSystemHardware() {
167
+ const response = await this.publishMessage('GET', 'Appliance.System.Hardware', {});
168
+ if (response && response.hardware) {
169
+ this._systemHardware = response.hardware;
170
+ if (response.hardware.macAddress) {
171
+ this.updateMacAddress(response.hardware.macAddress);
172
+ }
173
+ }
174
+ return response;
175
+ },
176
+
177
+ /**
178
+ * Gets system firmware information from the device.
179
+ *
180
+ * Automatically extracts and caches LAN IP and MQTT connection information if available.
181
+ *
182
+ * @returns {Promise<Object>} Response containing firmware information
183
+ * @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
184
+ * @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
185
+ */
186
+ async getSystemFirmware() {
187
+ const response = await this.publishMessage('GET', 'Appliance.System.Firmware', {});
188
+ if (response && response.firmware) {
189
+ this._systemFirmware = response.firmware;
190
+ if (response.firmware.innerIp) {
191
+ this._lanIp = response.firmware.innerIp;
192
+ }
193
+ if (response.firmware.server) {
194
+ this._mqttHost = response.firmware.server;
195
+ }
196
+ if (response.firmware.port) {
197
+ this._mqttPort = response.firmware.port;
198
+ }
199
+ }
200
+ return response;
201
+ },
202
+
203
+ /**
204
+ * Gets system time information from the device.
205
+ * * @returns {Promise<Object>} Response containing time information
206
+ * @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
207
+ * @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
208
+ */
209
+ async getSystemTime() {
210
+ return await this.publishMessage('GET', 'Appliance.System.Time', {});
211
+ },
212
+
213
+ /**
214
+ * Gets system position information from the device.
215
+ *
216
+ * @returns {Promise<Object>} Response containing position information
217
+ * @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
218
+ * @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
219
+ */
220
+ async getSystemPosition() {
221
+ return await this.publishMessage('GET', 'Appliance.System.Position', {});
222
+ },
223
+
224
+ /**
225
+ * Gets system factory test information from the device.
226
+ * * @returns {Promise<Object>} Response containing factory test information
227
+ * @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
228
+ * @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
229
+ */
230
+ async getSystemFactory() {
231
+ return await this.publishMessage('GET', 'Appliance.System.Factory', {});
232
+ },
233
+
234
+ /**
235
+ * Gets system LED mode configuration from the device.
236
+ *
237
+ * @returns {Promise<Object>} Response containing LED mode configuration
238
+ * @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
239
+ * @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
240
+ */
241
+ async getSystemLedMode() {
242
+ return await this.publishMessage('GET', 'Appliance.System.LedMode', {});
243
+ },
244
+
245
+ /**
246
+ * Controls the system LED mode configuration.
247
+ *
248
+ * @param {Object} ledModeData - LED mode data object with mode property (0=off, 1=match power, 2=opposite power) *
249
+ * @returns {Promise<Object>} Response from the device
250
+ * @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
251
+ * @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
252
+ */
253
+ async setSystemLedMode(ledModeData) {
254
+ const payload = { LedMode: ledModeData };
255
+ return await this.publishMessage('SET', 'Appliance.System.LedMode', payload);
256
+ },
257
+
258
+ /**
259
+ * Gets MCU firmware information from the device.
260
+ *
261
+ * @returns {Promise<Object>} Response containing MCU firmware information
262
+ * @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
263
+ * @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
264
+ */
265
+ async getMcuFirmware() {
266
+ return await this.publishMessage('GET', 'Appliance.Mcu.Firmware', {});
267
+ }
268
+ };
269
+
@@ -0,0 +1,55 @@
1
+ 'use strict';
2
+
3
+ const { normalizeChannel } = require('../../utilities/options');
4
+
5
+ /**
6
+ * Temperature unit feature module.
7
+ * Provides control over the temperature unit display preference (Celsius or Fahrenheit).
8
+ */
9
+ module.exports = {
10
+ /**
11
+ * Gets the temperature unit configuration from the device.
12
+ *
13
+ * @param {Object} [options={}] - Get options
14
+ * @param {number} [options.channel=0] - Channel to get temperature unit for (default: 0)
15
+ * @returns {Promise<Object>} Response containing temperature unit configuration with `tempUnit` array
16
+ * @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
17
+ * @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
18
+ */
19
+ async getTempUnit(options = {}) {
20
+ const channel = normalizeChannel(options);
21
+ const payload = {
22
+ tempUnit: [{
23
+ channel
24
+ }]
25
+ };
26
+ return await this.publishMessage('GET', 'Appliance.Control.TempUnit', payload);
27
+ },
28
+
29
+ /**
30
+ * Controls the temperature unit configuration.
31
+ *
32
+ * @param {Object} options - Temperature unit options
33
+ * @param {Object|Array<Object>} [options.tempUnitData] - Temperature unit data object or array of tempUnit items (if provided, used directly)
34
+ * @param {number} [options.channel] - Channel to configure
35
+ * @param {number} [options.tempUnit] - Temperature unit (1 = Celsius, 2 = Fahrenheit)
36
+ * @returns {Promise<Object>} Response from the device
37
+ * @throws {import('../lib/errors/errors').UnconnectedError} If device is not connected
38
+ * @throws {import('../lib/errors/errors').CommandTimeoutError} If command times out
39
+ */
40
+ async setTempUnit(options = {}) {
41
+ let tempUnitData;
42
+ if (options.tempUnitData) {
43
+ tempUnitData = Array.isArray(options.tempUnitData) ? options.tempUnitData : [options.tempUnitData];
44
+ } else {
45
+ const channel = normalizeChannel(options);
46
+ tempUnitData = [{
47
+ channel,
48
+ tempUnit: options.tempUnit
49
+ }];
50
+ }
51
+ const payload = { tempUnit: tempUnitData };
52
+ return await this.publishMessage('SET', 'Appliance.Control.TempUnit', payload);
53
+ }
54
+ };
55
+