homebridge-melcloud-control 4.1.2-beta.9 → 4.1.2
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 +10 -0
- package/README.md +16 -3
- package/config.schema.json +445 -115
- package/homebridge-ui/public/index.html +90 -46
- package/package.json +2 -2
- package/src/constants.js +4 -0
- package/src/deviceata.js +68 -12
- package/src/deviceatw.js +64 -3
- package/src/deviceerv.js +68 -7
- package/src/functions.js +41 -57
- package/src/melcloud.js +64 -47
- package/src/melcloudata.js +17 -8
- package/src/melcloudatw.js +14 -8
- package/src/melclouderv.js +14 -8
|
@@ -105,7 +105,6 @@
|
|
|
105
105
|
return;
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
this.accountIndex = 0;
|
|
109
108
|
const accounts = pluginConfig[0].accounts || [];
|
|
110
109
|
const accountsCount = accounts.length;
|
|
111
110
|
|
|
@@ -117,17 +116,22 @@
|
|
|
117
116
|
container.style.alignItems = 'center';
|
|
118
117
|
|
|
119
118
|
const formElements = {
|
|
119
|
+
accountName: document.getElementById('accountName'),
|
|
120
|
+
info: document.getElementById('info'),
|
|
121
|
+
info1: document.getElementById('info1'),
|
|
122
|
+
info2: document.getElementById('info2'),
|
|
120
123
|
name: document.getElementById('name'),
|
|
121
124
|
user: document.getElementById('user'),
|
|
122
125
|
passwd: document.getElementById('passwd'),
|
|
123
126
|
language: document.getElementById('language'),
|
|
124
127
|
accountType: document.getElementById('accountType'),
|
|
125
|
-
logIn: document.getElementById('logIn')
|
|
126
|
-
accountName: document.getElementById('accountName')
|
|
128
|
+
logIn: document.getElementById('logIn')
|
|
127
129
|
};
|
|
128
130
|
|
|
129
131
|
// Tworzenie przycisków
|
|
130
132
|
accounts.forEach((account, i) => {
|
|
133
|
+
this.account = account;
|
|
134
|
+
|
|
131
135
|
const button = document.createElement("button");
|
|
132
136
|
button.type = "button";
|
|
133
137
|
button.id = `button${i}`;
|
|
@@ -137,7 +141,7 @@
|
|
|
137
141
|
container.appendChild(button);
|
|
138
142
|
|
|
139
143
|
button.addEventListener('click', async () => {
|
|
140
|
-
this.
|
|
144
|
+
this.account = account;
|
|
141
145
|
|
|
142
146
|
// Zmieniamy klasę wszystkich przycisków
|
|
143
147
|
accounts.forEach((_, j) => {
|
|
@@ -146,6 +150,9 @@
|
|
|
146
150
|
|
|
147
151
|
// Ustawiamy formularz
|
|
148
152
|
formElements.accountName.innerText = account.name || '';
|
|
153
|
+
formElements.info.innerText = ``;
|
|
154
|
+
formElements.info1.innerText = '';
|
|
155
|
+
formElements.info2.innerText = '';
|
|
149
156
|
formElements.name.value = account.name || '';
|
|
150
157
|
formElements.user.value = account.user || '';
|
|
151
158
|
formElements.passwd.value = account.passwd || '';
|
|
@@ -160,7 +167,7 @@
|
|
|
160
167
|
|
|
161
168
|
// Jeden listener input dla całego formularza
|
|
162
169
|
document.getElementById('configForm').addEventListener('input', async () => {
|
|
163
|
-
const account =
|
|
170
|
+
const account = this.account;
|
|
164
171
|
if (!account) return;
|
|
165
172
|
|
|
166
173
|
account.name = formElements.name.value;
|
|
@@ -224,10 +231,13 @@
|
|
|
224
231
|
|
|
225
232
|
document.getElementById('logIn').addEventListener('click', async () => {
|
|
226
233
|
document.getElementById(`logIn`).className = "btn btn-primary";
|
|
234
|
+
updateInfo('info', '', 'white');
|
|
235
|
+
updateInfo('info1', '', 'white');
|
|
236
|
+
updateInfo('info2', '', 'white');
|
|
227
237
|
homebridge.showSpinner();
|
|
228
238
|
|
|
229
239
|
try {
|
|
230
|
-
const account =
|
|
240
|
+
const account = this.account;
|
|
231
241
|
const response = await homebridge.request('/connect', account);
|
|
232
242
|
if (!response.State) {
|
|
233
243
|
homebridge.hideSpinner();
|
|
@@ -254,45 +264,81 @@
|
|
|
254
264
|
const removedErv = removeStaleDevices(account.ervDevices, devicesByType.erv);
|
|
255
265
|
|
|
256
266
|
const handleDevices = (devicesInMelCloud, devicesInConfig, typeString, newArr, newPresets) => {
|
|
257
|
-
|
|
258
|
-
const
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
267
|
+
try {
|
|
268
|
+
const configDevicesMap = new Map(devicesInConfig.map(dev => [String(dev.id), dev]));
|
|
269
|
+
const isMelcloud = account.type === 'melcloud';
|
|
270
|
+
|
|
271
|
+
const idKey = isMelcloud ? 'ID' : 'Id';
|
|
272
|
+
const typeKey = isMelcloud ? 'Presets' : 'Schedule';
|
|
273
|
+
const typeKey1 = isMelcloud ? 'presets' : 'schedules';
|
|
274
|
+
|
|
275
|
+
devicesInMelCloud.forEach(device => {
|
|
276
|
+
const deviceId = String(device.DeviceID);
|
|
277
|
+
let deviceInConfig = configDevicesMap.get(deviceId);
|
|
278
|
+
|
|
279
|
+
// === Create device if missing ===
|
|
280
|
+
if (!deviceInConfig) {
|
|
281
|
+
deviceInConfig = {
|
|
282
|
+
id: device.DeviceID,
|
|
283
|
+
type: device.Type,
|
|
284
|
+
typeString,
|
|
285
|
+
displayType: 0,
|
|
286
|
+
name: device.DeviceName,
|
|
287
|
+
presets: [],
|
|
288
|
+
schedules: [],
|
|
289
|
+
buttonsSensors: []
|
|
290
|
+
};
|
|
291
|
+
devicesInConfig.push(deviceInConfig);
|
|
292
|
+
newArr.push(deviceInConfig);
|
|
293
|
+
configDevicesMap.set(deviceId, deviceInConfig);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// === Process presets/schedules ===
|
|
297
|
+
const presets = device[typeKey] || [];
|
|
298
|
+
const presetsInConfig = deviceInConfig[typeKey1] || [];
|
|
299
|
+
const presetIds = new Set(presetsInConfig.map(p => String(p.id)));
|
|
300
|
+
|
|
301
|
+
let addedNewPreset = false;
|
|
302
|
+
|
|
303
|
+
presets.forEach((preset, index) => {
|
|
304
|
+
const presetId = String(preset[idKey]);
|
|
305
|
+
if (!presetIds.has(presetId)) {
|
|
306
|
+
const presetObj = {
|
|
307
|
+
id: presetId,
|
|
308
|
+
displayType: 0,
|
|
309
|
+
name: preset.NumberDescription || `Schedule ${index}`,
|
|
310
|
+
namePrefix: false
|
|
311
|
+
};
|
|
312
|
+
presetsInConfig.push(presetObj);
|
|
313
|
+
newPresets.push(presetObj);
|
|
314
|
+
presetIds.add(presetId);
|
|
315
|
+
addedNewPreset = true;
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
// === Remove placeholder presets/schedules (id === '0') if new ones were added ===
|
|
320
|
+
if (addedNewPreset) {
|
|
321
|
+
const beforeCount = presetsInConfig.length;
|
|
322
|
+
deviceInConfig[typeKey1] = presetsInConfig.filter(p => String(p.id) !== '0');
|
|
323
|
+
const removedCount = beforeCount - deviceInConfig[typeKey1].length;
|
|
324
|
+
|
|
325
|
+
if (removedCount > 0 && removedCount < beforeCount) {
|
|
326
|
+
updateInfo('info2', `Removed ${removedCount} placeholder ${typeKey1} from device ${device.DeviceID}`, 'yellow');
|
|
327
|
+
}
|
|
288
328
|
}
|
|
289
329
|
});
|
|
290
|
-
|
|
330
|
+
|
|
331
|
+
// Return filtered devicesInConfig to make sure upstream code uses it
|
|
332
|
+
const filteredDevices = devicesInConfig.filter(d => String(d.id) !== '0');
|
|
333
|
+
return filteredDevices;
|
|
334
|
+
} catch (error) {
|
|
335
|
+
updateInfo('info', `Error while processing device: ${JSON.stringify(error)}`, 'red');
|
|
336
|
+
}
|
|
291
337
|
};
|
|
292
338
|
|
|
293
|
-
handleDevices(devicesByType.ata, account.ataDevices, "Air Conditioner", newDevices.ata, newDevices.ataPresets);
|
|
294
|
-
handleDevices(devicesByType.atw, account.atwDevices, "Heat Pump", newDevices.atw, newDevices.atwPresets);
|
|
295
|
-
handleDevices(devicesByType.erv, account.ervDevices, "Energy Recovery Ventilation", newDevices.erv, newDevices.ervPresets);
|
|
339
|
+
account.ataDevices = handleDevices(devicesByType.ata, account.ataDevices, "Air Conditioner", newDevices.ata, newDevices.ataPresets);
|
|
340
|
+
account.atwDevices = handleDevices(devicesByType.atw, account.atwDevices, "Heat Pump", newDevices.atw, newDevices.atwPresets);
|
|
341
|
+
account.ervDevices = handleDevices(devicesByType.erv, account.ervDevices, "Energy Recovery Ventilation", newDevices.erv, newDevices.ervPresets);
|
|
296
342
|
|
|
297
343
|
const newDevicesCount = newDevices.ata.length + newDevices.atw.length + newDevices.erv.length;
|
|
298
344
|
const newPresetsCount = newDevices.ataPresets.length + newDevices.atwPresets.length + newDevices.ervPresets.length;
|
|
@@ -304,20 +350,18 @@
|
|
|
304
350
|
if (newDevicesCount)
|
|
305
351
|
updateInfo('info', `Found new devices: ATA: ${newDevices.ata.length}, ATW: ${newDevices.atw.length}, ERV: ${newDevices.erv.length}.`, 'green');
|
|
306
352
|
if (newPresetsCount)
|
|
307
|
-
updateInfo('info1', `Found new presets: ATA: ${newDevices.ataPresets.length}, ATW: ${newDevices.atwPresets.length}, ERV: ${newDevices.ervPresets.length}.`, 'green');
|
|
353
|
+
updateInfo('info1', `Found new ${account.type === 'melcloud' ? 'presets' : 'schedules'}: ATA: ${newDevices.ataPresets.length}, ATW: ${newDevices.atwPresets.length}, ERV: ${newDevices.ervPresets.length}.`, 'green');
|
|
308
354
|
if (removedDevicesCount)
|
|
309
355
|
updateInfo('info2', `Removed devices: ATA: ${removedAta.length}, ATW: ${removedAtw.length}, ERV: ${removedErv.length}.`, 'orange');
|
|
310
356
|
}
|
|
311
357
|
|
|
312
358
|
await homebridge.updatePluginConfig(pluginConfig);
|
|
313
359
|
await homebridge.savePluginConfig(pluginConfig);
|
|
314
|
-
document.getElementById('logIn').className = "btn btn-secondary";
|
|
315
|
-
|
|
316
360
|
} catch (error) {
|
|
317
|
-
updateInfo('info',
|
|
318
|
-
updateInfo('info1', `${JSON.stringify(error)}`, 'red');
|
|
361
|
+
updateInfo('info', `Connect error ${JSON.stringify(error)}`, 'red');
|
|
319
362
|
document.getElementById('logIn').className = "btn btn-secondary";
|
|
320
363
|
} finally {
|
|
364
|
+
document.getElementById('logIn').className = "btn btn-secondary";
|
|
321
365
|
homebridge.hideSpinner();
|
|
322
366
|
}
|
|
323
367
|
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"displayName": "MELCloud Control",
|
|
3
3
|
"name": "homebridge-melcloud-control",
|
|
4
|
-
"version": "4.1.2
|
|
4
|
+
"version": "4.1.2",
|
|
5
5
|
"description": "Homebridge plugin to control Mitsubishi Air Conditioner, Heat Pump and Energy Recovery Ventilation.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "grzegorz914",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"async-mqtt": "^2.6.3",
|
|
40
40
|
"axios": "^1.13.2",
|
|
41
41
|
"express": "^5.1.0",
|
|
42
|
-
"puppeteer
|
|
42
|
+
"puppeteer": "^24.29.1"
|
|
43
43
|
},
|
|
44
44
|
"keywords": [
|
|
45
45
|
"homebridge",
|
package/src/constants.js
CHANGED
|
@@ -21,8 +21,12 @@ export const ApiUrlsHome = {
|
|
|
21
21
|
BaseURL: "https://melcloudhome.com",
|
|
22
22
|
GetUserContext: "/api/user/context",
|
|
23
23
|
SetAta: "/api/ataunit/deviceid",
|
|
24
|
+
GetAtaSchedule: "/ata/deviceid/schedule",
|
|
24
25
|
SetAtw: "/api/atwunit/deviceid",
|
|
26
|
+
GetAtwSchedule: "/atw/deviceid/schedule",
|
|
25
27
|
SetErv: "/api/ervunit/deviceid",
|
|
28
|
+
GetErvSchedule: "/erv/deviceid/schedule",
|
|
29
|
+
SetSchedule: "/api/cloudschedule/deviceid/enabled",
|
|
26
30
|
};
|
|
27
31
|
|
|
28
32
|
export const DeviceType = [
|
package/src/deviceata.js
CHANGED
|
@@ -37,7 +37,8 @@ class DeviceAta extends EventEmitter {
|
|
|
37
37
|
this.heatDryFanMode = device.heatDryFanMode || 1; //NONE, HEAT, DRY, FAN
|
|
38
38
|
this.coolDryFanMode = device.coolDryFanMode || 1; //NONE, COOL, DRY, FAN
|
|
39
39
|
this.autoDryFanMode = device.autoDryFanMode || 1; //NONE, AUTO, DRY, FAN
|
|
40
|
-
this.presets = (device.presets || []).filter(preset => (preset.displayType ?? 0) > 0);
|
|
40
|
+
this.presets = this.accountType === 'melcloud' ? (device.presets || []).filter(preset => (preset.displayType ?? 0) > 0 && preset.id !== '0') : [];
|
|
41
|
+
this.schedules = this.accountType === 'melcloudhome' ? (device.schedules || []).filter(schedule => (schedule.displayType ?? 0) > 0 && schedule.id !== '0') : [];
|
|
41
42
|
this.buttons = (device.buttonsSensors || []).filter(sensor => (sensor.displayType ?? 0) > 0);
|
|
42
43
|
this.deviceId = device.id;
|
|
43
44
|
this.deviceName = device.name;
|
|
@@ -61,6 +62,14 @@ class DeviceAta extends EventEmitter {
|
|
|
61
62
|
preset.previousSettings = {};
|
|
62
63
|
}
|
|
63
64
|
|
|
65
|
+
//schedules configured
|
|
66
|
+
for (const schedule of this.schedules) {
|
|
67
|
+
schedule.name = schedule.name || 'Schedule'
|
|
68
|
+
schedule.serviceType = [null, Service.Outlet, Service.Switch, Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor][schedule.displayType];
|
|
69
|
+
schedule.characteristicType = [null, Characteristic.On, Characteristic.On, Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState][schedule.displayType];
|
|
70
|
+
schedule.state = false;
|
|
71
|
+
}
|
|
72
|
+
|
|
64
73
|
//buttons configured
|
|
65
74
|
for (const button of this.buttons) {
|
|
66
75
|
button.name = button.name || 'Button'
|
|
@@ -244,6 +253,7 @@ class DeviceAta extends EventEmitter {
|
|
|
244
253
|
const deviceName = this.deviceName;
|
|
245
254
|
const accountName = this.accountName;
|
|
246
255
|
const presetsOnServer = this.accessory.presets;
|
|
256
|
+
const schedulesOnServer = this.accessory.schedules;
|
|
247
257
|
const supportsHeat = this.accessory.supportsHeat;
|
|
248
258
|
const supportsDry = this.accessory.supportsDry;
|
|
249
259
|
const supportsCool = this.accessory.supportsCool;
|
|
@@ -683,9 +693,8 @@ class DeviceAta extends EventEmitter {
|
|
|
683
693
|
if (this.presets.length > 0) {
|
|
684
694
|
if (this.logDebug) this.emit('debug', `Prepare presets services`);
|
|
685
695
|
this.presetsServices = [];
|
|
686
|
-
const presetsIdKey = this.accountType === 'melcloud' ? 'ID' : 'Id';
|
|
687
696
|
this.presets.forEach((preset, i) => {
|
|
688
|
-
const presetData = presetsOnServer.find(p => p
|
|
697
|
+
const presetData = presetsOnServer.find(p => p.ID === preset.id);
|
|
689
698
|
|
|
690
699
|
//get preset name
|
|
691
700
|
const name = preset.name;
|
|
@@ -706,8 +715,6 @@ class DeviceAta extends EventEmitter {
|
|
|
706
715
|
})
|
|
707
716
|
.onSet(async (state) => {
|
|
708
717
|
try {
|
|
709
|
-
const setTempKey = this.accountType === 'melcloud' ? 'SetTemperature' : 'SetPoint';
|
|
710
|
-
const fanKey = this.accountType === 'melcloud' ? 'FanSpeed' : 'SetFanSpeed';
|
|
711
718
|
switch (state) {
|
|
712
719
|
case true:
|
|
713
720
|
preset.previousSettings = deviceData.Device;
|
|
@@ -716,7 +723,7 @@ class DeviceAta extends EventEmitter {
|
|
|
716
723
|
deviceData.Device.SetTemperature = presetData.SetTemperature;
|
|
717
724
|
deviceData.Device.VaneHorizontalDirection = presetData.VaneHorizontalDirection;
|
|
718
725
|
deviceData.Device.VaneVerticalDirection = presetData.VaneVerticalDirection;
|
|
719
|
-
deviceData.Device
|
|
726
|
+
deviceData.Device.SetFanSpeed = presetData.SetFanSpeed;
|
|
720
727
|
break;
|
|
721
728
|
case false:
|
|
722
729
|
deviceData.Device.Power = preset.previousSettings.Power;
|
|
@@ -724,7 +731,7 @@ class DeviceAta extends EventEmitter {
|
|
|
724
731
|
deviceData.Device.SetTemperature = preset.previousSettings.SetTemperature;
|
|
725
732
|
deviceData.Device.VaneHorizontalDirection = preset.previousSettings.VaneHorizontalDirection;
|
|
726
733
|
deviceData.Device.VaneVerticalDirection = preset.previousSettings.VaneVerticalDirection;
|
|
727
|
-
deviceData.Device
|
|
734
|
+
deviceData.Device.SetFanSpeed = preset.previousSettings.SetFanSpeed;
|
|
728
735
|
break;
|
|
729
736
|
};
|
|
730
737
|
|
|
@@ -739,6 +746,42 @@ class DeviceAta extends EventEmitter {
|
|
|
739
746
|
});
|
|
740
747
|
};
|
|
741
748
|
|
|
749
|
+
//schedules services
|
|
750
|
+
if (this.schedules.length > 0) {
|
|
751
|
+
if (this.logDebug) this.emit('debug', `Prepare schedules services`);
|
|
752
|
+
this.schedulesServices = [];
|
|
753
|
+
this.schedules.forEach((schedule, i) => {
|
|
754
|
+
//get preset name
|
|
755
|
+
const name = schedule.name;
|
|
756
|
+
|
|
757
|
+
//get preset name prefix
|
|
758
|
+
const namePrefix = schedule.namePrefix;
|
|
759
|
+
|
|
760
|
+
const serviceName = namePrefix ? `${accessoryName} ${name}` : name;
|
|
761
|
+
const serviceType = schedule.serviceType;
|
|
762
|
+
const characteristicType = schedule.characteristicType;
|
|
763
|
+
const scheduleService = new serviceType(serviceName, `Schedule ${deviceId} ${i}`);
|
|
764
|
+
scheduleService.addOptionalCharacteristic(Characteristic.ConfiguredName);
|
|
765
|
+
scheduleService.setCharacteristic(Characteristic.ConfiguredName, serviceName);
|
|
766
|
+
scheduleService.getCharacteristic(characteristicType)
|
|
767
|
+
.onGet(async () => {
|
|
768
|
+
const state = schedule.state;
|
|
769
|
+
return state;
|
|
770
|
+
})
|
|
771
|
+
.onSet(async (state) => {
|
|
772
|
+
try {
|
|
773
|
+
deviceData.ScheduleEnabled = state;
|
|
774
|
+
await this.melCloudAta.send(this.accountType, this.displayType, deviceData, 'scheduleset');
|
|
775
|
+
if (this.logInfo) this.emit('info', `${state ? 'Set:' : 'Unset:'} ${name}`);
|
|
776
|
+
} catch (error) {
|
|
777
|
+
if (this.logWarn) this.emit('warn', `Set schedule error: ${error}`);
|
|
778
|
+
};
|
|
779
|
+
});
|
|
780
|
+
this.schedulesServices.push(scheduleService);
|
|
781
|
+
accessory.addService(scheduleService);
|
|
782
|
+
});
|
|
783
|
+
};
|
|
784
|
+
|
|
742
785
|
//buttons services
|
|
743
786
|
if (this.buttons.length > 0) {
|
|
744
787
|
if (this.logDebug) this.emit('debug', `Prepare buttons/sensors services`);
|
|
@@ -1017,7 +1060,6 @@ class DeviceAta extends EventEmitter {
|
|
|
1017
1060
|
this.deviceData = deviceData;
|
|
1018
1061
|
|
|
1019
1062
|
//keys
|
|
1020
|
-
const presetsKey = this.accountType === 'melcloud' ? 'Presets' : 'Schedule';
|
|
1021
1063
|
const presetsIdKey = this.accountType === 'melcloud' ? 'ID' : 'Id';
|
|
1022
1064
|
const setTempKey = this.accountType === 'melcloud' ? 'SetTemperature' : 'SetPoint';
|
|
1023
1065
|
const fanKey = this.accountType === 'melcloud' ? 'FanSpeed' : 'SetFanSpeed';
|
|
@@ -1032,7 +1074,10 @@ class DeviceAta extends EventEmitter {
|
|
|
1032
1074
|
const supportCoolKey = this.accountType === 'melcloud' ? 'ModelSupportsCool' : 'HasCoolOperationMode';
|
|
1033
1075
|
|
|
1034
1076
|
//presets schedule
|
|
1035
|
-
const
|
|
1077
|
+
const scheduleEnabled = deviceData.ScheduleEnabled;
|
|
1078
|
+
const schedulesOnServer = deviceData.Schedule ?? [];
|
|
1079
|
+
const presetsOnServer = deviceData.Presets ?? [];
|
|
1080
|
+
|
|
1036
1081
|
|
|
1037
1082
|
//protection
|
|
1038
1083
|
const frostProtectionEnabled = deviceData.FrostProtection?.Enabled;
|
|
@@ -1041,7 +1086,6 @@ class DeviceAta extends EventEmitter {
|
|
|
1041
1086
|
const overheatProtectionActive = deviceData.OverheatProtection?.Active;
|
|
1042
1087
|
const holidayModeEnabled = deviceData.HolidayMode?.Enabled;
|
|
1043
1088
|
const holidayModeActive = deviceData.HolidayMode?.Active;
|
|
1044
|
-
const scheduleEnabled = deviceData.ScheduleEnabled;
|
|
1045
1089
|
|
|
1046
1090
|
//device control
|
|
1047
1091
|
const hideVaneControls = deviceData.HideVaneControls ?? false;
|
|
@@ -1093,6 +1137,7 @@ class DeviceAta extends EventEmitter {
|
|
|
1093
1137
|
//accessory
|
|
1094
1138
|
const obj = {
|
|
1095
1139
|
presets: presetsOnServer,
|
|
1140
|
+
schedules: schedulesOnServer,
|
|
1096
1141
|
supportsAutomaticFanSpeed: supportsAutomaticFanSpeed,
|
|
1097
1142
|
supportsAirDirectionFunction: supportsAirDirectionFunction,
|
|
1098
1143
|
supportsSwingFunction: supportsSwingFunction,
|
|
@@ -1288,17 +1333,28 @@ class DeviceAta extends EventEmitter {
|
|
|
1288
1333
|
const presetData = presetsOnServer.find(p => p[presetsIdKey] === preset.id);
|
|
1289
1334
|
|
|
1290
1335
|
preset.state = presetData ? (presetData.Power === power
|
|
1291
|
-
&& presetData
|
|
1336
|
+
&& presetData.SetTemperature === setTemperature
|
|
1292
1337
|
&& presetData.OperationMode === operationMode
|
|
1293
1338
|
&& presetData.VaneHorizontalDirection === vaneHorizontalDirection
|
|
1294
1339
|
&& presetData.VaneVerticalDirection === vaneVerticalDirection
|
|
1295
|
-
&& presetData
|
|
1340
|
+
&& presetData.FanSpeed === setFanSpeed) : false;
|
|
1296
1341
|
|
|
1297
1342
|
const characteristicType = preset.characteristicType;
|
|
1298
1343
|
this.presetsServices?.[i]?.updateCharacteristic(characteristicType, preset.state);
|
|
1299
1344
|
});
|
|
1300
1345
|
};
|
|
1301
1346
|
|
|
1347
|
+
//update schedules state
|
|
1348
|
+
if (this.schedules.length > 0) {
|
|
1349
|
+
this.schedules.forEach((schedule, i) => {
|
|
1350
|
+
const scheduleData = schedulesOnServer.find(s => s[presetsIdKey] === schedule.id);
|
|
1351
|
+
schedule.state = scheduleEnabled; //scheduleData.Enabled : false;
|
|
1352
|
+
|
|
1353
|
+
const characteristicType = schedule.characteristicType;
|
|
1354
|
+
this.schedulesServices?.[i]?.updateCharacteristic(characteristicType, schedule.state);
|
|
1355
|
+
});
|
|
1356
|
+
};
|
|
1357
|
+
|
|
1302
1358
|
//update buttons state
|
|
1303
1359
|
if (this.buttons.length > 0) {
|
|
1304
1360
|
this.buttons.forEach((button, i) => {
|
package/src/deviceatw.js
CHANGED
|
@@ -38,7 +38,8 @@ class DeviceAtw extends EventEmitter {
|
|
|
38
38
|
this.temperatureFlowZone2Sensor = device.temperatureFlowZone2Sensor || false;
|
|
39
39
|
this.temperatureReturnZone2Sensor = device.temperatureReturnZone2Sensor || false;
|
|
40
40
|
this.errorSensor = device.errorSensor || false;
|
|
41
|
-
this.presets = (device.presets || []).filter(preset => (preset.displayType ?? 0) > 0);
|
|
41
|
+
this.presets = this.accountType === 'melcloud' ? (device.presets || []).filter(preset => (preset.displayType ?? 0) > 0 && preset.id !== '0') : [];
|
|
42
|
+
this.schedules = this.accountType === 'melcloudhome' ? (device.schedules || []).filter(schedule => (schedule.displayType ?? 0) > 0 && schedule.id !== '0') : [];
|
|
42
43
|
this.buttons = (device.buttonsSensors || []).filter(button => (button.displayType ?? 0) > 0);
|
|
43
44
|
this.deviceId = device.id;
|
|
44
45
|
this.deviceName = device.name;
|
|
@@ -62,6 +63,14 @@ class DeviceAtw extends EventEmitter {
|
|
|
62
63
|
preset.previousSettings = {};
|
|
63
64
|
}
|
|
64
65
|
|
|
66
|
+
//schedules configured
|
|
67
|
+
for (const schedule of this.schedules) {
|
|
68
|
+
schedule.name = schedule.name || 'Schedule'
|
|
69
|
+
schedule.serviceType = [null, Service.Outlet, Service.Switch, Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor][schedule.displayType];
|
|
70
|
+
schedule.characteristicType = [null, Characteristic.On, Characteristic.On, Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState][schedule.displayType];
|
|
71
|
+
schedule.state = false;
|
|
72
|
+
}
|
|
73
|
+
|
|
65
74
|
//buttons configured
|
|
66
75
|
for (const button of this.buttons) {
|
|
67
76
|
button.name = button.name || 'Button'
|
|
@@ -261,6 +270,7 @@ class DeviceAtw extends EventEmitter {
|
|
|
261
270
|
const deviceName = this.deviceName;
|
|
262
271
|
const accountName = this.accountName;
|
|
263
272
|
const presetsOnServer = this.accessory.presets;
|
|
273
|
+
const schedulesOnServer = this.accessory.schedules;
|
|
264
274
|
const zonesCount = this.accessory.zonesCount;
|
|
265
275
|
const caseHeatPump = this.accessory.caseHeatPump;
|
|
266
276
|
const caseZone1 = this.accessory.caseZone1;
|
|
@@ -1121,6 +1131,42 @@ class DeviceAtw extends EventEmitter {
|
|
|
1121
1131
|
});
|
|
1122
1132
|
};
|
|
1123
1133
|
|
|
1134
|
+
//schedules services
|
|
1135
|
+
if (this.schedules.length > 0) {
|
|
1136
|
+
if (this.logDebug) this.emit('debug', `Prepare schedules services`);
|
|
1137
|
+
this.schedulesServices = [];
|
|
1138
|
+
this.schedules.forEach((schedule, i) => {
|
|
1139
|
+
//get preset name
|
|
1140
|
+
const name = schedule.name;
|
|
1141
|
+
|
|
1142
|
+
//get preset name prefix
|
|
1143
|
+
const namePrefix = schedule.namePrefix;
|
|
1144
|
+
|
|
1145
|
+
const serviceName = namePrefix ? `${accessoryName} ${name}` : name;
|
|
1146
|
+
const serviceType = schedule.serviceType;
|
|
1147
|
+
const characteristicType = schedule.characteristicType;
|
|
1148
|
+
const scheduleService = new serviceType(serviceName, `Schedule ${deviceId} ${i}`);
|
|
1149
|
+
scheduleService.addOptionalCharacteristic(Characteristic.ConfiguredName);
|
|
1150
|
+
scheduleService.setCharacteristic(Characteristic.ConfiguredName, serviceName);
|
|
1151
|
+
scheduleService.getCharacteristic(characteristicType)
|
|
1152
|
+
.onGet(async () => {
|
|
1153
|
+
const state = schedule.state;
|
|
1154
|
+
return state;
|
|
1155
|
+
})
|
|
1156
|
+
.onSet(async (state) => {
|
|
1157
|
+
try {
|
|
1158
|
+
deviceData.ScheduleEnabled = state;
|
|
1159
|
+
await this.melCloudAta.send(this.accountType, this.displayType, deviceData, 'scheduleset');
|
|
1160
|
+
if (this.logInfo) this.emit('info', `${state ? 'Set:' : 'Unset:'} ${name}`);
|
|
1161
|
+
} catch (error) {
|
|
1162
|
+
if (this.logWarn) this.emit('warn', `Set schedule error: ${error}`);
|
|
1163
|
+
};
|
|
1164
|
+
});
|
|
1165
|
+
this.schedulesServices.push(scheduleService);
|
|
1166
|
+
accessory.addService(scheduleService);
|
|
1167
|
+
});
|
|
1168
|
+
};
|
|
1169
|
+
|
|
1124
1170
|
//buttons services
|
|
1125
1171
|
if (this.buttons.length > 0) {
|
|
1126
1172
|
if (this.logDebug) this.emit('debug', `Prepare buttons services`);
|
|
@@ -1336,8 +1382,10 @@ class DeviceAtw extends EventEmitter {
|
|
|
1336
1382
|
const tempStepKey = this.accountType === 'melcloud' ? 'TemperatureIncrement' : 'HasHalfDegreeIncrements';
|
|
1337
1383
|
const errorKey = this.accountType === 'melcloud' ? 'HasError' : 'IsInError';
|
|
1338
1384
|
|
|
1339
|
-
//presets
|
|
1340
|
-
const
|
|
1385
|
+
//presets schedule
|
|
1386
|
+
const scheduleEnabled = deviceData.ScheduleEnabled;
|
|
1387
|
+
const schedulesOnServer = deviceData.Schedule ?? [];
|
|
1388
|
+
const presetsOnServer = deviceData.Presets ?? [];
|
|
1341
1389
|
|
|
1342
1390
|
//device info
|
|
1343
1391
|
const hasHeatPump = ![1, 2, 3, 4, 5, 6, 7, 15].includes(this.hideZone);
|
|
@@ -1416,6 +1464,7 @@ class DeviceAtw extends EventEmitter {
|
|
|
1416
1464
|
//accessory
|
|
1417
1465
|
const obj = {
|
|
1418
1466
|
presets: presetsOnServer,
|
|
1467
|
+
schedules: schedulesOnServer,
|
|
1419
1468
|
power: power ? 1 : 0,
|
|
1420
1469
|
unitStatus: unitStatus,
|
|
1421
1470
|
idleZone1: idleZone1,
|
|
@@ -1439,6 +1488,7 @@ class DeviceAtw extends EventEmitter {
|
|
|
1439
1488
|
useFahrenheit: this.useFahrenheit,
|
|
1440
1489
|
temperatureUnit: TemperatureDisplayUnits[this.useFahrenheit],
|
|
1441
1490
|
isInError: isInError,
|
|
1491
|
+
scheduleEnabled: scheduleEnabled,
|
|
1442
1492
|
zones: [],
|
|
1443
1493
|
zonesSensors: []
|
|
1444
1494
|
};
|
|
@@ -1839,6 +1889,17 @@ class DeviceAtw extends EventEmitter {
|
|
|
1839
1889
|
});
|
|
1840
1890
|
};
|
|
1841
1891
|
|
|
1892
|
+
//update schedules state
|
|
1893
|
+
if (this.schedules.length > 0) {
|
|
1894
|
+
this.schedules.forEach((schedule, i) => {
|
|
1895
|
+
const scheduleData = schedulesOnServer.find(s => s[presetsIdKey] === schedule.id);
|
|
1896
|
+
schedule.state = scheduleEnabled; //scheduleData.Enabled : false;
|
|
1897
|
+
|
|
1898
|
+
const characteristicType = schedule.characteristicType;
|
|
1899
|
+
this.schedulesServices?.[i]?.updateCharacteristic(characteristicType, schedule.state);
|
|
1900
|
+
});
|
|
1901
|
+
};
|
|
1902
|
+
|
|
1842
1903
|
//update buttons state
|
|
1843
1904
|
if (this.buttons.length > 0) {
|
|
1844
1905
|
this.buttons.forEach((button, i) => {
|