homebridge-melcloud-control 4.1.2-beta.29 → 4.1.2-beta.30

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.
@@ -526,6 +526,87 @@
526
526
  ]
527
527
  }
528
528
  },
529
+ "schedules": {
530
+ "title": "Schedules",
531
+ "type": "array",
532
+ "items": {
533
+ "type": "object",
534
+ "properties": {
535
+ "id": {
536
+ "title": "Id",
537
+ "type": "string",
538
+ "default": "0"
539
+ },
540
+ "displayType": {
541
+ "title": "Display Type",
542
+ "type": "integer",
543
+ "minimum": 0,
544
+ "maximum": 5,
545
+ "default": 0,
546
+ "description": "Select the characteristic type to be displayed in HomeKit app.",
547
+ "anyOf": [
548
+ {
549
+ "title": "None/Disabled",
550
+ "enum": [
551
+ 0
552
+ ]
553
+ },
554
+ {
555
+ "title": "Outlet",
556
+ "enum": [
557
+ 1
558
+ ]
559
+ },
560
+ {
561
+ "title": "Switch",
562
+ "enum": [
563
+ 2
564
+ ]
565
+ },
566
+ {
567
+ "title": "Motion Sensor",
568
+ "enum": [
569
+ 3
570
+ ]
571
+ },
572
+ {
573
+ "title": "Occupancy Sensor",
574
+ "enum": [
575
+ 4
576
+ ]
577
+ },
578
+ {
579
+ "title": "Contact Sensor",
580
+ "enum": [
581
+ 5
582
+ ]
583
+ }
584
+ ]
585
+ },
586
+ "name": {
587
+ "title": "Name",
588
+ "type": "string",
589
+ "default": "Preset",
590
+ "description": "Your own name displayed in Homebridge/HomeKit app.",
591
+ "condition": {
592
+ "functionBody": "return model.accounts[arrayIndices[0]].ataDevices[arrayIndices[1]].schedules[arrayIndices[2]].displayType > 0;"
593
+ }
594
+ },
595
+ "namePrefix": {
596
+ "title": "Prefix",
597
+ "type": "boolean",
598
+ "default": false,
599
+ "description": "Enable/disable the accessory name as a prefix for button/sensor name.",
600
+ "condition": {
601
+ "functionBody": "return model.accounts[arrayIndices[0]].ataDevices[arrayIndices[1]].schedules[arrayIndices[2]].displayType > 0;"
602
+ }
603
+ }
604
+ },
605
+ "required": [
606
+ "displayType"
607
+ ]
608
+ }
609
+ },
529
610
  "buttonsSensors": {
530
611
  "title": "Button / Sensor",
531
612
  "type": "array",
@@ -1142,6 +1223,87 @@
1142
1223
  ]
1143
1224
  }
1144
1225
  },
1226
+ "schedules": {
1227
+ "title": "Schedules",
1228
+ "type": "array",
1229
+ "items": {
1230
+ "type": "object",
1231
+ "properties": {
1232
+ "id": {
1233
+ "title": "Id",
1234
+ "type": "string",
1235
+ "default": "0"
1236
+ },
1237
+ "displayType": {
1238
+ "title": "Display Type",
1239
+ "type": "integer",
1240
+ "minimum": 0,
1241
+ "maximum": 5,
1242
+ "default": 0,
1243
+ "description": "Select the characteristic type to be displayed in HomeKit app.",
1244
+ "anyOf": [
1245
+ {
1246
+ "title": "None/Disabled",
1247
+ "enum": [
1248
+ 0
1249
+ ]
1250
+ },
1251
+ {
1252
+ "title": "Outlet",
1253
+ "enum": [
1254
+ 1
1255
+ ]
1256
+ },
1257
+ {
1258
+ "title": "Switch",
1259
+ "enum": [
1260
+ 2
1261
+ ]
1262
+ },
1263
+ {
1264
+ "title": "Motion Sensor",
1265
+ "enum": [
1266
+ 3
1267
+ ]
1268
+ },
1269
+ {
1270
+ "title": "Occupancy Sensor",
1271
+ "enum": [
1272
+ 4
1273
+ ]
1274
+ },
1275
+ {
1276
+ "title": "Contact Sensor",
1277
+ "enum": [
1278
+ 5
1279
+ ]
1280
+ }
1281
+ ]
1282
+ },
1283
+ "name": {
1284
+ "title": "Name",
1285
+ "type": "string",
1286
+ "default": "Preset",
1287
+ "description": "Your own name displayed in Homebridge/HomeKit app.",
1288
+ "condition": {
1289
+ "functionBody": "return model.accounts[arrayIndices[0]].atwDevices[arrayIndices[1]].schedules[arrayIndices[2]].displayType > 0;"
1290
+ }
1291
+ },
1292
+ "namePrefix": {
1293
+ "title": "Prefix",
1294
+ "type": "boolean",
1295
+ "default": false,
1296
+ "description": "Enable/disable the accessory name as a prefix for button/sensor name.",
1297
+ "condition": {
1298
+ "functionBody": "return model.accounts[arrayIndices[0]].atwDevices[arrayIndices[1]].schedules[arrayIndices[2]].displayType > 0;"
1299
+ }
1300
+ }
1301
+ },
1302
+ "required": [
1303
+ "displayType"
1304
+ ]
1305
+ }
1306
+ },
1145
1307
  "buttonsSensors": {
1146
1308
  "title": "Button",
1147
1309
  "type": "array",
@@ -1540,6 +1702,87 @@
1540
1702
  ]
1541
1703
  }
1542
1704
  },
1705
+ "schedules": {
1706
+ "title": "Schedules",
1707
+ "type": "array",
1708
+ "items": {
1709
+ "type": "object",
1710
+ "properties": {
1711
+ "id": {
1712
+ "title": "Id",
1713
+ "type": "string",
1714
+ "default": "0"
1715
+ },
1716
+ "displayType": {
1717
+ "title": "Display Type",
1718
+ "type": "integer",
1719
+ "minimum": 0,
1720
+ "maximum": 5,
1721
+ "default": 0,
1722
+ "description": "Select the characteristic type to be displayed in HomeKit app.",
1723
+ "anyOf": [
1724
+ {
1725
+ "title": "None/Disabled",
1726
+ "enum": [
1727
+ 0
1728
+ ]
1729
+ },
1730
+ {
1731
+ "title": "Outlet",
1732
+ "enum": [
1733
+ 1
1734
+ ]
1735
+ },
1736
+ {
1737
+ "title": "Switch",
1738
+ "enum": [
1739
+ 2
1740
+ ]
1741
+ },
1742
+ {
1743
+ "title": "Motion Sensor",
1744
+ "enum": [
1745
+ 3
1746
+ ]
1747
+ },
1748
+ {
1749
+ "title": "Occupancy Sensor",
1750
+ "enum": [
1751
+ 4
1752
+ ]
1753
+ },
1754
+ {
1755
+ "title": "Contact Sensor",
1756
+ "enum": [
1757
+ 5
1758
+ ]
1759
+ }
1760
+ ]
1761
+ },
1762
+ "name": {
1763
+ "title": "Name",
1764
+ "type": "string",
1765
+ "default": "Preset",
1766
+ "description": "Your own name displayed in Homebridge/HomeKit app.",
1767
+ "condition": {
1768
+ "functionBody": "return model.accounts[arrayIndices[0]].ervDevices[arrayIndices[1]].schedules[arrayIndices[2]].displayType > 0;"
1769
+ }
1770
+ },
1771
+ "namePrefix": {
1772
+ "title": "Prefix",
1773
+ "type": "boolean",
1774
+ "default": false,
1775
+ "description": "Enable/disable the accessory name as a prefix for button/sensor name.",
1776
+ "condition": {
1777
+ "functionBody": "return model.accounts[arrayIndices[0]].ervDevices[arrayIndices[1]].schedules[arrayIndices[2]].displayType > 0;"
1778
+ }
1779
+ }
1780
+ },
1781
+ "required": [
1782
+ "displayType"
1783
+ ]
1784
+ }
1785
+ },
1543
1786
  "buttonsSensors": {
1544
1787
  "title": "Buttons",
1545
1788
  "type": "array",
@@ -1949,7 +2192,33 @@
1949
2192
  }
1950
2193
  ],
1951
2194
  "condition": {
1952
- "functionBody": "return model.accounts[arrayIndices[0]].ataDevices[arrayIndices[1]].displayType > 0;"
2195
+ "functionBody": "return model.accounts[arrayIndices[0]].type === 'melcloud' && model.accounts[arrayIndices[0]].ataDevices[arrayIndices[1]].displayType > 0;"
2196
+ }
2197
+ },
2198
+ {
2199
+ "title": "Schedules",
2200
+ "type": "section",
2201
+ "description": "Section for setup device schedules",
2202
+ "expandable": true,
2203
+ "expanded": false,
2204
+ "items": [
2205
+ {
2206
+ "key": "accounts[].ataDevices[].schedules",
2207
+ "type": "tabarray",
2208
+ "title": "{{ value.name }}",
2209
+ "items": [
2210
+ {
2211
+ "key": "accounts[].ataDevices[].schedules[].id",
2212
+ "readonly": true
2213
+ },
2214
+ "accounts[].ataDevices[].schedules[].displayType",
2215
+ "accounts[].ataDevices[].schedules[].name",
2216
+ "accounts[].ataDevices[].schedules[].namePrefix"
2217
+ ]
2218
+ }
2219
+ ],
2220
+ "condition": {
2221
+ "functionBody": "return model.accounts[arrayIndices[0]].type === 'melcloudhome' && model.accounts[arrayIndices[0]].ataDevices[arrayIndices[1]].displayType > 0;"
1953
2222
  }
1954
2223
  },
1955
2224
  {
@@ -2075,7 +2344,33 @@
2075
2344
  }
2076
2345
  ],
2077
2346
  "condition": {
2078
- "functionBody": "return model.accounts[arrayIndices[0]].atwDevices[arrayIndices[1]].displayType > 0;"
2347
+ "functionBody": "return model.accounts[arrayIndices[0]].type === 'melcloud' && model.accounts[arrayIndices[0]].atwDevices[arrayIndices[1]].displayType > 0;"
2348
+ }
2349
+ },
2350
+ {
2351
+ "title": "Schedules",
2352
+ "type": "section",
2353
+ "description": "Section for setup device schedules",
2354
+ "expandable": true,
2355
+ "expanded": false,
2356
+ "items": [
2357
+ {
2358
+ "key": "accounts[].atwDevices[].schedules",
2359
+ "type": "tabarray",
2360
+ "title": "{{ value.name }}",
2361
+ "items": [
2362
+ {
2363
+ "key": "accounts[].atwDevices[].schedules[].id",
2364
+ "readonly": true
2365
+ },
2366
+ "accounts[].atwDevices[].schedules[].displayType",
2367
+ "accounts[].atwDevices[].schedules[].name",
2368
+ "accounts[].atwDevices[].schedules[].namePrefix"
2369
+ ]
2370
+ }
2371
+ ],
2372
+ "condition": {
2373
+ "functionBody": "return model.accounts[arrayIndices[0]].type === 'melcloudhome' && model.accounts[arrayIndices[0]].atwDevices[arrayIndices[1]].displayType > 0;"
2079
2374
  }
2080
2375
  },
2081
2376
  {
@@ -2194,7 +2489,33 @@
2194
2489
  }
2195
2490
  ],
2196
2491
  "condition": {
2197
- "functionBody": "return model.accounts[arrayIndices[0]].ervDevices[arrayIndices[1]].displayType > 0;"
2492
+ "functionBody": "return model.accounts[arrayIndices[0]].type === 'melcloud' && model.accounts[arrayIndices[0]].ervDevices[arrayIndices[1]].displayType > 0;"
2493
+ }
2494
+ },
2495
+ {
2496
+ "title": "Schedules",
2497
+ "type": "section",
2498
+ "description": "Section for setup device schedules",
2499
+ "expandable": true,
2500
+ "expanded": false,
2501
+ "items": [
2502
+ {
2503
+ "key": "accounts[].ervDevices[].schedules",
2504
+ "type": "tabarray",
2505
+ "title": "{{ value.name }}",
2506
+ "items": [
2507
+ {
2508
+ "key": "accounts[].ervDevices[].schedules[].id",
2509
+ "readonly": true
2510
+ },
2511
+ "accounts[].ervDevices[].schedules[].displayType",
2512
+ "accounts[].ervDevices[].schedules[].name",
2513
+ "accounts[].ervDevices[].schedules[].namePrefix"
2514
+ ]
2515
+ }
2516
+ ],
2517
+ "condition": {
2518
+ "functionBody": "return model.accounts[arrayIndices[0]].type === 'melcloudhome' && model.accounts[arrayIndices[0]].ervDevices[arrayIndices[1]].displayType > 0;"
2198
2519
  }
2199
2520
  },
2200
2521
  {
@@ -262,6 +262,7 @@
262
262
  displayType: 0,
263
263
  name: device.DeviceName,
264
264
  presets: [],
265
+ schedules: [],
265
266
  buttonsSensors: []
266
267
  };
267
268
 
@@ -270,23 +271,41 @@
270
271
  newArr.push(deviceObj);
271
272
  }
272
273
 
273
- const presetsKey = account.type === 'melcloud' ? 'Presets' : 'Schedule';
274
- const presetsIdKey = account.type === 'melcloud' ? 'ID' : 'Id';
275
- const presets = device[presetsKey] || [];
276
- presets.forEach((preset, index) => {
277
- const presetObj = {
278
- id: preset[presetsIdKey],
279
- displayType: 0,
280
- name: preset.NumberDescription || `Preset ${index}`,
281
- namePrefix: false
282
- };
283
-
284
- const deviceInConfig = devicesInConfig.find(dev => String(dev.id) === deviceObj.id);
285
- if (deviceInConfig && !deviceInConfig.presets.some(pres => String(pres.id) === presetObj.id)) {
286
- deviceInConfig.presets.push(presetObj);
287
- newPresets.push(presetObj);
288
- }
289
- });
274
+ if (account.type === 'melcloud') {
275
+ const presets = device.Presets || [];
276
+ presets.forEach((preset, index) => {
277
+ const presetObj = {
278
+ id: preset.ID,
279
+ displayType: 0,
280
+ name: preset.NumberDescription || `Preset ${index}`,
281
+ namePrefix: false
282
+ };
283
+
284
+ const deviceInConfig = devicesInConfig.find(dev => String(dev.id) === deviceObj.id);
285
+ if (deviceInConfig && !deviceInConfig.presets.some(pres => String(pres.id) === presetObj.id)) {
286
+ deviceInConfig.presets.push(presetObj);
287
+ newPresets.push(presetObj);
288
+ }
289
+ });
290
+ }
291
+
292
+ if (account.type === 'melcloudhome') {
293
+ const schedule = device.Schedule || [];
294
+ schedule.forEach((preset, index) => {
295
+ const presetObj = {
296
+ id: preset.Id,
297
+ displayType: 0,
298
+ name: `Schedule ${index}`,
299
+ namePrefix: false
300
+ };
301
+
302
+ const deviceInConfig = devicesInConfig.find(dev => String(dev.id) === deviceObj.id);
303
+ if (deviceInConfig && !deviceInConfig.presets.some(pres => String(pres.id) === presetObj.id)) {
304
+ deviceInConfig.schedules.push(presetObj);
305
+ newPresets.push(presetObj);
306
+ }
307
+ });
308
+ }
290
309
  });
291
310
  };
292
311
 
@@ -304,7 +323,7 @@
304
323
  if (newDevicesCount)
305
324
  updateInfo('info', `Found new devices: ATA: ${newDevices.ata.length}, ATW: ${newDevices.atw.length}, ERV: ${newDevices.erv.length}.`, 'green');
306
325
  if (newPresetsCount)
307
- updateInfo('info1', `Found new presets: ATA: ${newDevices.ataPresets.length}, ATW: ${newDevices.atwPresets.length}, ERV: ${newDevices.ervPresets.length}.`, 'green');
326
+ updateInfo('info1', `Found new ${account.type === 'melcloud' ? 'presets' : 'schedules'}: ATA: ${newDevices.ataPresets.length}, ATW: ${newDevices.atwPresets.length}, ERV: ${newDevices.ervPresets.length}.`, 'green');
308
327
  if (removedDevicesCount)
309
328
  updateInfo('info2', `Removed devices: ATA: ${removedAta.length}, ATW: ${removedAtw.length}, ERV: ${removedErv.length}.`, 'orange');
310
329
  }
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-beta.29",
4
+ "version": "4.1.2-beta.30",
5
5
  "description": "Homebridge plugin to control Mitsubishi Air Conditioner, Heat Pump and Energy Recovery Ventilation.",
6
6
  "license": "MIT",
7
7
  "author": "grzegorz914",
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 && preset.id !== '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.presets || []).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[presetsIdKey] === preset.id);
697
+ const presetData = presetsOnServer.find(p => p.ID === preset.id);
689
698
 
690
699
  //get preset name
691
700
  const name = preset.name;
@@ -737,6 +746,44 @@ class DeviceAta extends EventEmitter {
737
746
  });
738
747
  };
739
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
+ const scheduleData = schedulesOnServer.find(p => p.Id === schedule.id);
755
+
756
+ //get preset name
757
+ const name = schedule.name;
758
+
759
+ //get preset name prefix
760
+ const namePrefix = schedule.namePrefix;
761
+
762
+ const serviceName = namePrefix ? `${accessoryName} ${name}` : name;
763
+ const serviceType = schedule.serviceType;
764
+ const characteristicType = schedule.characteristicType;
765
+ const scheduleService = new serviceType(serviceName, `Schedule ${deviceId} ${i}`);
766
+ scheduleService.addOptionalCharacteristic(Characteristic.ConfiguredName);
767
+ scheduleService.setCharacteristic(Characteristic.ConfiguredName, serviceName);
768
+ scheduleService.getCharacteristic(characteristicType)
769
+ .onGet(async () => {
770
+ const state = schedule.state;
771
+ return state;
772
+ })
773
+ .onSet(async (state) => {
774
+ try {
775
+ deviceData.Schedule = state;
776
+ await this.melCloudAta.send(this.accountType, this.displayType, deviceData);
777
+ if (this.logInfo) this.emit('info', `${state ? 'Set:' : 'Unset:'} ${name}`);
778
+ } catch (error) {
779
+ if (this.logWarn) this.emit('warn', `Set schedule error: ${error}`);
780
+ };
781
+ });
782
+ this.schedulesServices.push(scheduleService);
783
+ accessory.addService(scheduleService);
784
+ });
785
+ };
786
+
740
787
  //buttons services
741
788
  if (this.buttons.length > 0) {
742
789
  if (this.logDebug) this.emit('debug', `Prepare buttons/sensors services`);
@@ -1015,7 +1062,6 @@ class DeviceAta extends EventEmitter {
1015
1062
  this.deviceData = deviceData;
1016
1063
 
1017
1064
  //keys
1018
- const presetsKey = this.accountType === 'melcloud' ? 'Presets' : 'Schedule';
1019
1065
  const presetsIdKey = this.accountType === 'melcloud' ? 'ID' : 'Id';
1020
1066
  const setTempKey = this.accountType === 'melcloud' ? 'SetTemperature' : 'SetPoint';
1021
1067
  const fanKey = this.accountType === 'melcloud' ? 'FanSpeed' : 'SetFanSpeed';
@@ -1031,7 +1077,8 @@ class DeviceAta extends EventEmitter {
1031
1077
 
1032
1078
  //presets schedule
1033
1079
  const scheduleEnabled = deviceData.ScheduleEnabled;
1034
- const presetsOnServer = deviceData[presetsKey] ?? [];
1080
+ const schedulesOnServer = deviceData.Schedule ?? [];
1081
+ const presetsOnServer = deviceData.Presets ?? [];
1035
1082
 
1036
1083
 
1037
1084
  //protection
@@ -1092,6 +1139,7 @@ class DeviceAta extends EventEmitter {
1092
1139
  //accessory
1093
1140
  const obj = {
1094
1141
  presets: presetsOnServer,
1142
+ schedules: schedulesOnServer,
1095
1143
  supportsAutomaticFanSpeed: supportsAutomaticFanSpeed,
1096
1144
  supportsAirDirectionFunction: supportsAirDirectionFunction,
1097
1145
  supportsSwingFunction: supportsSwingFunction,
@@ -1286,18 +1334,29 @@ class DeviceAta extends EventEmitter {
1286
1334
  this.presets.forEach((preset, i) => {
1287
1335
  const presetData = presetsOnServer.find(p => p[presetsIdKey] === preset.id);
1288
1336
 
1289
- preset.state = presetData ? (this.accountType === 'melcloudhome' ? scheduleEnabled && presetData.Enabled : (presetData.Power === power
1337
+ preset.state = presetData ? (presetData.Power === power
1290
1338
  && presetData.SetTemperature === setTemperature
1291
1339
  && presetData.OperationMode === operationMode
1292
1340
  && presetData.VaneHorizontalDirection === vaneHorizontalDirection
1293
1341
  && presetData.VaneVerticalDirection === vaneVerticalDirection
1294
- && presetData.FanSpeed === setFanSpeed)) : false;
1342
+ && presetData.FanSpeed === setFanSpeed) : false;
1295
1343
 
1296
1344
  const characteristicType = preset.characteristicType;
1297
1345
  this.presetsServices?.[i]?.updateCharacteristic(characteristicType, preset.state);
1298
1346
  });
1299
1347
  };
1300
1348
 
1349
+ //update schedules state
1350
+ if (this.schedules.length > 0) {
1351
+ this.schedules.forEach((schedule, i) => {
1352
+ const scheduleData = schedulesOnServer.find(p => p[presetsIdKey] === schedule.id);
1353
+ schedule.state = scheduleData ? scheduleData.Enabled : false;
1354
+
1355
+ const characteristicType = schedule.characteristicType;
1356
+ this.schedulesServices?.[i]?.updateCharacteristic(characteristicType, schedule.state);
1357
+ });
1358
+ };
1359
+
1301
1360
  //update buttons state
1302
1361
  if (this.buttons.length > 0) {
1303
1362
  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 && preset.id !== '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.presets || []).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,44 @@ 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
+ const scheduleData = schedulesOnServer.find(p => p.Id === schedule.id);
1140
+
1141
+ //get preset name
1142
+ const name = schedule.name;
1143
+
1144
+ //get preset name prefix
1145
+ const namePrefix = schedule.namePrefix;
1146
+
1147
+ const serviceName = namePrefix ? `${accessoryName} ${name}` : name;
1148
+ const serviceType = schedule.serviceType;
1149
+ const characteristicType = schedule.characteristicType;
1150
+ const scheduleService = new serviceType(serviceName, `Schedule ${deviceId} ${i}`);
1151
+ scheduleService.addOptionalCharacteristic(Characteristic.ConfiguredName);
1152
+ scheduleService.setCharacteristic(Characteristic.ConfiguredName, serviceName);
1153
+ scheduleService.getCharacteristic(characteristicType)
1154
+ .onGet(async () => {
1155
+ const state = schedule.state;
1156
+ return state;
1157
+ })
1158
+ .onSet(async (state) => {
1159
+ try {
1160
+ deviceData.Schedule = state;
1161
+ await this.melCloudAta.send(this.accountType, this.displayType, deviceData);
1162
+ if (this.logInfo) this.emit('info', `${state ? 'Set:' : 'Unset:'} ${name}`);
1163
+ } catch (error) {
1164
+ if (this.logWarn) this.emit('warn', `Set schedule error: ${error}`);
1165
+ };
1166
+ });
1167
+ this.schedulesServices.push(scheduleService);
1168
+ accessory.addService(scheduleService);
1169
+ });
1170
+ };
1171
+
1124
1172
  //buttons services
1125
1173
  if (this.buttons.length > 0) {
1126
1174
  if (this.logDebug) this.emit('debug', `Prepare buttons services`);
@@ -1336,9 +1384,10 @@ class DeviceAtw extends EventEmitter {
1336
1384
  const tempStepKey = this.accountType === 'melcloud' ? 'TemperatureIncrement' : 'HasHalfDegreeIncrements';
1337
1385
  const errorKey = this.accountType === 'melcloud' ? 'HasError' : 'IsInError';
1338
1386
 
1339
- //presets
1387
+ //presets schedule
1340
1388
  const scheduleEnabled = deviceData.ScheduleEnabled;
1341
- const presetsOnServer = deviceData[presetsKey] ?? [];
1389
+ const schedulesOnServer = deviceData.Schedule ?? [];
1390
+ const presetsOnServer = deviceData.Presets ?? [];
1342
1391
 
1343
1392
  //device info
1344
1393
  const hasHeatPump = ![1, 2, 3, 4, 5, 6, 7, 15].includes(this.hideZone);
@@ -1417,6 +1466,7 @@ class DeviceAtw extends EventEmitter {
1417
1466
  //accessory
1418
1467
  const obj = {
1419
1468
  presets: presetsOnServer,
1469
+ schedules: schedulesOnServer,
1420
1470
  power: power ? 1 : 0,
1421
1471
  unitStatus: unitStatus,
1422
1472
  idleZone1: idleZone1,
@@ -1823,7 +1873,7 @@ class DeviceAtw extends EventEmitter {
1823
1873
  this.presets.forEach((preset, i) => {
1824
1874
  const presetData = presetsOnServer.find(p => p[presetsIdKey] === preset.id);
1825
1875
 
1826
- preset.state = presetData ? (this.accountType === 'melcloudhome' ? scheduleEnabled && presetData.Enabled : (presetData.Power === power
1876
+ preset.state = presetData ? (presetData.Power === power
1827
1877
  && presetData.EcoHotWater === ecoHotWater
1828
1878
  && presetData.OperationModeZone1 === operationModeZone1
1829
1879
  && presetData.OperationModeZone2 === operationModeZone2
@@ -1834,13 +1884,24 @@ class DeviceAtw extends EventEmitter {
1834
1884
  && presetData.SetHeatFlowTemperatureZone1 === setHeatFlowTemperatureZone1
1835
1885
  && presetData.SetHeatFlowTemperatureZone2 === setHeatFlowTemperatureZone2
1836
1886
  && presetData.SetCoolFlowTemperatureZone1 === setCoolFlowTemperatureZone1
1837
- && presetData.SetCoolFlowTemperatureZone2 === setCoolFlowTemperatureZone2)) : false;
1887
+ && presetData.SetCoolFlowTemperatureZone2 === setCoolFlowTemperatureZone2) : false;
1838
1888
 
1839
1889
  const characteristicType = preset.characteristicType;
1840
1890
  this.presetsServices?.[i]?.updateCharacteristic(characteristicType, preset.state);
1841
1891
  });
1842
1892
  };
1843
1893
 
1894
+ //update schedules state
1895
+ if (this.schedules.length > 0) {
1896
+ this.schedules.forEach((schedule, i) => {
1897
+ const scheduleData = schedulesOnServer.find(p => p[presetsIdKey] === schedule.id);
1898
+ schedule.state = scheduleData ? scheduleData.Enabled : false;
1899
+
1900
+ const characteristicType = schedule.characteristicType;
1901
+ this.schedulesServices?.[i]?.updateCharacteristic(characteristicType, schedule.state);
1902
+ });
1903
+ };
1904
+
1844
1905
  //update buttons state
1845
1906
  if (this.buttons.length > 0) {
1846
1907
  this.buttons.forEach((button, i) => {
package/src/deviceerv.js CHANGED
@@ -31,7 +31,8 @@ class DeviceErv extends EventEmitter {
31
31
  this.temperatureOutdoorSensor = device.temperatureOutdoorSensor || false;
32
32
  this.temperatureSupplySensor = device.temperatureSupplySensor || false;
33
33
  this.errorSensor = device.errorSensor || false;
34
- this.presets = (device.presets || []).filter(preset => (preset.displayType ?? 0) > 0 && preset.id !== '0');
34
+ this.presets = this.accountType === 'melcloud' ? (device.presets || []).filter(preset => (preset.displayType ?? 0) > 0 && preset.id !== '0') : [];
35
+ this.schedules = this.accountType === 'melcloudhome' ? (device.presets || []).filter(schedule => (schedule.displayType ?? 0) > 0 && schedule.id !== '0') : [];
35
36
  this.buttons = (device.buttonsSensors || []).filter(button => (button.displayType ?? 0) > 0);
36
37
  this.deviceId = device.id;
37
38
  this.deviceName = device.name;
@@ -55,6 +56,14 @@ class DeviceErv extends EventEmitter {
55
56
  preset.previousSettings = {};
56
57
  }
57
58
 
59
+ //schedules configured
60
+ for (const schedule of this.schedules) {
61
+ schedule.name = schedule.name || 'Schedule'
62
+ schedule.serviceType = [null, Service.Outlet, Service.Switch, Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor][schedule.displayType];
63
+ schedule.characteristicType = [null, Characteristic.On, Characteristic.On, Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState][schedule.displayType];
64
+ schedule.state = false;
65
+ }
66
+
58
67
  //buttons configured
59
68
  for (const button of this.buttons) {
60
69
  button.name = button.name || 'Button'
@@ -230,6 +239,7 @@ class DeviceErv extends EventEmitter {
230
239
  const deviceName = this.deviceName;
231
240
  const accountName = this.accountName;
232
241
  const presetsOnServer = this.accessory.presets;
242
+ const schedulesOnServer = this.accessory.schedules;
233
243
  const hasRoomTemperature = this.accessory.hasRoomTemperature;
234
244
  const hasSupplyTemperature = this.accessory.hasSupplyTemperature;
235
245
  const hasOutdoorTemperature = this.accessory.hasOutdoorTemperature;
@@ -725,6 +735,44 @@ class DeviceErv extends EventEmitter {
725
735
  accessory.addService(presetService);
726
736
  };
727
737
 
738
+ //schedules services
739
+ if (this.schedules.length > 0) {
740
+ if (this.logDebug) this.emit('debug', `Prepare schedules services`);
741
+ this.schedulesServices = [];
742
+ this.schedules.forEach((schedule, i) => {
743
+ const scheduleData = schedulesOnServer.find(p => p.Id === schedule.id);
744
+
745
+ //get preset name
746
+ const name = schedule.name;
747
+
748
+ //get preset name prefix
749
+ const namePrefix = schedule.namePrefix;
750
+
751
+ const serviceName = namePrefix ? `${accessoryName} ${name}` : name;
752
+ const serviceType = schedule.serviceType;
753
+ const characteristicType = schedule.characteristicType;
754
+ const scheduleService = new serviceType(serviceName, `Schedule ${deviceId} ${i}`);
755
+ scheduleService.addOptionalCharacteristic(Characteristic.ConfiguredName);
756
+ scheduleService.setCharacteristic(Characteristic.ConfiguredName, serviceName);
757
+ scheduleService.getCharacteristic(characteristicType)
758
+ .onGet(async () => {
759
+ const state = schedule.state;
760
+ return state;
761
+ })
762
+ .onSet(async (state) => {
763
+ try {
764
+ deviceData.Schedule = state;
765
+ await this.melCloudAta.send(this.accountType, this.displayType, deviceData);
766
+ if (this.logInfo) this.emit('info', `${state ? 'Set:' : 'Unset:'} ${name}`);
767
+ } catch (error) {
768
+ if (this.logWarn) this.emit('warn', `Set schedule error: ${error}`);
769
+ };
770
+ });
771
+ this.schedulesServices.push(scheduleService);
772
+ accessory.addService(scheduleService);
773
+ });
774
+ };
775
+
728
776
  //buttons services
729
777
  if (this.buttons.length > 0) {
730
778
  if (this.logDebug) this.emit('debug', `Prepare buttons services`);
@@ -884,7 +932,8 @@ class DeviceErv extends EventEmitter {
884
932
 
885
933
  //presets schedule
886
934
  const scheduleEnabled = deviceData.ScheduleEnabled;
887
- const presetsOnServer = deviceData[presetsKey] ?? [];
935
+ const schedulesOnServer = deviceData.Schedule ?? [];
936
+ const presetsOnServer = deviceData.Presets ?? [];
888
937
 
889
938
  //device control
890
939
  const hideRoomTemperature = deviceData.HideRoomTemperature;
@@ -935,6 +984,7 @@ class DeviceErv extends EventEmitter {
935
984
  //accessory
936
985
  const obj = {
937
986
  presets: presetsOnServer,
987
+ schedules: schedulesOnServer,
938
988
  hasRoomTemperature: hasRoomTemperature,
939
989
  hasSupplyTemperature: hasSupplyTemperature,
940
990
  hasOutdoorTemperature: hasOutdoorTemperature,
@@ -1119,17 +1169,28 @@ class DeviceErv extends EventEmitter {
1119
1169
  this.presets.forEach((preset, i) => {
1120
1170
  const presetData = presetsOnServer.find(p => p[presetsIdKey] === preset.id);
1121
1171
 
1122
- preset.state = presetData ? (this.accountType === 'melcloudhome' ? scheduleEnabled && presetData.Enabled : (presetData.Power === power
1172
+ preset.state = presetData ? (presetData.Power === power
1123
1173
  && presetData.SetTemperature === setTemperature
1124
1174
  && presetData.OperationMode === operationMode
1125
1175
  && presetData.VentilationMode === ventilationMode
1126
- && presetData.SetFanSpeed === setFanSpeed)) : false;
1176
+ && presetData.SetFanSpeed === setFanSpeed) : false;
1127
1177
 
1128
1178
  const characteristicType = preset.characteristicType;
1129
1179
  this.presetsServices?.[i]?.updateCharacteristic(characteristicType, preset.state);
1130
1180
  });
1131
1181
  };
1132
1182
 
1183
+ //update schedules state
1184
+ if (this.schedules.length > 0) {
1185
+ this.schedules.forEach((schedule, i) => {
1186
+ const scheduleData = schedulesOnServer.find(p => p[presetsIdKey] === schedule.id);
1187
+ schedule.state = scheduleData ? scheduleData.Enabled : false;
1188
+
1189
+ const characteristicType = schedule.characteristicType;
1190
+ this.schedulesServices?.[i]?.updateCharacteristic(characteristicType, schedule.state);
1191
+ });
1192
+ };
1193
+
1133
1194
  //update buttons state
1134
1195
  if (this.buttons.length > 0) {
1135
1196
  this.buttons.forEach((button, i) => {