homebridge-melcloud-control 4.1.3-beta.0 → 4.1.3-beta.10

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/README.md CHANGED
@@ -65,7 +65,8 @@ Homebridge plugin for Air Conditioner, Heat Pump and Energy Recovery Ventilation
65
65
  * Vane V mode `AUTO/1/2/3/4/5/SWING`.
66
66
  * Fan speed mode `AUTO/1/2/3/4/5`.
67
67
  * Presets `SET/UNSET`.
68
- * Schedules `ON/OFF`.
68
+ * Holiday mode `ON/OFF`.
69
+ * Schedule `ON/OFF`.
69
70
  * Sensors:
70
71
  * For automation and notifications.
71
72
  * Power `ON/OFF`.
@@ -80,7 +81,8 @@ Homebridge plugin for Air Conditioner, Heat Pump and Energy Recovery Ventilation
80
81
  * Frost protection.
81
82
  * Overheat protection.
82
83
  * Holiday mode.
83
- * Shedule.
84
+ * Shedule control.
85
+ * Shedule active
84
86
  * Error
85
87
  * Heat Pump:
86
88
  * Heater Cooler:
@@ -118,6 +120,8 @@ Homebridge plugin for Air Conditioner, Heat Pump and Energy Recovery Ventilation
118
120
  * Operating mode `HEAT/COOL/CURVE/HOLIDAY/AUTO HOT WATER/ECO HOT WATER/FORCE HOT WATER`.
119
121
  * Physical lock controls `LOCK/UNLOCK`.
120
122
  * Presets `SET/UNSET`.
123
+ * Holiday mode `ON/OFF`.
124
+ * Schedule `ON/OFF`.
121
125
  * Sensors:
122
126
  * For automation and notifications.
123
127
  * Power `ON/OFF`.
@@ -130,6 +134,9 @@ Homebridge plugin for Air Conditioner, Heat Pump and Energy Recovery Ventilation
130
134
  * Water tank temperature.
131
135
  * Flow Temperature Zone 1, 2, Hot Water.
132
136
  * Return Temperature Zone 1, 2, Hot Water.
137
+ * Holiday mode.
138
+ * Shedule control.
139
+ * Shedule active
133
140
  * Error
134
141
  * Energy Recovery Ventilation Lossnay:
135
142
  * Heater Cooler:
@@ -147,6 +154,8 @@ Homebridge plugin for Air Conditioner, Heat Pump and Energy Recovery Ventilation
147
154
  * Operating mode `LOSSNAY/BYPASS/AUTO/NIGHT PURGE`.
148
155
  * Fan speed mode `AUTO/1/2/3/4`.
149
156
  * Presets `SET/UNSET`.
157
+ * Holiday mode `ON/OFF`.
158
+ * Schedule `ON/OFF`.
150
159
  * Sensors:
151
160
  * For automation and notifications.
152
161
  * Power `ON/OFF`.
@@ -160,6 +169,9 @@ Homebridge plugin for Air Conditioner, Heat Pump and Energy Recovery Ventilation
160
169
  * Filter maintenance.
161
170
  * CO2 detected and level.
162
171
  * PM2.5 air quality and level.
172
+ * Holiday mode.
173
+ * Shedule control.
174
+ * Shedule active
163
175
  * Error
164
176
 
165
177
  ### HOME app current device mode display
@@ -229,8 +241,6 @@ Homebridge plugin for Air Conditioner, Heat Pump and Energy Recovery Ventilation
229
241
  | `ataDevices[].temperatureOutdoorSensor` | This enable extra `Outdoor` temperature sensor to use with automations in HomeKit app. |
230
242
  | `ataDevices[].frostProtectionSensor` | This enable extra `Frost Protectio` sensor to use with automations in HomeKit app. |
231
243
  | `ataDevices[].overHeatProtectionSensor` | This enable extra `Overheat Protection` sensor to use with automations in HomeKit app. |
232
- | `ataDevices[].holidayModeSensor` | This enable extra `Holiday Mode` sensor to use with automations in HomeKit app. |
233
- | `ataDevices[].scheduleSensor` | This enable extra `Shedule` sensor to use with automations in HomeKit app. |
234
244
  | `ataDevices[].errorSensor` | This enable `Error` sensor to use with automations in HomeKit app. |
235
245
  | `ataDevices[].refreshInterval` | Here set the background devices state refresh time in (sec), default `5s`. |
236
246
  | `ataDevices[].presets[]` | Array of ATA device `Presets` created automatically after login to MELCloud from plugin config UI. |
@@ -240,7 +250,7 @@ Homebridge plugin for Air Conditioner, Heat Pump and Energy Recovery Ventilation
240
250
  | `ataDevices[].schedules[]` | Array of ATA device `Schedules` created automatically after login to MELCloud Home from plugin config UI. |
241
251
  | `ataDevices[].schedules[].id` | Read only data, do not change it. |
242
252
  | `ataDevices[].schedules[].name` | Here You can schange the `Schedule Name` which is exposed to the `Homebridge/HomeKit`. |
243
- | `ataDevices[].schedules[].displayType` | Here select display type in HomeKit, `0 - None/Disabled`, `1 - Outlet`, `2 - Switch`, `3 - Motion Sensor`, `4 - Occupancy Sensor`, `5 - Contact Sensor`. |
253
+ | `ataDevices[].schedules[].displayType` | Here select display type in HomeKit, `0 - None/Disabled`, `1 - Motion Sensor`, `2 - Occupancy Sensor`, `3 - Contact Sensor`. |
244
254
  | `ataDevices[].buttonsSensors[]` | Array of buttons sensors. |
245
255
  | `ataDevices[].buttonsSensors[].name` | Here set `Button Name` which You want expose to the `Homebridge/HomeKit`. |
246
256
  | `ataDevices[].buttonsSensors[].mode` | Here select button mode, VH - Vane Horizontal, VV - Vane Horizontal. |
@@ -271,7 +281,7 @@ Homebridge plugin for Air Conditioner, Heat Pump and Energy Recovery Ventilation
271
281
  | `atwDevices[].schedules[]` | Array of ATW device `Schedules` created automatically after login to MELCloud Home from plugin config UI. |
272
282
  | `atwDevices[].schedules[].id` | Read only data, do not change it. |
273
283
  | `atwDevices[].schedules[].name` | Here You can schange the `Schedule Name` which is exposed to the `Homebridge/HomeKit`. |
274
- | `atwDevices[].schedules[].displayType` | Here select display type in HomeKit, `0 - None/Disabled`, `1 - Outlet`, `2 - Switch`, `3 - Motion Sensor`, `4 - Occupancy Sensor`, `5 - Contact Sensor`. |
284
+ | `atwDevices[].schedules[].displayType` | Here select display type in HomeKit, `0 - None/Disabled`, `1 - Motion Sensor`, `2 - Occupancy Sensor`, `3 - Contact Sensor`. |
275
285
  | `atwDevices[].buttonsSensors[]` | Array of buttons sensors. |
276
286
  | `atwDevices[].buttonsSensors[].name` | Here set `Button Name` which You want expose to the `Homebridge/HomeKit`. |
277
287
  | `atwDevices[].buttonsSensors[].mode` | Here select button mode. |
@@ -295,13 +305,13 @@ Homebridge plugin for Air Conditioner, Heat Pump and Energy Recovery Ventilation
295
305
  | `ervDevices[].schedules[]` | Array of ERV device `Schedules` created automatically after login to MELCloud Home from plugin config UI. |
296
306
  | `ervDevices[].schedules[].id` | Read only data, do not change it. |
297
307
  | `ervDevices[].schedules[].name` | Here You can schange the `Schedule Name` which is exposed to the `Homebridge/HomeKit`. |
298
- | `ervDevices[].schedules[].displayType` | Here select display type in HomeKit, `0 - None/Disabled`, `1 - Outlet`, `2 - Switch`, `3 - Motion Sensor`, `4 - Occupancy Sensor`, `5 - Contact Sensor`. |
308
+ | `ervDevices[].schedules[].displayType` | Here select display type in HomeKit, `0 - None/Disabled`, `1 - Motion Sensor`, `2 - Occupancy Sensor`, `3 - Contact Sensor`. |
299
309
  | `ervDevices[].buttonsSensors[]` | Array of buttons sensors. |
300
310
  | `ervDevices[].buttonsSensors[].name` | Here set `Button Name` which You want expose to the `Homebridge/HomeKit`. |
301
311
  | `ervDevices[].buttonsSensors[].mode` | Here select button mode. |
302
312
  | `ervDevices[].buttonsSensors[].displayType` | Here select display type in HomeKit, `0 - None/Disabled`, `1 - Outlet`, `2 - Switch`, `3 - Motion Sensor`, `4 - Occupancy Sensor`, `5 - Contact Sensor`. |
303
313
  | `ervDevices[].buttonsSensors[].namePrefix` | Here enable/disable the accessory name as a prefix for button/sensor name. |
304
- | `refreshInterval` | Here set the background account data refresh time in (sec), default `120s`. |
314
+ | `refreshInterval` | Here set the background account data refresh time in (sec) , only for old MELCLoud, default `120s`. |
305
315
  | `log{}` | Log object. |
306
316
  | `log.deviceInfo` | If enabled, log device info will be displayed by every connections device to the network. |
307
317
  | `log.success` | If enabled, success log will be displayed in console. |
@@ -413,24 +413,6 @@
413
413
  "functionBody": "return model.accounts[arrayIndices[0]].type === 'melcloudhome';"
414
414
  }
415
415
  },
416
- "holidayModeSensor": {
417
- "title": "Holiday Mode",
418
- "type": "boolean",
419
- "default": false,
420
- "description": "This enable extra holiday mode sensor to use with automations in HomeKit app.",
421
- "condition": {
422
- "functionBody": "return model.accounts[arrayIndices[0]].type === 'melcloudhome';"
423
- }
424
- },
425
- "scheduleSensor": {
426
- "title": "Schedule",
427
- "type": "boolean",
428
- "default": false,
429
- "description": "This enable extra schedule sensor to use with automations in HomeKit app.",
430
- "condition": {
431
- "functionBody": "return model.accounts[arrayIndices[0]].type === 'melcloudhome';"
432
- }
433
- },
434
416
  "errorSensor": {
435
417
  "title": "Error",
436
418
  "type": "boolean",
@@ -541,7 +523,7 @@
541
523
  "title": "Display Type",
542
524
  "type": "integer",
543
525
  "minimum": 0,
544
- "maximum": 5,
526
+ "maximum": 3,
545
527
  "default": 0,
546
528
  "description": "Select the characteristic type to be displayed in HomeKit app.",
547
529
  "anyOf": [
@@ -551,34 +533,22 @@
551
533
  0
552
534
  ]
553
535
  },
554
- {
555
- "title": "Outlet",
556
- "enum": [
557
- 1
558
- ]
559
- },
560
- {
561
- "title": "Switch",
562
- "enum": [
563
- 2
564
- ]
565
- },
566
536
  {
567
537
  "title": "Motion Sensor",
568
538
  "enum": [
569
- 3
539
+ 1
570
540
  ]
571
541
  },
572
542
  {
573
543
  "title": "Occupancy Sensor",
574
544
  "enum": [
575
- 4
545
+ 2
576
546
  ]
577
547
  },
578
548
  {
579
549
  "title": "Contact Sensor",
580
550
  "enum": [
581
- 5
551
+ 3
582
552
  ]
583
553
  }
584
554
  ]
@@ -1238,7 +1208,7 @@
1238
1208
  "title": "Display Type",
1239
1209
  "type": "integer",
1240
1210
  "minimum": 0,
1241
- "maximum": 5,
1211
+ "maximum": 3,
1242
1212
  "default": 0,
1243
1213
  "description": "Select the characteristic type to be displayed in HomeKit app.",
1244
1214
  "anyOf": [
@@ -1248,34 +1218,22 @@
1248
1218
  0
1249
1219
  ]
1250
1220
  },
1251
- {
1252
- "title": "Outlet",
1253
- "enum": [
1254
- 1
1255
- ]
1256
- },
1257
- {
1258
- "title": "Switch",
1259
- "enum": [
1260
- 2
1261
- ]
1262
- },
1263
1221
  {
1264
1222
  "title": "Motion Sensor",
1265
1223
  "enum": [
1266
- 3
1224
+ 1
1267
1225
  ]
1268
1226
  },
1269
1227
  {
1270
1228
  "title": "Occupancy Sensor",
1271
1229
  "enum": [
1272
- 4
1230
+ 2
1273
1231
  ]
1274
1232
  },
1275
1233
  {
1276
1234
  "title": "Contact Sensor",
1277
1235
  "enum": [
1278
- 5
1236
+ 3
1279
1237
  ]
1280
1238
  }
1281
1239
  ]
@@ -1717,7 +1675,7 @@
1717
1675
  "title": "Display Type",
1718
1676
  "type": "integer",
1719
1677
  "minimum": 0,
1720
- "maximum": 5,
1678
+ "maximum": 3,
1721
1679
  "default": 0,
1722
1680
  "description": "Select the characteristic type to be displayed in HomeKit app.",
1723
1681
  "anyOf": [
@@ -1727,34 +1685,22 @@
1727
1685
  0
1728
1686
  ]
1729
1687
  },
1730
- {
1731
- "title": "Outlet",
1732
- "enum": [
1733
- 1
1734
- ]
1735
- },
1736
- {
1737
- "title": "Switch",
1738
- "enum": [
1739
- 2
1740
- ]
1741
- },
1742
1688
  {
1743
1689
  "title": "Motion Sensor",
1744
1690
  "enum": [
1745
- 3
1691
+ 1
1746
1692
  ]
1747
1693
  },
1748
1694
  {
1749
1695
  "title": "Occupancy Sensor",
1750
1696
  "enum": [
1751
- 4
1697
+ 2
1752
1698
  ]
1753
1699
  },
1754
1700
  {
1755
1701
  "title": "Contact Sensor",
1756
1702
  "enum": [
1757
- 5
1703
+ 3
1758
1704
  ]
1759
1705
  }
1760
1706
  ]
@@ -1967,7 +1913,10 @@
1967
1913
  "default": 120,
1968
1914
  "minimum": 1,
1969
1915
  "maximum": 600,
1970
- "description": "Set the background account data refresh time in seconds."
1916
+ "description": "Set the background account data refresh time in seconds.",
1917
+ "condition": {
1918
+ "functionBody": "return model.accounts[arrayIndices[0]].type === 'melcloud';"
1919
+ }
1971
1920
  },
1972
1921
  "log": {
1973
1922
  "title": "Log",
@@ -2244,8 +2193,6 @@
2244
2193
  "items": [
2245
2194
  "accounts[].ataDevices[].frostProtectionSensor",
2246
2195
  "accounts[].ataDevices[].overheatProtectionSensor",
2247
- "accounts[].ataDevices[].holidayModeSensor",
2248
- "accounts[].ataDevices[].scheduleSensor",
2249
2196
  "accounts[].ataDevices[].errorSensor"
2250
2197
  ]
2251
2198
  },
@@ -2592,7 +2539,6 @@
2592
2539
  "title": "{{ value.name }}",
2593
2540
  "items": [
2594
2541
  {
2595
- "key": "accounts[]",
2596
2542
  "title": "Account Data Refresh",
2597
2543
  "items": [
2598
2544
  "accounts[].refreshInterval"
@@ -2611,7 +2557,6 @@
2611
2557
  ]
2612
2558
  },
2613
2559
  {
2614
- "key": "accounts[]",
2615
2560
  "title": "External Integrations",
2616
2561
  "items": [
2617
2562
  {
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.3-beta.0",
4
+ "version": "4.1.3-beta.10",
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/constants.js CHANGED
@@ -21,12 +21,13 @@ 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",
25
24
  SetAtw: "/api/atwunit/deviceid",
26
- GetAtwSchedule: "/atw/deviceid/schedule",
27
25
  SetErv: "/api/ervunit/deviceid",
28
- GetErvSchedule: "/erv/deviceid/schedule",
29
- SetSchedule: "/api/cloudschedule/deviceid/enabled",
26
+ PutScheduleEnable: "/api/cloudschedule/deviceid/enabled", // PUT {"enabled":true}
27
+ PostSchedule: " /api/cloudschedule/deviceid", // POST {"days":[2],"time":"17:59:00","enabled":true,"id":"53c5e804-0663-47d0-85c2-2d8ccd2573de","power":false,"operationMode":null,"setPoint":null,"vaneVerticalDirection":null,"vaneHorizontalDirection":null,"setFanSpeed":null}
28
+ PostProtectionFrost: "/api/protection/frost", // POST {"enabled":true,"min":13,"max":16,"units":{"ATA":["ef333525-2699-4290-af5a-2922566676da"]}}
29
+ PostProtectionOverheat: "api/protection/overheat", // POST {"enabled":true,"min":32,"max":35,"units":{"ATA":["ef333525-2699-4290-af5a-2922566676da"]}}
30
+ PostHolidayMode: " /api/holidaymode" // POST {"enabled":true,"startDate":"2025-11-11T17:42:24.913","endDate":"2026-06-01T09:18:00","units":{"ATA":["ef333525-2699-4290-af5a-2922566676da"]}}
30
31
  };
31
32
 
32
33
  export const DeviceType = [
package/src/deviceata.js CHANGED
@@ -31,8 +31,6 @@ class DeviceAta extends EventEmitter {
31
31
  this.temperatureOutdoorSensor = device.temperatureOutdoorSensor || false;
32
32
  this.frostProtectionSensor = device.frostProtectionSensor || false;
33
33
  this.overheatProtectionSensor = device.overheatProtectionSensor || false;
34
- this.holidayModeSensor = device.holidayModeSensor || false;
35
- this.scheduleSensor = device.scheduleSensor || false;
36
34
  this.errorSensor = device.errorSensor || false;
37
35
  this.heatDryFanMode = device.heatDryFanMode || 1; //NONE, HEAT, DRY, FAN
38
36
  this.coolDryFanMode = device.coolDryFanMode || 1; //NONE, COOL, DRY, FAN
@@ -65,8 +63,8 @@ class DeviceAta extends EventEmitter {
65
63
  //schedules configured
66
64
  for (const schedule of this.schedules) {
67
65
  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];
66
+ schedule.serviceType = [null, Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor][schedule.displayType];
67
+ schedule.characteristicType = [null, Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState][schedule.displayType];
70
68
  schedule.state = false;
71
69
  }
72
70
 
@@ -634,7 +632,7 @@ class DeviceAta extends EventEmitter {
634
632
  }
635
633
 
636
634
  //overheat sensor
637
- if (this.overheatProtectionSensor && this.accessory.overheatProtectionEnabled) {
635
+ if (this.overheatProtectionSensor && this.accessory.overheatProtectionEnabled !== null) {
638
636
  if (this.logDebug) this.emit('debug', `Prepare overheat protection service`);
639
637
  this.overheatProtectionSensorService = new Service.ContactSensor(`${serviceName} Overheat Protection`, `Overheat Protection Sensor ${deviceId}`);
640
638
  this.overheatProtectionSensorService.addOptionalCharacteristic(Characteristic.ConfiguredName);
@@ -647,9 +645,29 @@ class DeviceAta extends EventEmitter {
647
645
  accessory.addService(this.overheatProtectionSensorService);
648
646
  }
649
647
 
650
- //holiday mode sensor
651
- if (this.holidayModeSensor && this.accessory.holidayModeEnabled) {
652
- if (this.logDebug) this.emit('debug', `Prepare holiday mode service`);
648
+ //holiday mode
649
+ if (this.accessory.holidayModeEnabled !== null) {
650
+ if (this.logDebug) this.emit('debug', `Prepare holiday mode control service`);
651
+ this.holidayModeControlService = new Service.Switch(serviceName, `Holiday Mode Control ${deviceId} ${i}`);
652
+ this.holidayModeControlService.addOptionalCharacteristic(Characteristic.ConfiguredName);
653
+ this.holidayModeControlService.setCharacteristic(Characteristic.ConfiguredName, `${accessoryName} Holiday Mode Control`);
654
+ this.holidayModeControlService.getCharacteristic(Characteristic.On)
655
+ .onGet(async () => {
656
+ const state = this.accessory.holidayModeEnabled;
657
+ return state;
658
+ })
659
+ .onSet(async (state) => {
660
+ try {
661
+ deviceData.HolidayMode.Enabled = state;
662
+ await this.melCloudAta.send(this.accountType, this.displayType, deviceData, 'holidaymode');
663
+ if (this.logInfo) this.emit('info', `Holiday mode: ${state ? 'Enabled' : 'Disabled'}`);
664
+ } catch (error) {
665
+ if (this.logWarn) this.emit('warn', `Set holiday mode error: ${error}`);
666
+ };
667
+ });
668
+ accessory.addService(this.holidayModeControlService);
669
+
670
+ if (this.logDebug) this.emit('debug', `Prepare holiday mode sensor service`);
653
671
  this.holidayModeSensorService = new Service.ContactSensor(`${serviceName} Holiday Mode`, `Holiday Mode Sensor ${deviceId}`);
654
672
  this.holidayModeSensorService.addOptionalCharacteristic(Characteristic.ConfiguredName);
655
673
  this.holidayModeSensorService.setCharacteristic(Characteristic.ConfiguredName, `${accessoryName} Holiday Mode`);
@@ -661,20 +679,6 @@ class DeviceAta extends EventEmitter {
661
679
  accessory.addService(this.holidayModeSensorService);
662
680
  }
663
681
 
664
- //schedule sensor
665
- if (this.scheduleSensor && this.accessory.scheduleEnabled !== null) {
666
- if (this.logDebug) this.emit('debug', `Prepare schedule service`);
667
- this.scheduleSensorService = new Service.ContactSensor(`${serviceName} Schedule`, `Schedule Sensor ${deviceId}`);
668
- this.scheduleSensorService.addOptionalCharacteristic(Characteristic.ConfiguredName);
669
- this.scheduleSensorService.setCharacteristic(Characteristic.ConfiguredName, `${accessoryName} Schedule`);
670
- this.scheduleSensorService.getCharacteristic(Characteristic.ContactSensorState)
671
- .onGet(async () => {
672
- const state = this.accessory.scheduleEnabled;
673
- return state;
674
- })
675
- accessory.addService(this.scheduleSensorService);
676
- }
677
-
678
682
  //error sensor
679
683
  if (this.errorSensor && this.accessory.isInError !== null) {
680
684
  if (this.logDebug) this.emit('debug', `Prepare error service`);
@@ -747,7 +751,7 @@ class DeviceAta extends EventEmitter {
747
751
  };
748
752
 
749
753
  //schedules services
750
- if (this.schedules.length > 0) {
754
+ if (this.schedules.length > 0 && this.accessory.scheduleEnabled !== null) {
751
755
  if (this.logDebug) this.emit('debug', `Prepare schedules services`);
752
756
  this.schedulesServices = [];
753
757
  this.schedules.forEach((schedule, i) => {
@@ -757,25 +761,52 @@ class DeviceAta extends EventEmitter {
757
761
  //get preset name prefix
758
762
  const namePrefix = schedule.namePrefix;
759
763
 
764
+ //control
765
+ if (i === 0) {
766
+ if (this.logDebug) this.emit('debug', `Prepare schedule control service`);
767
+ const serviceNameSchedule = namePrefix ? `${accessoryName} Schedule Control` : `Schedule Control`;
768
+ this.schedulesControlService = new Service.Switch(serviceNameSchedule, `Schedule Control ${deviceId} ${i}`);
769
+ this.schedulesControlService.addOptionalCharacteristic(Characteristic.ConfiguredName);
770
+ this.schedulesControlService.setCharacteristic(Characteristic.ConfiguredName, serviceNameSchedule);
771
+ this.schedulesControlService.getCharacteristic(Characteristic.On)
772
+ .onGet(async () => {
773
+ const state = this.accessory.scheduleEnabled;
774
+ return state;
775
+ })
776
+ .onSet(async (state) => {
777
+ try {
778
+ deviceData.ScheduleEnabled = state;
779
+ await this.melCloudAta.send(this.accountType, this.displayType, deviceData, 'scheduleenabled');
780
+ if (this.logInfo) this.emit('info', `Schedule: ${state ? 'Enabled' : 'Disabled'}`);
781
+ } catch (error) {
782
+ if (this.logWarn) this.emit('warn', `Set schedule error: ${error}`);
783
+ };
784
+ });
785
+ accessory.addService(this.schedulesControlService);
786
+
787
+ if (this.logDebug) this.emit('debug', `Prepare schedule control sensor service`);
788
+ this.scheduleSensorService = new Service.ContactSensor(serviceNameSchedule, `Schedule Control Sensor ${deviceId}`);
789
+ this.scheduleSensorService.addOptionalCharacteristic(Characteristic.ConfiguredName);
790
+ this.scheduleSensorService.setCharacteristic(Characteristic.ConfiguredName, serviceNameSchedule);
791
+ this.scheduleSensorService.getCharacteristic(Characteristic.ContactSensorState)
792
+ .onGet(async () => {
793
+ const state = this.accessory.scheduleEnabled;
794
+ return state;
795
+ })
796
+ accessory.addService(this.scheduleSensorService);
797
+ }
798
+
799
+ //sensors
760
800
  const serviceName = namePrefix ? `${accessoryName} ${name}` : name;
761
801
  const serviceType = schedule.serviceType;
762
802
  const characteristicType = schedule.characteristicType;
763
- const scheduleService = new serviceType(serviceName, `Schedule ${deviceId} ${i}`);
803
+ const scheduleService = new serviceType(serviceName, `Schedule Sensor ${deviceId} ${i}`);
764
804
  scheduleService.addOptionalCharacteristic(Characteristic.ConfiguredName);
765
805
  scheduleService.setCharacteristic(Characteristic.ConfiguredName, serviceName);
766
806
  scheduleService.getCharacteristic(characteristicType)
767
807
  .onGet(async () => {
768
808
  const state = schedule.state;
769
809
  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
810
  });
780
811
  this.schedulesServices.push(scheduleService);
781
812
  accessory.addService(scheduleService);
@@ -1073,19 +1104,18 @@ class DeviceAta extends EventEmitter {
1073
1104
  const supportDryKey = this.accountType === 'melcloud' ? 'ModelSupportsDry' : 'HasDryOperationMode';
1074
1105
  const supportCoolKey = this.accountType === 'melcloud' ? 'ModelSupportsCool' : 'HasCoolOperationMode';
1075
1106
 
1076
- //presets schedule
1107
+ //presets schedules
1077
1108
  const scheduleEnabled = deviceData.ScheduleEnabled;
1078
1109
  const schedulesOnServer = deviceData.Schedule ?? [];
1079
1110
  const presetsOnServer = deviceData.Presets ?? [];
1080
-
1111
+ const holidayModeEnabled = deviceData.HolidayMode?.Enabled;
1112
+ const holidayModeActive = deviceData.HolidayMode?.Active;
1081
1113
 
1082
1114
  //protection
1083
1115
  const frostProtectionEnabled = deviceData.FrostProtection?.Enabled;
1084
1116
  const frostProtectionActive = deviceData.FrostProtection?.Active;
1085
1117
  const overheatProtectionEnabled = deviceData.OverheatProtection?.Enabled;
1086
1118
  const overheatProtectionActive = deviceData.OverheatProtection?.Active;
1087
- const holidayModeEnabled = deviceData.HolidayMode?.Enabled;
1088
- const holidayModeActive = deviceData.HolidayMode?.Active;
1089
1119
 
1090
1120
  //device control
1091
1121
  const hideVaneControls = deviceData.HideVaneControls ?? false;
@@ -1323,8 +1353,8 @@ class DeviceAta extends EventEmitter {
1323
1353
  this.outdoorTemperatureSensorService?.updateCharacteristic(Characteristic.CurrentTemperature, outdoorTemperature);
1324
1354
  this.frostProtectionSensorService?.updateCharacteristic(Characteristic.ContactSensorState, frostProtectionActive);
1325
1355
  this.overheatProtectionSensorService?.updateCharacteristic(Characteristic.ContactSensorState, overheatProtectionActive);
1356
+ this.holidayModeControlService?.updateCharacteristic(Characteristic.ContactSensorState, holidayModeEnabled);
1326
1357
  this.holidayModeSensorService?.updateCharacteristic(Characteristic.ContactSensorState, holidayModeActive);
1327
- this.scheduleSensorService?.updateCharacteristic(Characteristic.ContactSensorState, scheduleEnabled);
1328
1358
  this.errorService?.updateCharacteristic(Characteristic.ContactSensorState, isInError);
1329
1359
 
1330
1360
  //update presets state
@@ -1345,10 +1375,14 @@ class DeviceAta extends EventEmitter {
1345
1375
  };
1346
1376
 
1347
1377
  //update schedules state
1348
- if (this.schedules.length > 0) {
1378
+ if (this.schedules.length > 0 && scheduleEnabled !== null) {
1349
1379
  this.schedules.forEach((schedule, i) => {
1380
+ //control
1381
+ if (i === 0) this.schedulesControlService?.updateCharacteristic(Characteristic.On, scheduleEnabled);
1382
+
1383
+ //sensors
1350
1384
  const scheduleData = schedulesOnServer.find(s => s[presetsIdKey] === schedule.id);
1351
- schedule.state = scheduleEnabled; //scheduleData.Enabled : false;
1385
+ schedule.state = scheduleEnabled ? scheduleData.Enabled ?? false : false;
1352
1386
 
1353
1387
  const characteristicType = schedule.characteristicType;
1354
1388
  this.schedulesServices?.[i]?.updateCharacteristic(characteristicType, schedule.state);
package/src/deviceatw.js CHANGED
@@ -66,8 +66,8 @@ class DeviceAtw extends EventEmitter {
66
66
  //schedules configured
67
67
  for (const schedule of this.schedules) {
68
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];
69
+ schedule.serviceType = [null, Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor][schedule.displayType];
70
+ schedule.characteristicType = [null, Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState][schedule.displayType];
71
71
  schedule.state = false;
72
72
  }
73
73
 
@@ -877,20 +877,6 @@ class DeviceAtw extends EventEmitter {
877
877
  })
878
878
  accessory.addService(this.returnTemperatureSensorService);
879
879
  };
880
-
881
- //error sensor
882
- if (this.errorSensor && this.accessory.isInError !== null) {
883
- if (this.logDebug) this.emit('debug', `Prepare error service`);
884
- this.errorService = new Service.ContactSensor(`${serviceName} Error`, `Error Sensor ${deviceId}`);
885
- this.errorService.addOptionalCharacteristic(Characteristic.ConfiguredName);
886
- this.errorService.setCharacteristic(Characteristic.ConfiguredName, `${accessoryName} Error`);
887
- this.errorService.getCharacteristic(Characteristic.ContactSensorState)
888
- .onGet(async () => {
889
- const state = this.accessory.isInError;
890
- return state;
891
- })
892
- accessory.addService(this.errorService);
893
- }
894
880
  break;
895
881
  case caseZone1Sensor: //Zone 1
896
882
  if (zone.roomTemperature !== null) {
@@ -1061,6 +1047,54 @@ class DeviceAtw extends EventEmitter {
1061
1047
  });
1062
1048
  };
1063
1049
 
1050
+ //holiday mode
1051
+ if (this.accessory.holidayModeEnabled !== null) {
1052
+ if (this.logDebug) this.emit('debug', `Prepare holiday mode control service`);
1053
+ this.holidayModeControlService = new Service.Switch(serviceName, `Holiday Mode Control ${deviceId} ${i}`);
1054
+ this.holidayModeControlService.addOptionalCharacteristic(Characteristic.ConfiguredName);
1055
+ this.holidayModeControlService.setCharacteristic(Characteristic.ConfiguredName, `${accessoryName} Holiday Mode Control`);
1056
+ this.holidayModeControlService.getCharacteristic(Characteristic.On)
1057
+ .onGet(async () => {
1058
+ const state = this.accessory.holidayModeEnabled;
1059
+ return state;
1060
+ })
1061
+ .onSet(async (state) => {
1062
+ try {
1063
+ deviceData.HolidayMode.Enabled = state;
1064
+ await this.melCloudAta.send(this.accountType, this.displayType, deviceData, 'holidaymode');
1065
+ if (this.logInfo) this.emit('info', `Holiday mode: ${state ? 'Enabled' : 'Disabled'}`);
1066
+ } catch (error) {
1067
+ if (this.logWarn) this.emit('warn', `Set holiday mode error: ${error}`);
1068
+ };
1069
+ });
1070
+ accessory.addService(this.holidayModeControlService);
1071
+
1072
+ if (this.logDebug) this.emit('debug', `Prepare holiday mode sensor service`);
1073
+ this.holidayModeSensorService = new Service.ContactSensor(`${serviceName} Holiday Mode`, `Holiday Mode Sensor ${deviceId}`);
1074
+ this.holidayModeSensorService.addOptionalCharacteristic(Characteristic.ConfiguredName);
1075
+ this.holidayModeSensorService.setCharacteristic(Characteristic.ConfiguredName, `${accessoryName} Holiday Mode`);
1076
+ this.holidayModeSensorService.getCharacteristic(Characteristic.ContactSensorState)
1077
+ .onGet(async () => {
1078
+ const state = this.accessory.holidayModeActive;
1079
+ return state;
1080
+ })
1081
+ accessory.addService(this.holidayModeSensorService);
1082
+ }
1083
+
1084
+ //error sensor
1085
+ if (this.errorSensor && this.accessory.isInError !== null) {
1086
+ if (this.logDebug) this.emit('debug', `Prepare error service`);
1087
+ this.errorService = new Service.ContactSensor(`${serviceName} Error`, `Error Sensor ${deviceId}`);
1088
+ this.errorService.addOptionalCharacteristic(Characteristic.ConfiguredName);
1089
+ this.errorService.setCharacteristic(Characteristic.ConfiguredName, `${accessoryName} Error`);
1090
+ this.errorService.getCharacteristic(Characteristic.ContactSensorState)
1091
+ .onGet(async () => {
1092
+ const state = this.accessory.isInError;
1093
+ return state;
1094
+ })
1095
+ accessory.addService(this.errorService);
1096
+ }
1097
+
1064
1098
  //presets services
1065
1099
  if (this.presets.length > 0) {
1066
1100
  if (this.logDebug) this.emit('debug', `Prepare presets services`);
@@ -1132,7 +1166,7 @@ class DeviceAtw extends EventEmitter {
1132
1166
  };
1133
1167
 
1134
1168
  //schedules services
1135
- if (this.schedules.length > 0) {
1169
+ if (this.schedules.length > 0 && this.accessory.scheduleEnabled !== null) {
1136
1170
  if (this.logDebug) this.emit('debug', `Prepare schedules services`);
1137
1171
  this.schedulesServices = [];
1138
1172
  this.schedules.forEach((schedule, i) => {
@@ -1142,25 +1176,52 @@ class DeviceAtw extends EventEmitter {
1142
1176
  //get preset name prefix
1143
1177
  const namePrefix = schedule.namePrefix;
1144
1178
 
1179
+ //control
1180
+ if (i === 0) {
1181
+ if (this.logDebug) this.emit('debug', `Prepare schedule control service`);
1182
+ const serviceNameSchedule = namePrefix ? `${accessoryName} Schedule Control` : `Schedule Control`;
1183
+ this.schedulesControlService = new Service.Switch(serviceNameSchedule, `Schedule Control ${deviceId} ${i}`);
1184
+ this.schedulesControlService.addOptionalCharacteristic(Characteristic.ConfiguredName);
1185
+ this.schedulesControlService.setCharacteristic(Characteristic.ConfiguredName, serviceNameSchedule);
1186
+ this.schedulesControlService.getCharacteristic(Characteristic.On)
1187
+ .onGet(async () => {
1188
+ const state = this.accessory.scheduleEnabled;
1189
+ return state;
1190
+ })
1191
+ .onSet(async (state) => {
1192
+ try {
1193
+ deviceData.ScheduleEnabled = state;
1194
+ await this.melCloudAta.send(this.accountType, this.displayType, deviceData, 'scheduleenabled');
1195
+ if (this.logInfo) this.emit('info', `Schedule: ${state ? 'Enabled' : 'Disabled'}`);
1196
+ } catch (error) {
1197
+ if (this.logWarn) this.emit('warn', `Set schedule error: ${error}`);
1198
+ };
1199
+ });
1200
+ accessory.addService(this.schedulesControlService);
1201
+
1202
+ if (this.logDebug) this.emit('debug', `Prepare schedule control sensor service`);
1203
+ this.scheduleSensorService = new Service.ContactSensor(serviceNameSchedule, `Schedule Control Sensor ${deviceId}`);
1204
+ this.scheduleSensorService.addOptionalCharacteristic(Characteristic.ConfiguredName);
1205
+ this.scheduleSensorService.setCharacteristic(Characteristic.ConfiguredName, serviceNameSchedule);
1206
+ this.scheduleSensorService.getCharacteristic(Characteristic.ContactSensorState)
1207
+ .onGet(async () => {
1208
+ const state = this.accessory.scheduleEnabled;
1209
+ return state;
1210
+ })
1211
+ accessory.addService(this.scheduleSensorService);
1212
+ }
1213
+
1214
+ //sensors
1145
1215
  const serviceName = namePrefix ? `${accessoryName} ${name}` : name;
1146
1216
  const serviceType = schedule.serviceType;
1147
1217
  const characteristicType = schedule.characteristicType;
1148
- const scheduleService = new serviceType(serviceName, `Schedule ${deviceId} ${i}`);
1218
+ const scheduleService = new serviceType(serviceName, `Schedule Sensor ${deviceId} ${i}`);
1149
1219
  scheduleService.addOptionalCharacteristic(Characteristic.ConfiguredName);
1150
1220
  scheduleService.setCharacteristic(Characteristic.ConfiguredName, serviceName);
1151
1221
  scheduleService.getCharacteristic(characteristicType)
1152
1222
  .onGet(async () => {
1153
1223
  const state = schedule.state;
1154
1224
  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
1225
  });
1165
1226
  this.schedulesServices.push(scheduleService);
1166
1227
  accessory.addService(scheduleService);
@@ -1377,7 +1438,6 @@ class DeviceAtw extends EventEmitter {
1377
1438
  this.deviceData = deviceData;
1378
1439
 
1379
1440
  //keys
1380
- const presetsKey = this.accountType === 'melcloud' ? 'Presets' : 'Schedule';
1381
1441
  const presetsIdKey = this.accountType === 'melcloud' ? 'ID' : 'Id';
1382
1442
  const tempStepKey = this.accountType === 'melcloud' ? 'TemperatureIncrement' : 'HasHalfDegreeIncrements';
1383
1443
  const errorKey = this.accountType === 'melcloud' ? 'HasError' : 'IsInError';
@@ -1386,6 +1446,8 @@ class DeviceAtw extends EventEmitter {
1386
1446
  const scheduleEnabled = deviceData.ScheduleEnabled;
1387
1447
  const schedulesOnServer = deviceData.Schedule ?? [];
1388
1448
  const presetsOnServer = deviceData.Presets ?? [];
1449
+ const holidayModeEnabled = deviceData.HolidayMode?.Enabled;
1450
+ const holidayModeActive = deviceData.HolidayMode?.Active;
1389
1451
 
1390
1452
  //device info
1391
1453
  const hasHeatPump = ![1, 2, 3, 4, 5, 6, 7, 15].includes(this.hideZone);
@@ -1489,6 +1551,9 @@ class DeviceAtw extends EventEmitter {
1489
1551
  temperatureUnit: TemperatureDisplayUnits[this.useFahrenheit],
1490
1552
  isInError: isInError,
1491
1553
  scheduleEnabled: scheduleEnabled,
1554
+ holidayModeEnabled: holidayModeEnabled,
1555
+ holidayModeActive: holidayModeActive,
1556
+ scheduleEnabled: scheduleEnabled,
1492
1557
  zones: [],
1493
1558
  zonesSensors: []
1494
1559
  };
@@ -1792,7 +1857,6 @@ class DeviceAtw extends EventEmitter {
1792
1857
  this.roomTemperatureSensorService?.updateCharacteristic(Characteristic.CurrentTemperature, outdoorTemperature);
1793
1858
  this.flowTemperatureSensorService?.updateCharacteristic(Characteristic.CurrentTemperature, flowTemperatureHeatPump);
1794
1859
  this.returnTemperatureSensorService?.updateCharacteristic(Characteristic.CurrentTemperature, returnTemperatureHeatPump);
1795
- this.errorService?.updateCharacteristic(Characteristic.ContactSensorState, isInError);
1796
1860
  break;
1797
1861
  case caseZone1Sensor: //Zone 1
1798
1862
  name = zone1Name;
@@ -1866,6 +1930,11 @@ class DeviceAtw extends EventEmitter {
1866
1930
  };
1867
1931
  this.accessory = obj;
1868
1932
 
1933
+ //update sensors state
1934
+ this.holidayModeControlService?.updateCharacteristic(Characteristic.ContactSensorState, holidayModeEnabled);
1935
+ this.holidayModeSensorService?.updateCharacteristic(Characteristic.ContactSensorState, holidayModeActive);
1936
+ this.errorService?.updateCharacteristic(Characteristic.ContactSensorState, isInError);
1937
+
1869
1938
  //update presets state
1870
1939
  if (this.presets.length > 0) {
1871
1940
  this.presets.forEach((preset, i) => {
@@ -1890,10 +1959,14 @@ class DeviceAtw extends EventEmitter {
1890
1959
  };
1891
1960
 
1892
1961
  //update schedules state
1893
- if (this.schedules.length > 0) {
1962
+ if (this.schedules.length > 0 && scheduleEnabled !== null) {
1894
1963
  this.schedules.forEach((schedule, i) => {
1964
+ //control
1965
+ if (i === 0) this.schedulesControlService?.updateCharacteristic(Characteristic.On, scheduleEnabled);
1966
+
1967
+ //sensors
1895
1968
  const scheduleData = schedulesOnServer.find(s => s[presetsIdKey] === schedule.id);
1896
- schedule.state = scheduleEnabled; //scheduleData.Enabled : false;
1969
+ schedule.state = scheduleEnabled ? scheduleData.Enabled ?? false : false;
1897
1970
 
1898
1971
  const characteristicType = schedule.characteristicType;
1899
1972
  this.schedulesServices?.[i]?.updateCharacteristic(characteristicType, schedule.state);
package/src/deviceerv.js CHANGED
@@ -59,8 +59,8 @@ class DeviceErv extends EventEmitter {
59
59
  //schedules configured
60
60
  for (const schedule of this.schedules) {
61
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];
62
+ schedule.serviceType = [null, Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor][schedule.displayType];
63
+ schedule.characteristicType = [null, Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState][schedule.displayType];
64
64
  schedule.state = false;
65
65
  }
66
66
 
@@ -666,6 +666,40 @@ class DeviceErv extends EventEmitter {
666
666
  accessory.addService(this.airQualitySensorService);
667
667
  }
668
668
 
669
+ //holiday mode
670
+ if (this.accessory.holidayModeEnabled !== null) {
671
+ if (this.logDebug) this.emit('debug', `Prepare holiday mode control service`);
672
+ this.holidayModeControlService = new Service.Switch(serviceName, `Holiday Mode Control ${deviceId} ${i}`);
673
+ this.holidayModeControlService.addOptionalCharacteristic(Characteristic.ConfiguredName);
674
+ this.holidayModeControlService.setCharacteristic(Characteristic.ConfiguredName, `${accessoryName} Holiday Mode Control`);
675
+ this.holidayModeControlService.getCharacteristic(Characteristic.On)
676
+ .onGet(async () => {
677
+ const state = this.accessory.holidayModeEnabled;
678
+ return state;
679
+ })
680
+ .onSet(async (state) => {
681
+ try {
682
+ deviceData.HolidayMode.Enabled = state;
683
+ await this.melCloudAta.send(this.accountType, this.displayType, deviceData, 'holidaymode');
684
+ if (this.logInfo) this.emit('info', `Holiday mode: ${state ? 'Enabled' : 'Disabled'}`);
685
+ } catch (error) {
686
+ if (this.logWarn) this.emit('warn', `Set holiday mode error: ${error}`);
687
+ };
688
+ });
689
+ accessory.addService(this.holidayModeControlService);
690
+
691
+ if (this.logDebug) this.emit('debug', `Prepare holiday mode sensor service`);
692
+ this.holidayModeSensorService = new Service.ContactSensor(`${serviceName} Holiday Mode`, `Holiday Mode Sensor ${deviceId}`);
693
+ this.holidayModeSensorService.addOptionalCharacteristic(Characteristic.ConfiguredName);
694
+ this.holidayModeSensorService.setCharacteristic(Characteristic.ConfiguredName, `${accessoryName} Holiday Mode`);
695
+ this.holidayModeSensorService.getCharacteristic(Characteristic.ContactSensorState)
696
+ .onGet(async () => {
697
+ const state = this.accessory.holidayModeActive;
698
+ return state;
699
+ })
700
+ accessory.addService(this.holidayModeSensorService);
701
+ }
702
+
669
703
  //error sensor
670
704
  if (this.errorSensor && this.accessory.isInError !== null) {
671
705
  if (this.logDebug) this.emit('debug', `Prepare error service`);
@@ -736,7 +770,7 @@ class DeviceErv extends EventEmitter {
736
770
  };
737
771
 
738
772
  //schedules services
739
- if (this.schedules.length > 0) {
773
+ if (this.schedules.length > 0 && this.accessory.scheduleEnabled !== null) {
740
774
  if (this.logDebug) this.emit('debug', `Prepare schedules services`);
741
775
  this.schedulesServices = [];
742
776
  this.schedules.forEach((schedule, i) => {
@@ -746,25 +780,52 @@ class DeviceErv extends EventEmitter {
746
780
  //get preset name prefix
747
781
  const namePrefix = schedule.namePrefix;
748
782
 
783
+ //control
784
+ if (i === 0) {
785
+ if (this.logDebug) this.emit('debug', `Prepare schedule control service`);
786
+ const serviceNameSchedule = namePrefix ? `${accessoryName} Schedule Control` : `Schedule Control`;
787
+ this.schedulesControlService = new Service.Switch(serviceNameSchedule, `Schedule Control ${deviceId} ${i}`);
788
+ this.schedulesControlService.addOptionalCharacteristic(Characteristic.ConfiguredName);
789
+ this.schedulesControlService.setCharacteristic(Characteristic.ConfiguredName, serviceNameSchedule);
790
+ this.schedulesControlService.getCharacteristic(Characteristic.On)
791
+ .onGet(async () => {
792
+ const state = this.accessory.scheduleEnabled;
793
+ return state;
794
+ })
795
+ .onSet(async (state) => {
796
+ try {
797
+ deviceData.ScheduleEnabled = state;
798
+ await this.melCloudAta.send(this.accountType, this.displayType, deviceData, 'scheduleenabled');
799
+ if (this.logInfo) this.emit('info', `Schedule: ${state ? 'Enabled' : 'Disabled'}`);
800
+ } catch (error) {
801
+ if (this.logWarn) this.emit('warn', `Set schedule error: ${error}`);
802
+ };
803
+ });
804
+ accessory.addService(this.schedulesControlService);
805
+
806
+ if (this.logDebug) this.emit('debug', `Prepare schedule control sensor service`);
807
+ this.scheduleSensorService = new Service.ContactSensor(serviceNameSchedule, `Schedule Control Sensor ${deviceId}`);
808
+ this.scheduleSensorService.addOptionalCharacteristic(Characteristic.ConfiguredName);
809
+ this.scheduleSensorService.setCharacteristic(Characteristic.ConfiguredName, serviceNameSchedule);
810
+ this.scheduleSensorService.getCharacteristic(Characteristic.ContactSensorState)
811
+ .onGet(async () => {
812
+ const state = this.accessory.scheduleEnabled;
813
+ return state;
814
+ })
815
+ accessory.addService(this.scheduleSensorService);
816
+ }
817
+
818
+ //sensors
749
819
  const serviceName = namePrefix ? `${accessoryName} ${name}` : name;
750
820
  const serviceType = schedule.serviceType;
751
821
  const characteristicType = schedule.characteristicType;
752
- const scheduleService = new serviceType(serviceName, `Schedule ${deviceId} ${i}`);
822
+ const scheduleService = new serviceType(serviceName, `Schedule Sensor ${deviceId} ${i}`);
753
823
  scheduleService.addOptionalCharacteristic(Characteristic.ConfiguredName);
754
824
  scheduleService.setCharacteristic(Characteristic.ConfiguredName, serviceName);
755
825
  scheduleService.getCharacteristic(characteristicType)
756
826
  .onGet(async () => {
757
827
  const state = schedule.state;
758
828
  return state;
759
- })
760
- .onSet(async (state) => {
761
- try {
762
- deviceData.ScheduleEnabled = state;
763
- await this.melCloudAta.send(this.accountType, this.displayType, deviceData, 'scheduleset');
764
- if (this.logInfo) this.emit('info', `${state ? 'Set:' : 'Unset:'} ${name}`);
765
- } catch (error) {
766
- if (this.logWarn) this.emit('warn', `Set schedule error: ${error}`);
767
- };
768
829
  });
769
830
  this.schedulesServices.push(scheduleService);
770
831
  accessory.addService(scheduleService);
@@ -922,7 +983,6 @@ class DeviceErv extends EventEmitter {
922
983
  this.deviceData = deviceData;
923
984
 
924
985
  //keys
925
- const presetsKey = this.accountType === 'melcloud' ? 'Presets' : 'Schedule';
926
986
  const presetsIdKey = this.accountType === 'melcloud' ? 'ID' : 'Id';
927
987
  const fanKey = this.accountType === 'melcloud' ? 'FanSpeed' : 'SetFanSpeed';
928
988
  const tempStepKey = this.accountType === 'melcloud' ? 'TemperatureIncrement' : 'HasHalfDegreeIncrements';
@@ -932,6 +992,8 @@ class DeviceErv extends EventEmitter {
932
992
  const scheduleEnabled = deviceData.ScheduleEnabled;
933
993
  const schedulesOnServer = deviceData.Schedule ?? [];
934
994
  const presetsOnServer = deviceData.Presets ?? [];
995
+ const holidayModeEnabled = deviceData.HolidayMode?.Enabled;
996
+ const holidayModeActive = deviceData.HolidayMode?.Active;
935
997
 
936
998
  //device control
937
999
  const hideRoomTemperature = deviceData.HideRoomTemperature;
@@ -1022,6 +1084,9 @@ class DeviceErv extends EventEmitter {
1022
1084
  useFahrenheit: this.useFahrenheit,
1023
1085
  temperatureUnit: TemperatureDisplayUnits[this.useFahrenheit],
1024
1086
  isInError: isInError,
1087
+ scheduleEnabled: scheduleEnabled,
1088
+ holidayModeEnabled: holidayModeEnabled,
1089
+ holidayModeActive: holidayModeActive,
1025
1090
  scheduleEnabled: scheduleEnabled
1026
1091
  };
1027
1092
 
@@ -1160,6 +1225,8 @@ class DeviceErv extends EventEmitter {
1160
1225
  .updateCharacteristic(Characteristic.PM2_5Density, pM25Level);
1161
1226
 
1162
1227
  //error sensor
1228
+ this.holidayModeControlService?.updateCharacteristic(Characteristic.ContactSensorState, holidayModeEnabled);
1229
+ this.holidayModeSensorService?.updateCharacteristic(Characteristic.ContactSensorState, holidayModeActive);
1163
1230
  this.errorService?.updateCharacteristic(Characteristic.ContactSensorState, isInError);
1164
1231
 
1165
1232
  //update presets state
@@ -1179,10 +1246,14 @@ class DeviceErv extends EventEmitter {
1179
1246
  };
1180
1247
 
1181
1248
  //update schedules state
1182
- if (this.schedules.length > 0) {
1249
+ if (this.schedules.length > 0 && scheduleEnabled !== null) {
1183
1250
  this.schedules.forEach((schedule, i) => {
1251
+ //control
1252
+ if (i === 0) this.schedulesControlService?.updateCharacteristic(Characteristic.On, scheduleEnabled);
1253
+
1254
+ //sensors
1184
1255
  const scheduleData = schedulesOnServer.find(s => s[presetsIdKey] === schedule.id);
1185
- schedule.state = scheduleEnabled; //scheduleData.Enabled : false;
1256
+ schedule.state = scheduleEnabled ? scheduleData.Enabled ?? false : false;
1186
1257
 
1187
1258
  const characteristicType = schedule.characteristicType;
1188
1259
  this.schedulesServices?.[i]?.updateCharacteristic(characteristicType, schedule.state);
package/src/melcloud.js CHANGED
@@ -168,7 +168,7 @@ class MelCloud extends EventEmitter {
168
168
  const loginData = account.LoginData ?? [];
169
169
  const contextKey = loginData.ContextKey;
170
170
 
171
- const debugData = {
171
+ const safeConfig = {
172
172
  ...loginData,
173
173
  ContextKey: 'removed',
174
174
  ClientId: 'removed',
@@ -177,7 +177,7 @@ class MelCloud extends EventEmitter {
177
177
  MapLongitude: 'removed',
178
178
  MapLatitude: 'removed'
179
179
  };
180
- if (this.logDebug) this.emit('debug', `MELCloud Info: ${JSON.stringify(debugData, null, 2)}`);
180
+ if (this.logDebug) this.emit('debug', `MELCloud Info: ${JSON.stringify(safeConfig, null, 2)}`);
181
181
 
182
182
  if (!contextKey) {
183
183
  accountInfo.Info = 'Context key missing'
@@ -203,19 +203,33 @@ class MelCloudAta extends EventEmitter {
203
203
  }
204
204
  }
205
205
 
206
- const settings = effectiveFlags === 'scheduleset' ? { data: { enabled: deviceData.ScheduleEnabled } } : {
207
- data: {
208
- Power: deviceData.Device.Power,
209
- SetTemperature: deviceData.Device.SetTemperature,
210
- SetFanSpeed: String(deviceData.Device.SetFanSpeed),
211
- OperationMode: AirConditioner.OperationModeMapEnumToString[deviceData.Device.OperationMode],
212
- VaneHorizontalDirection: AirConditioner.VaneHorizontalDirectionMapEnumToString[deviceData.Device.VaneHorizontalDirection],
213
- VaneVerticalDirection: AirConditioner.VaneVerticalDirectionMapEnumToString[deviceData.Device.VaneVerticalDirection],
214
- }
215
- };
216
- if (this.logDebug) this.emit('debug', `Send Data: ${JSON.stringify(settings.data, null, 2)}`);
206
+ let settings = {};
207
+ let path = '';
208
+ switch (effectiveFlags) {
209
+ case 'scheduleenabled':
210
+ settings = {
211
+ data: {
212
+ enabled: deviceData.ScheduleEnabled
213
+ }
214
+ };
215
+ path = ApiUrlsHome.PutScheduleEnable.replace('deviceid', deviceData.DeviceID);
216
+ break;
217
+ default:
218
+ settings = {
219
+ data: {
220
+ Power: deviceData.Device.Power,
221
+ SetTemperature: deviceData.Device.SetTemperature,
222
+ SetFanSpeed: String(deviceData.Device.SetFanSpeed),
223
+ OperationMode: AirConditioner.OperationModeMapEnumToString[deviceData.Device.OperationMode],
224
+ VaneHorizontalDirection: AirConditioner.VaneHorizontalDirectionMapEnumToString[deviceData.Device.VaneHorizontalDirection],
225
+ VaneVerticalDirection: AirConditioner.VaneVerticalDirectionMapEnumToString[deviceData.Device.VaneVerticalDirection],
226
+ }
227
+ };
228
+ path = ApiUrlsHome.SetAta.replace('deviceid', deviceData.DeviceID);
229
+ break
230
+ }
217
231
 
218
- const path = effectiveFlags === 'scheduleset' ? ApiUrlsHome.SetSchedule.replace('deviceid', deviceData.DeviceID) : ApiUrlsHome.SetAta.replace('deviceid', deviceData.DeviceID);
232
+ if (this.logDebug) this.emit('debug', `Send Data: ${JSON.stringify(settings.data, null, 2)}`);
219
233
  await axiosInstancePut(path, settings);
220
234
  this.updateData(deviceData);
221
235
  return true;
@@ -223,11 +237,7 @@ class MelCloudAta extends EventEmitter {
223
237
  return;
224
238
  }
225
239
  } catch (error) {
226
- // Return 500 for schedule hovewer working correct
227
- if (error?.response?.status === 500) {
228
- return true;
229
- }
230
-
240
+ if (error.response?.status === 500) return true; // Return 500 for schedule hovewer working correct
231
241
  throw new Error(`Send data error: ${error.message}`);
232
242
  }
233
243
  }
@@ -195,26 +195,40 @@ class MelCloudAtw extends EventEmitter {
195
195
  withCredentials: true
196
196
  });
197
197
 
198
- const settings = effectiveFlags === 'scheduleset' ? { data: { enabled: deviceData.ScheduleEnabled } } : {
199
- data: {
200
- Power: deviceData.Device.Power,
201
- SetTemperatureZone1: deviceData.Device.SetTemperatureZone1,
202
- SetTemperatureZone2: deviceData.Device.SetTemperatureZone2,
203
- OperationMode: HeatPump.OperationModeMapEnumToString[deviceData.Device.OperationMode],
204
- OperationModeZone1: HeatPump.OperationModeMapEnumToString[deviceData.Device.OperationModeZone1],
205
- OperationModeZone2: HeatPump.OperationModeMapEnumToString[deviceData.Device.OperationModeZone2],
206
- SetHeatFlowTemperatureZone1: deviceData.Device.SetHeatFlowTemperatureZone1,
207
- SetHeatFlowTemperatureZone2: deviceData.Device.SetHeatFlowTemperatureZone2,
208
- SetCoolFlowTemperatureZone1: deviceData.Device.SetCoolFlowTemperatureZone1,
209
- SetCoolFlowTemperatureZone2: deviceData.Device.SetCoolFlowTemperatureZone2,
210
- SetTankWaterTemperature: deviceData.Device.SetTankWaterTemperature,
211
- ForcedHotWaterMode: deviceData.Device.ForcedHotWaterMode,
212
- EcoHotWater: deviceData.Device.EcoHotWater,
213
- }
214
- };
215
- if (this.logDebug) this.emit('debug', `Send Data: ${JSON.stringify(settings.data, null, 2)}`);
198
+ let settings = {};
199
+ let path = '';
200
+ switch (effectiveFlags) {
201
+ case 'scheduleenabled':
202
+ settings = {
203
+ data: {
204
+ enabled: deviceData.ScheduleEnabled
205
+ }
206
+ };
207
+ path = ApiUrlsHome.PutScheduleEnable.replace('deviceid', deviceData.DeviceID);
208
+ break;
209
+ default:
210
+ settings = {
211
+ data: {
212
+ Power: deviceData.Device.Power,
213
+ SetTemperatureZone1: deviceData.Device.SetTemperatureZone1,
214
+ SetTemperatureZone2: deviceData.Device.SetTemperatureZone2,
215
+ OperationMode: HeatPump.OperationModeMapEnumToString[deviceData.Device.OperationMode],
216
+ OperationModeZone1: HeatPump.OperationModeMapEnumToString[deviceData.Device.OperationModeZone1],
217
+ OperationModeZone2: HeatPump.OperationModeMapEnumToString[deviceData.Device.OperationModeZone2],
218
+ SetHeatFlowTemperatureZone1: deviceData.Device.SetHeatFlowTemperatureZone1,
219
+ SetHeatFlowTemperatureZone2: deviceData.Device.SetHeatFlowTemperatureZone2,
220
+ SetCoolFlowTemperatureZone1: deviceData.Device.SetCoolFlowTemperatureZone1,
221
+ SetCoolFlowTemperatureZone2: deviceData.Device.SetCoolFlowTemperatureZone2,
222
+ SetTankWaterTemperature: deviceData.Device.SetTankWaterTemperature,
223
+ ForcedHotWaterMode: deviceData.Device.ForcedHotWaterMode,
224
+ EcoHotWater: deviceData.Device.EcoHotWater,
225
+ }
226
+ };
227
+ path = ApiUrlsHome.SetAtw.replace('deviceid', deviceData.DeviceID);
228
+ break
229
+ }
216
230
 
217
- const path = effectiveFlags === 'scheduleset' ? ApiUrlsHome.SetSchedule.replace('deviceid', deviceData.DeviceID) : ApiUrlsHome.SetAtw.replace('deviceid', deviceData.DeviceID);
231
+ if (this.logDebug) this.emit('debug', `Send Data: ${JSON.stringify(settings.data, null, 2)}`);
218
232
  await axiosInstancePut(path, settings);
219
233
  this.updateData(deviceData);
220
234
  return true;
@@ -222,11 +236,7 @@ class MelCloudAtw extends EventEmitter {
222
236
  return;
223
237
  }
224
238
  } catch (error) {
225
- // Return 500 for schedule hovewer working correct
226
- if (error?.response?.status === 500) {
227
- return true;
228
- }
229
-
239
+ if (error.response?.status === 500) return true; // Return 500 for schedule hovewer working correct
230
240
  throw new Error(`Send data error: ${error.message}`);
231
241
  }
232
242
  }
@@ -211,18 +211,32 @@ class MelCloudErv extends EventEmitter {
211
211
  }
212
212
  }
213
213
 
214
- const settings = effectiveFlags === 'scheduleset' ? { data: { enabled: deviceData.ScheduleEnabled } } : {
215
- data: {
216
- Power: deviceData.Device.Power,
217
- SetTemperature: deviceData.Device.SetTemperature,
218
- SetFanSpeed: String(deviceData.Device.SetFanSpeed),
219
- OperationMode: Ventilation.OperationModeMapEnumToString[deviceData.Device.OperationMode],
220
- VentilationMode: Ventilation.VentilationModeMapEnumToString[deviceData.Device.VentilationMode],
221
- }
222
- };
223
- if (this.logDebug) this.emit('debug', `Send Data: ${JSON.stringify(settings.data, null, 2)}`);
214
+ let settings = {};
215
+ let path = '';
216
+ switch (effectiveFlags) {
217
+ case 'scheduleenabled':
218
+ settings = {
219
+ data: {
220
+ enabled: deviceData.ScheduleEnabled
221
+ }
222
+ };
223
+ path = ApiUrlsHome.PutScheduleEnable.replace('deviceid', deviceData.DeviceID);
224
+ break;
225
+ default:
226
+ settings = {
227
+ data: {
228
+ Power: deviceData.Device.Power,
229
+ SetTemperature: deviceData.Device.SetTemperature,
230
+ SetFanSpeed: String(deviceData.Device.SetFanSpeed),
231
+ OperationMode: Ventilation.OperationModeMapEnumToString[deviceData.Device.OperationMode],
232
+ VentilationMode: Ventilation.VentilationModeMapEnumToString[deviceData.Device.VentilationMode],
233
+ }
234
+ };
235
+ path = ApiUrlsHome.SetErv.replace('deviceid', deviceData.DeviceID);
236
+ break
237
+ }
224
238
 
225
- const path = effectiveFlags === 'scheduleset' ? ApiUrlsHome.SetSchedule.replace('deviceid', deviceData.DeviceID) : ApiUrlsHome.SetErv.replace('deviceid', deviceData.DeviceID);
239
+ if (this.logDebug) this.emit('debug', `Send Data: ${JSON.stringify(settings.data, null, 2)}`);
226
240
  await axiosInstancePut(path, settings);
227
241
  this.updateData(deviceData);
228
242
  return true;
@@ -230,11 +244,7 @@ class MelCloudErv extends EventEmitter {
230
244
  return;
231
245
  }
232
246
  } catch (error) {
233
- // Return 500 for schedule hovewer working correct
234
- if (error?.response?.status === 500) {
235
- return true;
236
- }
237
-
247
+ if (error.response?.status === 500) return true; // Return 500 for schedule hovewer working correct
238
248
  throw new Error(`Send data error: ${error.message}`);
239
249
  }
240
250
  }