homebridge-melcloud-control 4.7.0 → 4.7.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 CHANGED
@@ -24,7 +24,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
24
24
  - For plugin < v4.6.0 use Homebridge UI <= v5.5.0
25
25
  - For plugin >= v4.6.0 use Homebridge UI >= v5.13.0
26
26
 
27
- # [4.7.0] - (xx.01.2026)
27
+ # [4.7.2] - (29.01.2026)
28
+
29
+ ## Changes
30
+
31
+ - fix zone2 for ATW devices
32
+ - constants updated
33
+ - log info updated
34
+ - bump dependencies
35
+ - cleanup
36
+
37
+ # [4.7.1] - (27.01.2026)
38
+
39
+ ## Changes
40
+
41
+ - add falback to power for unit status in melcloud home
42
+ - constants updated
43
+ - cleanup
44
+
45
+ # [4.7.0] - (27.01.2026)
28
46
 
29
47
  ## Changes
30
48
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "displayName": "MELCloud Control",
3
3
  "name": "homebridge-melcloud-control",
4
- "version": "4.7.0",
4
+ "version": "4.7.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",
@@ -37,9 +37,9 @@
37
37
  "dependencies": {
38
38
  "@homebridge/plugin-ui-utils": "^2.1.2",
39
39
  "mqtt": "^5.14.1",
40
- "axios": "^1.13.3",
40
+ "axios": "^1.13.4",
41
41
  "express": "^5.2.1",
42
- "puppeteer": "^24.36.0",
42
+ "puppeteer": "^24.36.1",
43
43
  "ws": "^8.19.0"
44
44
  },
45
45
  "keywords": [
package/src/constants.js CHANGED
@@ -65,7 +65,7 @@ export const DeviceType = {
65
65
  };
66
66
 
67
67
  export const AirConditioner = {
68
- SystemMapEnumToString: { 0: "Air Conditioner Off", 1: "Air Conditioner On", 2: "Air Conditioner Offline" },
68
+ SystemMapEnumToStringInfo: { 0: "Air Conditioner Off", 1: "Air Conditioner On", 2: "Air Conditioner Offline" },
69
69
  OperationModeMapStringToEnum: { "0": 0, "Heat": 1, "Dry": 2, "Cool": 3, "4": 4, "5": 5, "6": 6, "Fan": 7, "Automatic": 8, "Heat Isee": 9, "Dry Isee": 10, "Cool Isee": 11 },
70
70
  OperationModeMapEnumToString: { 0: "0", 1: "Heat", 2: "Dry", 3: "Cool", 4: "4", 5: "5", 6: "6", 7: "Fan", 8: "Automatic", 9: "Heat Isee", 10: "Dry Isee", 11: "Cool Isee" },
71
71
  OperationModeMapEnumToEnumWs: { 0: 0, 1: 1, 2: 2, 3: 3, 4: 7, 5: 8 },
@@ -107,22 +107,24 @@ export const AirConditioner = {
107
107
  };
108
108
 
109
109
  export const HeatPump = {
110
- SystemMapEnumToString: { 0: "SystemOff", 1: "SystemOn", 2: "Emergency Run", 3: "Test Run" },
111
110
  ZoneNameMapEnumToString: { 0: "Heat Pump", 1: "Zone 1", 2: "Hot Water", 3: "Zone 2" },
111
+ SystemMapEnumToStringInfo: { 0: "System Off", 1: "System On", 2: "Emergency Run", 3: "Test Run" },
112
112
  ControlTypeMapStringToEnum: { "Heat": 0, "Cool": 1 },
113
113
  ControlTypeMapEnumToString: { 0: "Heat", 1: "Cool" },
114
114
  DefrostMapStringToEnum: { "Normal": 0, "Standby": 1, "Defrost": 2, "Waiting Restart": 3 },
115
115
  DefrostMapEnumToString: { 0: "Normal", 1: "Standby", 2: "Defrost", 3: "Waiting Restart" },
116
116
  OperationModeMapStringToEnum: { "Idle": 0, "HotWater": 1, "Heating": 2, "Cooling": 3, "HotWaterStorage": 4, "FreezeStat": 5, "Legionella": 6, "HeatEco": 7, "Mode1": 8, "Mode2": 9, "Mode3": 10, "HeatUp": 11 },
117
117
  OperationModeMapEnumToString: { 0: "Idle", 1: "HotWater", 2: "Heating", 3: "Cooling", 4: "HotWaterStorage", 5: "FreezeStat", 6: "Legionella", 7: "HeatEco", 8: "Mode1", 9: "Mode2", 10: "Mode3", 11: "HeatUp" },
118
+ OperationModeMapEnumToStringInfo: { 0: "Idle", 1: "Hot Water", 2: "Heating", 3: "Cooling", 4: "Hot Water Storage", 5: "Freeze Stat", 6: "Legionella", 7: "Heat Eco", 8: "Mode 1", 9: "Mode 2", 10: "Mode 3", 11: "Heat Up" },
118
119
  OperationModeDhwMapStringToEnum: { "Normal": 0, "Eco": 1 },
119
120
  OperationModeDhwMapEnumToString: { 0: "Normal", 1: "Eco" },
120
121
  ForceDhwMapStringToEnum: { "Normal": 0, "HeatNow": 1 },
121
122
  ForceDhwMapEnumToString: { 0: "Normal", 1: "HeatNow" },
122
123
  HolidayMapStringToEnum: { "Normal": 0, "Holiday": 1 },
123
124
  HolidayMapEnumToString: { 0: "Normal", 1: "Holiday" },
124
- OperationModeZoneMapStringToEnum: { "HeatThermostat": 0, "HeatFlowTemperature": 1, "HeatCurve": 2, "CoolThermostat": 3, "CoolFlowTemperature": 4, "FlorDryUp": 5, "Idle": 6 },
125
- OperationModeZoneMapEnumToString: { 0: "HeatThermostat", 1: "HeatFlowTemperature", 2: "Heat Curve", 3: "CoolThermostat", 4: "CoolFlowTemperature", 5: "FlorDryUp", 6: "Idle" },
125
+ OperationModeZoneMapStringToEnum: { "HeatThermostat": 0, "HeatFlowTemperature": 1, "HeatCurve": 2, "CoolThermostat": 3, "CoolFlowTemperature": 4, "FloorDryUp": 5, "Idle": 6 },
126
+ OperationModeZoneMapEnumToString: { 0: "HeatThermostat", 1: "HeatFlowTemperature", 2: "HeatCurve", 3: "CoolThermostat", 4: "CoolFlowTemperature", 5: "FloorDryUp", 6: "Idle" },
127
+ OperationModeZoneMapEnumToStringInfo: { 0: "Heat Thermostat", 1: "Heat Flow Temperature", 2: "Heat Curve", 3: "Cool Thermostat", 4: "Cool Flow Temperature", 5: "Floor Dry Up", 6: "Idle" },
126
128
  EffectiveFlags: {
127
129
  Power: 1,
128
130
  OperationMode: 2,
package/src/deviceatw.js CHANGED
@@ -398,7 +398,7 @@ class DeviceAtw extends EventEmitter {
398
398
  flag = HeatPump.EffectiveFlags.Power + HeatPump.EffectiveFlags.OperationMode;
399
399
  break;
400
400
  };
401
- operationModeText = [HeatPump.SystemMapEnumToString[0], HeatPump.SystemMapEnumToString[deviceData.Device.UnitStatus]][this.accessory.power];
401
+ operationModeText = [HeatPump.SystemMapEnumToStringInfo[0], HeatPump.SystemMapEnumToStringInfo[deviceData.Device.UnitStatus]][this.accessory.power];
402
402
  break;
403
403
  case caseZone1: //Zone 1 - HEAT THERMOSTAT, HEAT FLOW, HEAT CURVE, COOL THERMOSTAT, COOL FLOW, FLOOR DRY UP
404
404
  switch (value) {
@@ -415,7 +415,7 @@ class DeviceAtw extends EventEmitter {
415
415
  flag = HeatPump.EffectiveFlags.OperationModeZone1;
416
416
  break;
417
417
  };
418
- operationModeText = HeatPump.ZoneOperation[deviceData.Device.OperationModeZone1];
418
+ operationModeText = HeatPump.OperationModeMapEnumToStringInfo[deviceData.Device.OperationModeZone1];
419
419
  break;
420
420
  case caseHotWater: //Hot Water - AUTO, HEAT NOW
421
421
  switch (value) {
@@ -449,7 +449,7 @@ class DeviceAtw extends EventEmitter {
449
449
  flag = HeatPump.EffectiveFlags.OperationModeZone2;
450
450
  break;
451
451
  };
452
- operationModeText = HeatPump.ZoneOperationMapEnumToString[deviceData.Device.OperationModeZone2];
452
+ operationModeText = HeatPump.OperationModeMapEnumToStringInfo[deviceData.Device.OperationModeZone2];
453
453
  break;
454
454
  };
455
455
 
@@ -696,7 +696,7 @@ class DeviceAtw extends EventEmitter {
696
696
  flag = HeatPump.EffectiveFlags.Power;
697
697
  break;
698
698
  };
699
- operationModeText = [HeatPump.SystemMapEnumToString[0], HeatPump.SystemMapEnumToString[deviceData.Device.UnitStatus]][this.accessory.power];
699
+ operationModeText = [HeatPump.SystemMapEnumToStringInfo[0], HeatPump.SystemMapEnumToStringInfo[deviceData.Device.UnitStatus]][this.accessory.power];
700
700
  break;
701
701
  case caseZone1: //Zone 1 - HEAT THERMOSTAT, HEAT FLOW, HEAT CURVE, COOL THERMOSTAT, COOL FLOW, FLOOR DRY UP
702
702
  switch (value) {
@@ -717,7 +717,7 @@ class DeviceAtw extends EventEmitter {
717
717
  flag = HeatPump.EffectiveFlags.OperationModeZone1;
718
718
  break;
719
719
  };
720
- operationModeText = HeatPump.ZoneOperationMapEnumToString[deviceData.Device.OperationModeZone1];
720
+ operationModeText = HeatPump.OperationModeMapEnumToStringInfo[deviceData.Device.OperationModeZone1];
721
721
  break;
722
722
  case caseHotWater: //Hot Water - AUTO, HEAT NOW
723
723
  switch (value) {
@@ -759,7 +759,7 @@ class DeviceAtw extends EventEmitter {
759
759
  flag = HeatPump.EffectiveFlags.OperationModeZone2;
760
760
  break;
761
761
  };
762
- operationModeText = HeatPump.ZoneOperationMapEnumToString[deviceData.Device.OperationModeZone2];
762
+ operationModeText = HeatPump.OperationModeMapEnumToStringInfo[deviceData.Device.OperationModeZone2];
763
763
  break;
764
764
  };
765
765
 
@@ -1686,7 +1686,7 @@ class DeviceAtw extends EventEmitter {
1686
1686
  const supportsHeatPump = ![1, 2, 3, 4, 5, 6, 7, 15].includes(this.hideZone);
1687
1687
  const supportsZone1 = ![2, 3, 4, 8, 9, 10, 11, 15].includes(this.hideZone);
1688
1688
  const supportsHotWaterTank = ![3, 5, 6, 9, 10, 12, 13, 15].includes(this.hideZone) && deviceData.Device[supportHotWaterKey];
1689
- const supportsZone2 = ![4, 6, 7, 10, 11, 13, 14, 15].includes(this.hideZone) && deviceData.Device.HasZone2;
1689
+ const supportsZone2 = ![4, 6, 7, 10, 11, 13, 14, 15].includes(this.hideZone) && deviceData.Device.HasZone2 !== false && deviceData.Device.HasZone2 !== null;
1690
1690
  const canHeat = deviceData.Device[supportHeatKey] ?? true;
1691
1691
  const canCool = deviceData.Device[supportCoolKey] ?? false;
1692
1692
  const heatCoolModes = canHeat && canCool ? 0 : canHeat ? 1 : canCool ? 2 : 3;
@@ -1709,14 +1709,14 @@ class DeviceAtw extends EventEmitter {
1709
1709
  const caseHeatPumpSensor = this.temperatureSensor || this.temperatureFlowSensor || this.temperatureReturnSensor ? currentZoneSensorCase++ : -1;
1710
1710
  const caseZone1Sensor = this.temperatureFlowZone1Sensor || this.temperatureReturnZone1Sensor ? currentZoneSensorCase++ : -1;
1711
1711
  const caseHotWaterSensor = (this.temperatureFlowWaterTankSensor || this.temperatureReturnWaterTankSensor) && deviceData.Device.HasHotWaterTank ? currentZoneSensorCase++ : -1;
1712
- const caseZone2Sensor = (this.temperatureFlowZone2Sensor || this.temperatureReturnZone2Sensor) && deviceData.Device.HasZone2 ? currentZoneSensorCase++ : -1;
1712
+ const caseZone2Sensor = (this.temperatureFlowZone2Sensor || this.temperatureReturnZone2Sensor) && deviceData.Device.HasZone2 !== false && deviceData.Device.HasZone2 !== null ? currentZoneSensorCase++ : -1;
1713
1713
  const zonesSensorsCount = currentZoneSensorCase;
1714
1714
 
1715
1715
  //heat pump
1716
1716
  const heatPumpName = 'Heat Pump';
1717
1717
  const power = deviceData.Device.Power;
1718
1718
  const inStandbyMode = deviceData.Device.InStandbyMode;
1719
- const unitStatus = deviceData.Device.UnitStatus ?? 0;
1719
+ const unitStatus = deviceData.Device.UnitStatus ?? power; // fallback to power melcloud home
1720
1720
  const operationMode = deviceData.Device.OperationMode;
1721
1721
  const outdoorTemperature = deviceData.Device.OutdoorTemperature ?? deviceData.Device.RoomTemperatureZone1; // fallback to room temperature zone 1 melcloud home
1722
1722
  const flowTemperatureHeatPump = deviceData.Device.FlowTemperature ?? null; // only sensor
@@ -2061,36 +2061,37 @@ class DeviceAtw extends EventEmitter {
2061
2061
  let operationModeText = '';
2062
2062
  switch (i) {
2063
2063
  case caseHeatPump: //Heat Pump - HEAT, COOL, OFF
2064
- this.emit('info', `Power: ${power ? 'On' : 'Off'}`)
2065
- this.emit('info', `Operation mode: ${HeatPump.SystemMapEnumToString[unitStatus]}`);
2066
- this.emit('info', `Outdoor temperature: ${roomTemperature}${obj.temperatureUnit}`);
2067
- this.emit('info', `Temperature display unit: ${obj.temperatureUnit}`);
2068
- this.emit('info', `Lock physical controls: ${lockPhysicalControl ? 'Locked' : 'Unlocked'}`);
2064
+ this.emit('info', `${name} Power: ${power ? 'On' : 'Off'}`)
2065
+ this.emit('info', `${name} System status: ${HeatPump.SystemMapEnumToStringInfo[unitStatus]}`);
2066
+ this.emit('info', `${name} Operation mode: ${HeatPump.OperationModeMapEnumToStringInfo[operationMode]}`);
2067
+ this.emit('info', `${name} Outdoor temperature: ${roomTemperature}${obj.temperatureUnit}`);
2068
+ this.emit('info', `${name} Temperature display unit: ${obj.temperatureUnit}`);
2069
+ this.emit('info', `${name} Lock physical controls: ${lockPhysicalControl ? 'Locked' : 'Unlocked'}`);
2069
2070
  if (this.accountType === 'melcloudhome') this.emit('info', `Signal strength: ${deviceData.Rssi}dBm`);
2070
2071
  break;
2071
2072
  case caseZone1: //Zone 1 - HEAT THERMOSTAT, HEAT FLOW, HEAT CURVE, COOL THERMOSTAT, COOL FLOW, FLOOR DRY UP
2072
- operationModeText = idleZone1 ? HeatPump.OperationModeZoneMapEnumToString[6] : HeatPump.OperationModeZoneMapEnumToString[operationModeZone1];
2073
- this.emit('info', `Operation mode: ${operationModeText}`);
2074
- this.emit('info', `Temperature: ${roomTemperature}${obj.temperatureUnit}`);
2075
- this.emit('info', `Target temperature: ${setTemperature}${obj.temperatureUnit}`)
2076
- this.emit('info', `Temperature display unit: ${obj.temperatureUnit}`);
2077
- this.emit('info', `Lock physical controls: ${lockPhysicalControl ? 'Locked' : 'Unlocked'}`);
2073
+ operationModeText = idleZone1 ? HeatPump.OperationModeZoneMapEnumToStringInfo[6] : HeatPump.OperationModeZoneMapEnumToStringInfo[operationModeZone1];
2074
+ this.emit('info', `${name} Operation mode: ${operationModeText}`);
2075
+ this.emit('info', `${name} Temperature: ${roomTemperature}${obj.temperatureUnit}`);
2076
+ this.emit('info', `${name} Target temperature: ${setTemperature}${obj.temperatureUnit}`)
2077
+ this.emit('info', `${name} Temperature display unit: ${obj.temperatureUnit}`);
2078
+ this.emit('info', `${name} Lock physical controls: ${lockPhysicalControl ? 'Locked' : 'Unlocked'}`);
2078
2079
  break;
2079
2080
  case caseHotWater: //Hot Water - AUTO, HEAT NOW
2080
2081
  operationModeText = operationMode === 1 ? HeatPump.ForceDhwMapEnumToString[1] : HeatPump.ForceDhwMapEnumToString[forcedHotWaterMode ? 1 : 0];
2081
- this.emit('info', `Operation mode: ${operationModeText}`);
2082
- this.emit('info', `Temperature: ${roomTemperature}${obj.temperatureUnit}`);
2083
- this.emit('info', `Target temperature: ${setTemperature}${obj.temperatureUnit}`)
2084
- this.emit('info', `Temperature display unit: ${obj.temperatureUnit}`);
2085
- this.emit('info', `Lock physical controls: ${lockPhysicalControl ? 'Locked' : 'Unlocked'}`);
2082
+ this.emit('info', `${name} Operation mode: ${operationModeText}`);
2083
+ this.emit('info', `${name} Temperature: ${roomTemperature}${obj.temperatureUnit}`);
2084
+ this.emit('info', `${name} Target temperature: ${setTemperature}${obj.temperatureUnit}`)
2085
+ this.emit('info', `${name} Temperature display unit: ${obj.temperatureUnit}`);
2086
+ this.emit('info', `${name} Lock physical controls: ${lockPhysicalControl ? 'Locked' : 'Unlocked'}`);
2086
2087
  break;
2087
2088
  case caseZone2: //Zone 2 - HEAT THERMOSTAT, HEAT FLOW, HEAT CURVE, COOL THERMOSTAT, COOL FLOW, FLOOR DRY UP
2088
- operationModeText = idleZone2 ? HeatPump.OperationModeZoneMapEnumToString[6] : HeatPump.OperationModeZoneMapEnumToString[operationModeZone2];
2089
- this.emit('info', `Operation mode: ${operationModeText}`);
2090
- this.emit('info', `Temperature: ${roomTemperature}${obj.temperatureUnit}`);
2091
- this.emit('info', `Target temperature: ${setTemperature}${obj.temperatureUnit}`)
2092
- this.emit('info', `Temperature display unit: ${obj.temperatureUnit}`);
2093
- this.emit('info', `Lock physical controls: ${lockPhysicalControl ? 'Locked' : 'Unlocked'}`);
2089
+ operationModeText = idleZone2 ? HeatPump.OperationModeZoneMapEnumToStringInfo[6] : HeatPump.OperationModeZoneMapEnumToStringInfo[operationModeZone2];
2090
+ this.emit('info', `${name} Operation mode: ${operationModeText}`);
2091
+ this.emit('info', `${name} Temperature: ${roomTemperature}${obj.temperatureUnit}`);
2092
+ this.emit('info', `${name} Target temperature: ${setTemperature}${obj.temperatureUnit}`)
2093
+ this.emit('info', `${name} Temperature display unit: ${obj.temperatureUnit}`);
2094
+ this.emit('info', `${name} Lock physical controls: ${lockPhysicalControl ? 'Locked' : 'Unlocked'}`);
2094
2095
  break;
2095
2096
  };
2096
2097
  }
@@ -130,7 +130,7 @@ class MelCloudAtw extends EventEmitter {
130
130
  const serialNumber = deviceData.SerialNumber || '4.0.0';
131
131
  const firmwareAppVersion = deviceData.Device?.FirmwareAppVersion || '4.0.0';
132
132
  const hasHotWaterTank = deviceData.Device?.HasHotWaterTank || false;
133
- const hasZone2 = deviceData.Device?.HasZone2 || false;
133
+ const hasZone2 = deviceData.Device.HasZone2 !== false && deviceData.Device.HasZone2 !== null;
134
134
 
135
135
  //units
136
136
  const units = Array.isArray(deviceData.Device?.Units) ? deviceData.Device?.Units : [];