homebridge-melcloud-control 4.10.12-beta.0 → 4.10.13

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 CHANGED
@@ -24,6 +24,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
24
24
  - For plugin < v4.6.0 use Homebridge UI <= v5.5.0
25
25
  - For plugin >= v4.6.0 use Homebridge UI >= v5.13.0
26
26
 
27
+ ## [4.10.13] - (04.06.2026)
28
+
29
+ ### Fixed
30
+
31
+ - RESTful / MQTT: after a network or power restart, the REST server returned `"This data is not available at this time."` for all endpoints and never recovered without a manual plugin restart; root cause: each retry attempt created a new Express server on the same port — the second and subsequent servers silently failed to bind (port already in use, no error handler), leaving `restFulConnected = false`, so all `update()` calls were skipped even after the device successfully reconnected; fixed by creating RestFul/MQTT instances lazily per device on the first successful `registerDevice` call and reusing them across all retry attempts via a `deviceStates` Map; the `'set'` handler is attached once via an `activeDevice` reference updated only after a successful connect; applies to DeviceAta, DeviceAtw and DeviceErv
32
+
27
33
  ## [4.10.12] - (28.05.2026)
28
34
 
29
35
  ### Changes
package/index.js CHANGED
@@ -6,6 +6,8 @@ import DeviceAta from './src/deviceata.js';
6
6
  import DeviceAtw from './src/deviceatw.js';
7
7
  import DeviceErv from './src/deviceerv.js';
8
8
  import ImpulseGenerator from './src/impulsegenerator.js';
9
+ import RestFul from './src/restful.js';
10
+ import Mqtt from './src/mqtt.js';
9
11
  import { PluginName, PlatformName, DeviceType } from './src/constants.js';
10
12
 
11
13
  class MelCloudPlatform {
@@ -93,6 +95,20 @@ class MelCloudPlatform {
93
95
  log.info(`${name}, config: ${JSON.stringify(safeConfig, null, 2)}`);
94
96
  }
95
97
 
98
+ // Per-device state that persists across retries — RestFul/MQTT are created
99
+ // once (lazily on first successful registerDevice call) and reused thereafter.
100
+ const allConfigDevices = [
101
+ ...(account.ataDevices || []),
102
+ ...(account.atwDevices || []),
103
+ ...(account.ervDevices || []),
104
+ ].filter(d => (d.displayType ?? 0) > 0);
105
+
106
+ const deviceStates = new Map(allConfigDevices.map(device => [device, {
107
+ restFul1: null, restFulConnected: false,
108
+ mqtt1: null, mqttConnected: false,
109
+ activeDevice: null,
110
+ }]));
111
+
96
112
  // The startup impulse generator retries the full connect+discover cycle
97
113
  // every 120 s until it succeeds, then hands off to the melcloud class
98
114
  // impulse generator and stops itself.
@@ -102,7 +118,7 @@ class MelCloudPlatform {
102
118
  await this.startAccount(
103
119
  account, name, type, accountMelcloud,
104
120
  accountRefreshInterval, prefDir, logLevel,
105
- log, api, impulseGenerator
121
+ log, api, impulseGenerator, deviceStates
106
122
  );
107
123
  } catch (error) {
108
124
  if (logLevel.error) log.error(`${name}, Start impulse generator error, ${error.message ?? error}, trying again.`);
@@ -117,7 +133,7 @@ class MelCloudPlatform {
117
133
 
118
134
  // ── Connect, discover and register accessories for one account ────────────
119
135
 
120
- async startAccount(account, name, type, accountMelcloud, accountRefreshInterval, prefDir, logLevel, log, api, impulseGenerator) {
136
+ async startAccount(account, name, type, accountMelcloud, accountRefreshInterval, prefDir, logLevel, log, api, impulseGenerator, deviceStates) {
121
137
  let timers;
122
138
  let melCloudClass;
123
139
 
@@ -172,7 +188,7 @@ class MelCloudPlatform {
172
188
  await this.registerDevice({
173
189
  account, device, index, name, type, accountMelcloud,
174
190
  prefDir, logLevel, log, api,
175
- melCloudClass, melCloudAccountData, melCloudDevicesData,
191
+ melCloudClass, melCloudAccountData, melCloudDevicesData, deviceStates,
176
192
  });
177
193
  }
178
194
 
@@ -183,7 +199,7 @@ class MelCloudPlatform {
183
199
 
184
200
  // ── Register a single device as a Homebridge accessory ───────────────────
185
201
 
186
- async registerDevice({ account, device, index, name, type, accountMelcloud, prefDir, logLevel, log, api, melCloudClass, melCloudAccountData, melCloudDevicesData }) {
202
+ async registerDevice({ account, device, index, name, type, accountMelcloud, prefDir, logLevel, log, api, melCloudClass, melCloudAccountData, melCloudDevicesData, deviceStates }) {
187
203
  device.id = String(device.id);
188
204
 
189
205
  const deviceName = device.name;
@@ -232,13 +248,86 @@ class MelCloudPlatform {
232
248
  }
233
249
  }
234
250
 
235
- // Construct the device class original arg order preserved
251
+ // Lazily create RestFul/MQTT on the first successful call — port/connection
252
+ // is bound once and reused across all retry attempts via deviceStates.
253
+ // The 'set' handler routes to activeDevice so it always targets the live instance.
254
+ const state = deviceStates.get(device);
255
+ const mqtt = account.mqtt ?? {};
256
+
257
+ if (!state.restFul1 && device.restFul?.enable) {
258
+ try {
259
+ await new Promise((resolve) => {
260
+ const timer = setTimeout(resolve, 5000);
261
+ state.restFul1 = new RestFul({
262
+ port: device.restFul.port,
263
+ logWarn: logLevel.warn,
264
+ logDebug: logLevel.debug,
265
+ })
266
+ .once('connected', (msg) => {
267
+ clearTimeout(timer);
268
+ state.restFulConnected = true;
269
+ if (logLevel.success) log.success(`${name}, ${deviceTypeString}, ${deviceName}, ${msg}`);
270
+ resolve();
271
+ })
272
+ .on('set', async (key, value) => {
273
+ try {
274
+ if (state.activeDevice) await state.activeDevice.setOverExternalIntegration('RESTFul', state.activeDevice.deviceData, key, value);
275
+ } catch (error) {
276
+ if (logLevel.warn) log.warn(`${name}, ${deviceTypeString}, ${deviceName}, RESTFul set error: ${error.message ?? error}`);
277
+ }
278
+ })
279
+ .on('debug', (msg) => logLevel.debug && log.info(`${name}, ${deviceTypeString}, ${deviceName}, debug: ${msg}`))
280
+ .on('warn', (msg) => logLevel.warn && log.warn(`${name}, ${deviceTypeString}, ${deviceName}, ${msg}`))
281
+ .on('error', (msg) => logLevel.error && log.error(`${name}, ${deviceTypeString}, ${deviceName}, ${msg}`));
282
+ });
283
+ } catch (error) {
284
+ if (logLevel.warn) log.warn(`${name}, ${deviceTypeString}, ${deviceName}, RESTFul start error: ${error.message ?? error}`);
285
+ }
286
+ }
287
+
288
+ if (!state.mqtt1 && mqtt.enable) {
289
+ try {
290
+ await new Promise((resolve) => {
291
+ const timer = setTimeout(resolve, 10000);
292
+ state.mqtt1 = new Mqtt({
293
+ host: mqtt.host,
294
+ port: mqtt.port || 1883,
295
+ clientId: mqtt.clientId ? `melcloud_${mqtt.clientId}_${Math.random().toString(16).slice(3)}` : `melcloud_${Math.random().toString(16).slice(3)}`,
296
+ prefix: mqtt.prefix ? `melcloud/${mqtt.prefix}/${deviceTypeString}/${deviceName}` : `melcloud/${deviceTypeString}/${deviceName}`,
297
+ user: mqtt.auth?.user,
298
+ passwd: mqtt.auth?.passwd,
299
+ logWarn: logLevel.warn,
300
+ logDebug: logLevel.debug,
301
+ })
302
+ .once('connected', (msg) => {
303
+ clearTimeout(timer);
304
+ state.mqttConnected = true;
305
+ if (logLevel.success) log.success(`${name}, ${deviceTypeString}, ${deviceName}, ${msg}`);
306
+ resolve();
307
+ })
308
+ .on('set', async (key, value) => {
309
+ try {
310
+ if (state.activeDevice) await state.activeDevice.setOverExternalIntegration('MQTT', state.activeDevice.deviceData, key, value);
311
+ } catch (error) {
312
+ if (logLevel.warn) log.warn(`${name}, ${deviceTypeString}, ${deviceName}, MQTT set error: ${error.message ?? error}`);
313
+ }
314
+ })
315
+ .on('debug', (msg) => logLevel.debug && log.info(`${name}, ${deviceTypeString}, ${deviceName}, debug: ${msg}`))
316
+ .on('warn', (msg) => logLevel.warn && log.warn(`${name}, ${deviceTypeString}, ${deviceName}, ${msg}`))
317
+ .on('error', (msg) => logLevel.error && log.error(`${name}, ${deviceTypeString}, ${deviceName}, ${msg}`));
318
+ });
319
+ } catch (error) {
320
+ if (logLevel.warn) log.warn(`${name}, ${deviceTypeString}, ${deviceName}, MQTT start error: ${error.message ?? error}`);
321
+ }
322
+ }
323
+
324
+ // Construct the device class — pass pre-created RestFul/MQTT instances
236
325
  let deviceClass;
237
326
  switch (deviceType) {
238
- case 0: deviceClass = new DeviceAta(api, account, device, presets, schedules, scenes, buttons, defaultTempsFile, melCloudClass, melCloudAccountData, melCloudDeviceData); break; // ATA
239
- case 1: deviceClass = new DeviceAtw(api, account, device, presets, schedules, scenes, buttons, defaultTempsFile, melCloudClass, melCloudAccountData, melCloudDeviceData); break; // ATW
240
- case 2: return; // reserved
241
- case 3: deviceClass = new DeviceErv(api, account, device, presets, schedules, scenes, buttons, defaultTempsFile, melCloudClass, melCloudAccountData, melCloudDeviceData); break; // ERV
327
+ case 0: deviceClass = new DeviceAta(api, account, device, presets, schedules, scenes, buttons, defaultTempsFile, melCloudClass, melCloudAccountData, melCloudDeviceData, state.restFul1, state.restFulConnected, state.mqtt1, state.mqttConnected); break; // ATA
328
+ case 1: deviceClass = new DeviceAtw(api, account, device, presets, schedules, scenes, buttons, defaultTempsFile, melCloudClass, melCloudAccountData, melCloudDeviceData, state.restFul1, state.restFulConnected, state.mqtt1, state.mqttConnected); break; // ATW
329
+ case 2: return; // reserved
330
+ case 3: deviceClass = new DeviceErv(api, account, device, presets, schedules, scenes, buttons, defaultTempsFile, melCloudClass, melCloudAccountData, melCloudDeviceData, state.restFul1, state.restFulConnected, state.mqtt1, state.mqttConnected); break; // ERV
242
331
  default:
243
332
  if (logLevel.warn) log.warn(`${name}, ${deviceTypeString}, ${deviceName}, received unknown device type: ${deviceType}.`);
244
333
  return;
@@ -254,6 +343,7 @@ class MelCloudPlatform {
254
343
 
255
344
  const accessory = await deviceClass.start();
256
345
  if (accessory) {
346
+ state.activeDevice = deviceClass;
257
347
  api.publishExternalAccessories(PluginName, [accessory]);
258
348
  if (logLevel.success) log.success(`${name}, ${deviceTypeString}, ${deviceName}, Published as external accessory.`);
259
349
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "displayName": "MELCloud Control",
3
3
  "name": "homebridge-melcloud-control",
4
- "version": "4.10.12-beta.0",
4
+ "version": "4.10.13",
5
5
  "description": "Homebridge plugin to control Mitsubishi Air Conditioner, Heat Pump and Energy Recovery Ventilation.",
6
6
  "license": "MIT",
7
7
  "author": "grzegorz914",
@@ -37,7 +37,7 @@
37
37
  "dependencies": {
38
38
  "@homebridge/plugin-ui-utils": "^2.2.4",
39
39
  "mqtt": "^5.15.1",
40
- "axios": "^1.16.1",
40
+ "axios": "^1.17.0",
41
41
  "axios-cookiejar-support": "^7.0.0",
42
42
  "tough-cookie": "^6.0.1",
43
43
  "express": "^5.2.1",
package/src/deviceata.js CHANGED
@@ -1,13 +1,11 @@
1
1
  import EventEmitter from 'events';
2
2
  import MelCloudAta from './melcloudata.js';
3
- import RestFul from './restful.js';
4
- import Mqtt from './mqtt.js';
5
3
  import Functions from './functions.js';
6
4
  import { TemperatureDisplayUnits, AirConditioner, DeviceType } from './constants.js';
7
5
  let Accessory, Characteristic, Service, Categories, AccessoryUUID;
8
6
 
9
7
  class DeviceAta extends EventEmitter {
10
- constructor(api, account, device, presets, schedules, scenes, buttons, defaultTempsFile, melCloudClass, melCloudAccountData, melCloudDeviceData) {
8
+ constructor(api, account, device, presets, schedules, scenes, buttons, defaultTempsFile, melCloudClass, melCloudAccountData, melCloudDeviceData, restFul1 = null, restFulConnected = false, mqtt1 = null, mqttConnected = false) {
11
9
  super();
12
10
 
13
11
  Accessory = api.platformAccessory;
@@ -60,9 +58,11 @@ class DeviceAta extends EventEmitter {
60
58
 
61
59
  //external integrations
62
60
  this.restFul = device.restFul ?? {};
63
- this.restFulConnected = false;
61
+ this.restFul1 = restFul1;
62
+ this.restFulConnected = restFulConnected;
64
63
  this.mqtt = account.mqtt ?? {};
65
- this.mqttConnected = false;
64
+ this.mqtt1 = mqtt1;
65
+ this.mqttConnected = mqttConnected;
66
66
 
67
67
  const serviceType = [null, Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor, Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor, null];
68
68
  const characteristicType = [null, Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState, Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState, null];
@@ -196,83 +196,6 @@ class DeviceAta extends EventEmitter {
196
196
  };
197
197
  }
198
198
 
199
- async externalIntegrations() {
200
- //RESTFul server
201
- const restFulEnabled = this.restFul.enable || false;
202
- if (restFulEnabled) {
203
- try {
204
- await new Promise((resolve) => {
205
- const timer = setTimeout(resolve, 5000);
206
- this.restFul1 = new RestFul({
207
- port: this.device.restFul.port,
208
- logWarn: this.logWarn,
209
- logDebug: this.logDebug,
210
- })
211
- .once('connected', (success) => {
212
- clearTimeout(timer);
213
- this.restFulConnected = true;
214
- this.emit('success', success);
215
- resolve();
216
- })
217
- .on('set', async (key, value) => {
218
- try {
219
- await this.setOverExternalIntegration('RESTFul', this.deviceData, key, value);
220
- } catch (error) {
221
- if (this.logWarn) this.emit('warn', `RESTFul set error: ${error}`);
222
- };
223
- })
224
- .on('debug', (debug) => this.emit('debug', debug))
225
- .on('warn', (warn) => this.emit('warn', warn))
226
- .on('error', (error) => this.emit('error', error));
227
- });
228
- } catch (error) {
229
- this.emit('warn', `RESTFul integration start error: ${error}`);
230
- }
231
- }
232
-
233
- const mqttEnabled = this.mqtt.enable || false;
234
- if (mqttEnabled) {
235
- try {
236
- await new Promise((resolve) => {
237
- const timer = setTimeout(resolve, 10000);
238
- this.mqtt1 = new Mqtt({
239
- host: this.mqtt.host,
240
- port: this.mqtt.port || 1883,
241
- clientId: this.mqtt.clientId ? `melcloud_${this.mqtt.clientId}_${Math.random().toString(16).slice(3)}` : `melcloud_${Math.random().toString(16).slice(3)}`,
242
- prefix: this.mqtt.prefix ? `melcloud/${this.mqtt.prefix}/${this.deviceTypeString}/${this.deviceName}` : `melcloud/${this.deviceTypeString}/${this.deviceName}`,
243
- user: this.mqtt.auth?.user,
244
- passwd: this.mqtt.auth?.passwd,
245
- logWarn: this.logWarn,
246
- logDebug: this.logDebug
247
- })
248
- .once('connected', (success) => {
249
- clearTimeout(timer);
250
- this.mqttConnected = true;
251
- this.emit('success', success);
252
- resolve();
253
- })
254
- .on('subscribed', (success) => {
255
- this.emit('success', success);
256
- })
257
- .on('set', async (key, value) => {
258
- try {
259
- await this.setOverExternalIntegration('MQTT', this.deviceData, key, value);
260
- } catch (error) {
261
- if (this.logWarn) this.emit('warn', `MQTT set, error: ${error}`);
262
- };
263
- })
264
- .on('debug', (debug) => this.emit('debug', debug))
265
- .on('warn', (warn) => this.emit('warn', warn))
266
- .on('error', (error) => this.emit('error', error));
267
- });
268
- } catch (error) {
269
- this.emit('warn', `MQTT integration start error: ${error}`);
270
- }
271
- };
272
-
273
- return true;
274
- }
275
-
276
199
  //prepare accessory
277
200
  async prepareAccessory() {
278
201
  try {
@@ -1424,8 +1347,6 @@ class DeviceAta extends EventEmitter {
1424
1347
  //start
1425
1348
  async start() {
1426
1349
  try {
1427
- //start external integrations
1428
- if (this.restFul.enable || this.mqtt.enable) await this.externalIntegrations();
1429
1350
 
1430
1351
  //melcloud device
1431
1352
  this.melCloudAta = new MelCloudAta(this.account, this.device, this.defaultTempsFile, this.melCloudClass)
package/src/deviceatw.js CHANGED
@@ -1,13 +1,11 @@
1
1
  import EventEmitter from 'events';
2
2
  import MelCloudAtw from './melcloudatw.js';
3
- import RestFul from './restful.js';
4
- import Mqtt from './mqtt.js';
5
3
  import Functions from './functions.js';
6
4
  import { TemperatureDisplayUnits, HeatPump, DeviceType } from './constants.js';
7
5
  let Accessory, Characteristic, Service, Categories, AccessoryUUID;
8
6
 
9
7
  class DeviceAtw extends EventEmitter {
10
- constructor(api, account, device, presets, schedules, scenes, buttons, defaultTempsFile, melCloudClass, melCloudAccountData, melCloudDeviceData) {
8
+ constructor(api, account, device, presets, schedules, scenes, buttons, defaultTempsFile, melCloudClass, melCloudAccountData, melCloudDeviceData, restFul1 = null, restFulConnected = false, mqtt1 = null, mqttConnected = false) {
11
9
  super();
12
10
 
13
11
  Accessory = api.platformAccessory;
@@ -67,9 +65,11 @@ class DeviceAtw extends EventEmitter {
67
65
 
68
66
  //external integrations
69
67
  this.restFul = device.restFul ?? {};
70
- this.restFulConnected = false;
68
+ this.restFul1 = restFul1;
69
+ this.restFulConnected = restFulConnected;
71
70
  this.mqtt = account.mqtt ?? {};
72
- this.mqttConnected = false;
71
+ this.mqtt1 = mqtt1;
72
+ this.mqttConnected = mqttConnected;
73
73
 
74
74
  const serviceType = [null, Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor, Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor, null];
75
75
  const characteristicType = [null, Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState, Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState, null];
@@ -215,83 +215,6 @@ class DeviceAtw extends EventEmitter {
215
215
  };
216
216
  }
217
217
 
218
- async externalIntegrations() {
219
- //RESTFul server
220
- const restFulEnabled = this.restFul.enable || false;
221
- if (restFulEnabled) {
222
- try {
223
- await new Promise((resolve) => {
224
- const timer = setTimeout(resolve, 5000);
225
- this.restFul1 = new RestFul({
226
- port: this.device.restFul.port,
227
- logWarn: this.logWarn,
228
- logDebug: this.logDebug,
229
- })
230
- .once('connected', (success) => {
231
- clearTimeout(timer);
232
- this.restFulConnected = true;
233
- this.emit('success', success);
234
- resolve();
235
- })
236
- .on('set', async (key, value) => {
237
- try {
238
- await this.setOverExternalIntegration('RESTFul', this.deviceData, key, value);
239
- } catch (error) {
240
- if (this.logWarn) this.emit('warn', `RESTFul set error: ${error}`);
241
- };
242
- })
243
- .on('debug', (debug) => this.emit('debug', debug))
244
- .on('warn', (warn) => this.emit('warn', warn))
245
- .on('error', (error) => this.emit('error', error));
246
- });
247
- } catch (error) {
248
- this.emit('warn', `RESTFul integration start error: ${error}`);
249
- }
250
- }
251
-
252
- const mqttEnabled = this.mqtt.enable || false;
253
- if (mqttEnabled) {
254
- try {
255
- await new Promise((resolve) => {
256
- const timer = setTimeout(resolve, 10000);
257
- this.mqtt1 = new Mqtt({
258
- host: this.mqtt.host,
259
- port: this.mqtt.port || 1883,
260
- clientId: this.mqtt.clientId ? `melcloud_${this.mqtt.clientId}_${Math.random().toString(16).slice(3)}` : `melcloud_${Math.random().toString(16).slice(3)}`,
261
- prefix: this.mqtt.prefix ? `melcloud/${this.mqtt.prefix}/${this.deviceTypeString}/${this.deviceName}` : `melcloud/${this.deviceTypeString}/${this.deviceName}`,
262
- user: this.mqtt.auth?.user,
263
- passwd: this.mqtt.auth?.passwd,
264
- logWarn: this.logWarn,
265
- logDebug: this.logDebug
266
- })
267
- .once('connected', (success) => {
268
- clearTimeout(timer);
269
- this.mqttConnected = true;
270
- this.emit('success', success);
271
- resolve();
272
- })
273
- .on('subscribed', (success) => {
274
- this.emit('success', success);
275
- })
276
- .on('set', async (key, value) => {
277
- try {
278
- await this.setOverExternalIntegration('MQTT', this.deviceData, key, value);
279
- } catch (error) {
280
- if (this.logWarn) this.emit('warn', `MQTT set, error: ${error}`);
281
- };
282
- })
283
- .on('debug', (debug) => this.emit('debug', debug))
284
- .on('warn', (warn) => this.emit('warn', warn))
285
- .on('error', (error) => this.emit('error', error));
286
- });
287
- } catch (error) {
288
- this.emit('warn', `MQTT integration start error: ${error}`);
289
- }
290
- };
291
-
292
- return true;
293
- }
294
-
295
218
  //prepare accessory
296
219
  async prepareAccessory() {
297
220
  try {
@@ -1751,9 +1674,6 @@ class DeviceAtw extends EventEmitter {
1751
1674
  //start
1752
1675
  async start() {
1753
1676
  try {
1754
- //start external integrations
1755
- if (this.restFul.enable || this.mqtt.enable) await this.externalIntegrations();
1756
-
1757
1677
  //melcloud device
1758
1678
  this.melCloudAtw = new MelCloudAtw(this.account, this.device, this.defaultTempsFile, this.melCloudClass)
1759
1679
  .on('deviceInfo', (modelIndoor, modelOutdoor, serialNumber, firmwareAppVersion, supportsHotWaterTank, supportsZone2, ftcModel) => {
package/src/deviceerv.js CHANGED
@@ -1,13 +1,11 @@
1
1
  import EventEmitter from 'events';
2
2
  import MelCloudErv from './melclouderv.js';
3
- import RestFul from './restful.js';
4
- import Mqtt from './mqtt.js';
5
3
  import Functions from './functions.js';
6
4
  import { TemperatureDisplayUnits, Ventilation, DeviceType } from './constants.js';
7
5
  let Accessory, Characteristic, Service, Categories, AccessoryUUID;
8
6
 
9
7
  class DeviceErv extends EventEmitter {
10
- constructor(api, account, device, presets, schedules, scenes, buttons, defaultTempsFile, melCloudClass, melCloudAccountData, melCloudDeviceData) {
8
+ constructor(api, account, device, presets, schedules, scenes, buttons, defaultTempsFile, melCloudClass, melCloudAccountData, melCloudDeviceData, restFul1 = null, restFulConnected = false, mqtt1 = null, mqttConnected = false) {
11
9
  super();
12
10
 
13
11
  Accessory = api.platformAccessory;
@@ -55,9 +53,11 @@ class DeviceErv extends EventEmitter {
55
53
 
56
54
  //external integrations
57
55
  this.restFul = device.restFul ?? {};
58
- this.restFulConnected = false;
56
+ this.restFul1 = restFul1;
57
+ this.restFulConnected = restFulConnected;
59
58
  this.mqtt = account.mqtt ?? {};
60
- this.mqttConnected = false;
59
+ this.mqtt1 = mqtt1;
60
+ this.mqttConnected = mqttConnected;
61
61
 
62
62
  const serviceType = [null, Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor, Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor, null];
63
63
  const characteristicType = [null, Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState, Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState, null];
@@ -163,83 +163,6 @@ class DeviceErv extends EventEmitter {
163
163
  };
164
164
  }
165
165
 
166
- async externalIntegrations() {
167
- //RESTFul server
168
- const restFulEnabled = this.restFul.enable || false;
169
- if (restFulEnabled) {
170
- try {
171
- await new Promise((resolve) => {
172
- const timer = setTimeout(resolve, 5000);
173
- this.restFul1 = new RestFul({
174
- port: this.device.restFul.port,
175
- logWarn: this.logWarn,
176
- logDebug: this.logDebug,
177
- })
178
- .once('connected', (success) => {
179
- clearTimeout(timer);
180
- this.restFulConnected = true;
181
- this.emit('success', success);
182
- resolve();
183
- })
184
- .on('set', async (key, value) => {
185
- try {
186
- await this.setOverExternalIntegration('RESTFul', this.deviceData, key, value);
187
- } catch (error) {
188
- if (this.logWarn) this.emit('warn', `RESTFul set error: ${error}`);
189
- };
190
- })
191
- .on('debug', (debug) => this.emit('debug', debug))
192
- .on('warn', (warn) => this.emit('warn', warn))
193
- .on('error', (error) => this.emit('error', error));
194
- });
195
- } catch (error) {
196
- this.emit('warn', `RESTFul integration start error: ${error}`);
197
- }
198
- }
199
-
200
- const mqttEnabled = this.mqtt.enable || false;
201
- if (mqttEnabled) {
202
- try {
203
- await new Promise((resolve) => {
204
- const timer = setTimeout(resolve, 10000);
205
- this.mqtt1 = new Mqtt({
206
- host: this.mqtt.host,
207
- port: this.mqtt.port || 1883,
208
- clientId: this.mqtt.clientId ? `melcloud_${this.mqtt.clientId}_${Math.random().toString(16).slice(3)}` : `melcloud_${Math.random().toString(16).slice(3)}`,
209
- prefix: this.mqtt.prefix ? `melcloud/${this.mqtt.prefix}/${this.deviceTypeString}/${this.deviceName}` : `melcloud/${this.deviceTypeString}/${this.deviceName}`,
210
- user: this.mqtt.auth?.user,
211
- passwd: this.mqtt.auth?.passwd,
212
- logWarn: this.logWarn,
213
- logDebug: this.logDebug
214
- })
215
- .once('connected', (success) => {
216
- clearTimeout(timer);
217
- this.mqttConnected = true;
218
- this.emit('success', success);
219
- resolve();
220
- })
221
- .on('subscribed', (success) => {
222
- this.emit('success', success);
223
- })
224
- .on('set', async (key, value) => {
225
- try {
226
- await this.setOverExternalIntegration('MQTT', this.deviceData, key, value);
227
- } catch (error) {
228
- if (this.logWarn) this.emit('warn', `MQTT set, error: ${error}`);
229
- };
230
- })
231
- .on('debug', (debug) => this.emit('debug', debug))
232
- .on('warn', (warn) => this.emit('warn', warn))
233
- .on('error', (error) => this.emit('error', error));
234
- });
235
- } catch (error) {
236
- this.emit('warn', `MQTT integration start error: ${error}`);
237
- }
238
- };
239
-
240
- return true;
241
- }
242
-
243
166
  //prepare accessory
244
167
  async prepareAccessory() {
245
168
  try {
@@ -1083,9 +1006,6 @@ class DeviceErv extends EventEmitter {
1083
1006
  //start
1084
1007
  async start() {
1085
1008
  try {
1086
- //start external integrations
1087
- if (this.restFul.enable || this.mqtt.enable) await this.externalIntegrations();
1088
-
1089
1009
  //melcloud device
1090
1010
  this.melCloudErv = new MelCloudErv(this.account, this.device, this.defaultTempsFile, this.melCloudClass)
1091
1011
  .on('deviceInfo', (modelIndoor, modelOutdoor, serialNumber, firmwareAppVersion) => {