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 +6 -0
- package/index.js +99 -9
- package/package.json +2 -2
- package/src/deviceata.js +5 -84
- package/src/deviceatw.js +5 -85
- package/src/deviceerv.js +5 -85
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
|
-
//
|
|
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;
|
|
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.
|
|
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.
|
|
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.
|
|
61
|
+
this.restFul1 = restFul1;
|
|
62
|
+
this.restFulConnected = restFulConnected;
|
|
64
63
|
this.mqtt = account.mqtt ?? {};
|
|
65
|
-
this.
|
|
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.
|
|
68
|
+
this.restFul1 = restFul1;
|
|
69
|
+
this.restFulConnected = restFulConnected;
|
|
71
70
|
this.mqtt = account.mqtt ?? {};
|
|
72
|
-
this.
|
|
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.
|
|
56
|
+
this.restFul1 = restFul1;
|
|
57
|
+
this.restFulConnected = restFulConnected;
|
|
59
58
|
this.mqtt = account.mqtt ?? {};
|
|
60
|
-
this.
|
|
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) => {
|