homebridge-melcloud-control 4.3.2-beta.2 → 4.3.2-beta.21

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "displayName": "MELCloud Control",
3
3
  "name": "homebridge-melcloud-control",
4
- "version": "4.3.2-beta.2",
4
+ "version": "4.3.2-beta.21",
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
@@ -649,7 +649,7 @@ class DeviceAta extends EventEmitter {
649
649
  return state;
650
650
  })
651
651
  accessory.addService(this.roomTemperatureSensorService);
652
- };
652
+ }
653
653
 
654
654
  if (this.temperatureOutdoorSensor && supportsOutdoorTemperature && this.accessory.outdoorTemperature !== null) {
655
655
  if (this.logDebug) this.emit('debug', `Prepare outdoor temperature sensor service`);
@@ -662,7 +662,7 @@ class DeviceAta extends EventEmitter {
662
662
  return state;
663
663
  })
664
664
  accessory.addService(this.outdoorTemperatureSensorService);
665
- };
665
+ }
666
666
 
667
667
  //in standby sensor
668
668
  if (this.inStandbySensor && this.accessory.inStandbyMode !== null) {
@@ -922,7 +922,7 @@ class DeviceAta extends EventEmitter {
922
922
  accessory.addService(presetControlSensorService);
923
923
  }
924
924
  });
925
- };
925
+ }
926
926
 
927
927
  //schedules services
928
928
  if (this.schedules.length > 0 && this.accessory.scheduleEnabled !== null) {
@@ -996,7 +996,7 @@ class DeviceAta extends EventEmitter {
996
996
  accessory.addService(scheduleSensorService);
997
997
  }
998
998
  });
999
- };
999
+ }
1000
1000
 
1001
1001
  //scenes
1002
1002
  if (this.scenes.length > 0) {
@@ -1055,7 +1055,7 @@ class DeviceAta extends EventEmitter {
1055
1055
  accessory.addService(sceneControlSensorService);
1056
1056
  }
1057
1057
  });
1058
- };
1058
+ }
1059
1059
 
1060
1060
  //buttons services
1061
1061
  if (this.buttons.length > 0) {
@@ -1318,7 +1318,7 @@ class DeviceAta extends EventEmitter {
1318
1318
  accessory.addService(buttonControlSensorService);
1319
1319
  }
1320
1320
  });
1321
- };
1321
+ }
1322
1322
 
1323
1323
  return accessory;
1324
1324
  } catch (error) {
@@ -1690,7 +1690,7 @@ class DeviceAta extends EventEmitter {
1690
1690
  //sensor
1691
1691
  if (preset.displayType < 7) this.presetControlSensorServices?.[i]?.updateCharacteristic(characteristicType, preset.state);
1692
1692
  });
1693
- };
1693
+ }
1694
1694
 
1695
1695
  ///schedules
1696
1696
  if (this.schedules.length > 0 && scheduleEnabled !== null) {
@@ -1710,7 +1710,7 @@ class DeviceAta extends EventEmitter {
1710
1710
  //sensor
1711
1711
  if (schedule.displayType < 7) this.scheduleSensorServices?.[i]?.updateCharacteristic(characteristicType, schedule.state);
1712
1712
  });
1713
- };
1713
+ }
1714
1714
 
1715
1715
  //scenes
1716
1716
  if (this.scenes.length > 0) {
@@ -1727,7 +1727,7 @@ class DeviceAta extends EventEmitter {
1727
1727
  //sensor
1728
1728
  if (scene.displayType < 7) this.sceneControlSensorServices?.[i]?.updateCharacteristic(characteristicType, scene.state);
1729
1729
  });
1730
- };
1730
+ }
1731
1731
 
1732
1732
  //buttons
1733
1733
  if (this.buttons.length > 0) {
@@ -1851,7 +1851,7 @@ class DeviceAta extends EventEmitter {
1851
1851
  //sensor
1852
1852
  if (button.displayType < 7) this.buttonControlSensorServices?.[i]?.updateCharacteristic(characteristicType, button.state);
1853
1853
  });
1854
- };
1854
+ }
1855
1855
 
1856
1856
  //log current state
1857
1857
  if (this.logInfo) {
@@ -1869,7 +1869,7 @@ class DeviceAta extends EventEmitter {
1869
1869
  this.emit('info', `Temperature display unit: ${obj.temperatureUnit}`);
1870
1870
  this.emit('info', `Lock physical controls: ${obj.lockPhysicalControl ? 'Locked' : 'Unlocked'}`);
1871
1871
  if (this.accountType === 'melcloudhome') this.emit('info', `Signal strength: ${deviceData.Rssi}dBm`);
1872
- };
1872
+ }
1873
1873
  })
1874
1874
  .on('success', (success) => this.emit('success', success))
1875
1875
  .on('info', (info) => this.emit('info', info))
package/src/deviceatw.js CHANGED
@@ -852,7 +852,7 @@ class DeviceAtw extends EventEmitter {
852
852
  break;
853
853
  };
854
854
  });
855
- };
855
+ }
856
856
 
857
857
  //sensor services
858
858
  if (zonesSensorsCount > 0) {
@@ -1023,7 +1023,7 @@ class DeviceAtw extends EventEmitter {
1023
1023
  break;
1024
1024
  };
1025
1025
  });
1026
- };
1026
+ }
1027
1027
 
1028
1028
  //in standby sensor
1029
1029
  if (this.inStandbySensor && this.accessory.inStandbyMode !== null) {
@@ -1237,7 +1237,7 @@ class DeviceAtw extends EventEmitter {
1237
1237
  accessory.addService(presetControlSensorService);
1238
1238
  }
1239
1239
  });
1240
- };
1240
+ }
1241
1241
 
1242
1242
  //schedules services
1243
1243
  if (this.schedules.length > 0 && this.accessory.scheduleEnabled !== null) {
@@ -1311,7 +1311,7 @@ class DeviceAtw extends EventEmitter {
1311
1311
  accessory.addService(scheduleSensorService);
1312
1312
  }
1313
1313
  });
1314
- };
1314
+ }
1315
1315
 
1316
1316
  //scenes
1317
1317
  if (this.scenes.length > 0) {
@@ -1370,7 +1370,7 @@ class DeviceAtw extends EventEmitter {
1370
1370
  accessory.addService(sceneControlSensorService);
1371
1371
  }
1372
1372
  });
1373
- };
1373
+ }
1374
1374
 
1375
1375
  //buttons services
1376
1376
  if (this.buttons.length > 0) {
@@ -1565,7 +1565,7 @@ class DeviceAtw extends EventEmitter {
1565
1565
  accessory.addService(buttonControlSensorService);
1566
1566
  }
1567
1567
  });
1568
- };
1568
+ }
1569
1569
 
1570
1570
  return accessory;
1571
1571
  } catch (error) {
@@ -2001,40 +2001,40 @@ class DeviceAtw extends EventEmitter {
2001
2001
  let operationModeText = '';
2002
2002
  switch (i) {
2003
2003
  case caseHeatPump: //Heat Pump - HEAT, COOL, OFF
2004
- this.emit('info', `${heatPumpName}, Power: ${power ? 'On' : 'Off'}`)
2005
- this.emit('info', `${heatPumpName}, Operation mode: ${HeatPump.SystemMapEnumToString[unitStatus]}`);
2006
- this.emit('info', `${heatPumpName},'Outdoor temperature: ${roomTemperature}${obj.temperatureUnit}`);
2007
- this.emit('info', `${heatPumpName}, Temperature display unit: ${obj.temperatureUnit}`);
2008
- this.emit('info', `${heatPumpName}, Lock physical controls: ${lockPhysicalControl ? 'Locked' : 'Unlocked'}`);
2004
+ this.emit('info', `Power: ${power ? 'On' : 'Off'}`)
2005
+ this.emit('info', `Operation mode: ${HeatPump.SystemMapEnumToString[unitStatus]}`);
2006
+ this.emit('info', `Outdoor temperature: ${roomTemperature}${obj.temperatureUnit}`);
2007
+ this.emit('info', `Temperature display unit: ${obj.temperatureUnit}`);
2008
+ this.emit('info', `Lock physical controls: ${lockPhysicalControl ? 'Locked' : 'Unlocked'}`);
2009
2009
  if (this.accountType === 'melcloudhome') this.emit('info', `Signal strength: ${deviceData.Rssi}dBm`);
2010
2010
  break;
2011
2011
  case caseZone1: //Zone 1 - HEAT THERMOSTAT, HEAT FLOW, HEAT CURVE, COOL THERMOSTAT, COOL FLOW, FLOOR DRY UP
2012
2012
  operationModeText = idleZone1 ? HeatPump.ZoneOperationMapEnumToString[6] : HeatPump.ZoneOperationMapEnumToString[operationModeZone1];
2013
- this.emit('info', `${zone1Name}, Operation mode: ${operationModeText}`);
2014
- this.emit('info', `${zone1Name}, Temperature: ${roomTemperature}${obj.temperatureUnit}`);
2015
- this.emit('info', `${zone1Name}, Target temperature: ${setTemperature}${obj.temperatureUnit}`)
2016
- this.emit('info', `${zone1Name}, Temperature display unit: ${obj.temperatureUnit}`);
2017
- this.emit('info', `${zone1Name}, Lock physical controls: ${lockPhysicalControl ? 'Locked' : 'Unlocked'}`);
2013
+ this.emit('info', `Operation mode: ${operationModeText}`);
2014
+ this.emit('info', `Temperature: ${roomTemperature}${obj.temperatureUnit}`);
2015
+ this.emit('info', `Target temperature: ${setTemperature}${obj.temperatureUnit}`)
2016
+ this.emit('info', `Temperature display unit: ${obj.temperatureUnit}`);
2017
+ this.emit('info', `Lock physical controls: ${lockPhysicalControl ? 'Locked' : 'Unlocked'}`);
2018
2018
  break;
2019
2019
  case caseHotWater: //Hot Water - AUTO, HEAT NOW
2020
2020
  operationModeText = operationMode === 1 ? HeatPump.ForceDhwMapEnumToString[1] : HeatPump.ForceDhwMapEnumToString[forcedHotWaterMode ? 1 : 0];
2021
- this.emit('info', `${hotWaterName}, Operation mode: ${operationModeText}`);
2022
- this.emit('info', `${hotWaterName}, Temperature: ${roomTemperature}${obj.temperatureUnit}`);
2023
- this.emit('info', `${hotWaterName}, Target temperature: ${setTemperature}${obj.temperatureUnit}`)
2024
- this.emit('info', `${hotWaterName}, Temperature display unit: ${obj.temperatureUnit}`);
2025
- this.emit('info', `${hotWaterName}, Lock physical controls: ${lockPhysicalControl ? 'Locked' : 'Unlocked'}`);
2021
+ this.emit('info', `Operation mode: ${operationModeText}`);
2022
+ this.emit('info', `Temperature: ${roomTemperature}${obj.temperatureUnit}`);
2023
+ this.emit('info', `Target temperature: ${setTemperature}${obj.temperatureUnit}`)
2024
+ this.emit('info', `Temperature display unit: ${obj.temperatureUnit}`);
2025
+ this.emit('info', `Lock physical controls: ${lockPhysicalControl ? 'Locked' : 'Unlocked'}`);
2026
2026
  break;
2027
2027
  case caseZone2: //Zone 2 - HEAT THERMOSTAT, HEAT FLOW, HEAT CURVE, COOL THERMOSTAT, COOL FLOW, FLOOR DRY UP
2028
2028
  operationModeText = idleZone2 ? HeatPump.ZoneOperationMapEnumToString[6] : HeatPump.ZoneOperationMapEnumToString[operationModeZone2];
2029
- this.emit('info', `${zone2Name}, Operation mode: ${operationModeText}`);
2030
- this.emit('info', `${zone2Name}, Temperature: ${roomTemperature}${obj.temperatureUnit}`);
2031
- this.emit('info', `${zone2Name}, Target temperature: ${setTemperature}${obj.temperatureUnit}`)
2032
- this.emit('info', `${zone2Name}, Temperature display unit: ${obj.temperatureUnit}`);
2033
- this.emit('info', `${zone2Name}, Lock physical controls: ${lockPhysicalControl ? 'Locked' : 'Unlocked'}`);
2029
+ this.emit('info', `Operation mode: ${operationModeText}`);
2030
+ this.emit('info', `Temperature: ${roomTemperature}${obj.temperatureUnit}`);
2031
+ this.emit('info', `Target temperature: ${setTemperature}${obj.temperatureUnit}`)
2032
+ this.emit('info', `Temperature display unit: ${obj.temperatureUnit}`);
2033
+ this.emit('info', `Lock physical controls: ${lockPhysicalControl ? 'Locked' : 'Unlocked'}`);
2034
2034
  break;
2035
2035
  };
2036
- };
2037
- };
2036
+ }
2037
+ }
2038
2038
 
2039
2039
  //update sensors characteristics
2040
2040
  for (let i = 0; i < zonesSensorsCount; i++) {
@@ -2119,7 +2119,7 @@ class DeviceAtw extends EventEmitter {
2119
2119
  break;
2120
2120
  };
2121
2121
  };
2122
- };
2122
+ }
2123
2123
  this.accessory = obj;
2124
2124
 
2125
2125
  //update services
@@ -2174,7 +2174,7 @@ class DeviceAtw extends EventEmitter {
2174
2174
  //sensor
2175
2175
  if (preset.displayType < 7) this.presetControlSensorServices?.[i]?.updateCharacteristic(characteristicType, preset.state);
2176
2176
  });
2177
- };
2177
+ }
2178
2178
 
2179
2179
  ///schedules
2180
2180
  if (this.schedules.length > 0 && scheduleEnabled !== null) {
@@ -2194,7 +2194,7 @@ class DeviceAtw extends EventEmitter {
2194
2194
  //sensor
2195
2195
  if (schedule.displayType < 7) this.scheduleSensorServices?.[i]?.updateCharacteristic(characteristicType, schedule.state);
2196
2196
  });
2197
- };
2197
+ }
2198
2198
 
2199
2199
  //scenes
2200
2200
  if (this.scenes.length > 0) {
@@ -2211,7 +2211,7 @@ class DeviceAtw extends EventEmitter {
2211
2211
  //sensor
2212
2212
  if (scene.displayType < 7) this.sceneControlSensorServices?.[i]?.updateCharacteristic(characteristicType, scene.state);
2213
2213
  });
2214
- };
2214
+ }
2215
2215
 
2216
2216
  //buttons
2217
2217
  if (this.buttons.length > 0) {
@@ -2299,7 +2299,7 @@ class DeviceAtw extends EventEmitter {
2299
2299
  //sensor
2300
2300
  if (button.displayType < 7) this.buttonControlSensorServices?.[i]?.updateCharacteristic(characteristicType, button.state);
2301
2301
  });
2302
- };
2302
+ }
2303
2303
  })
2304
2304
  .on('success', (success) => this.emit('success', success))
2305
2305
  .on('info', (info) => this.emit('info', info))
package/src/deviceerv.js CHANGED
@@ -586,7 +586,7 @@ class DeviceErv extends EventEmitter {
586
586
  return state;
587
587
  })
588
588
  accessory.addService(this.roomTemperatureSensorService);
589
- };
589
+ }
590
590
 
591
591
  //temperature sensor service supply
592
592
  if (this.temperatureSupplySensor && supportsSupplyTemperature && this.accessory.supplyTemperature !== null) {
@@ -600,7 +600,7 @@ class DeviceErv extends EventEmitter {
600
600
  return state;
601
601
  })
602
602
  accessory.addService(this.supplyTemperatureSensorService);
603
- };
603
+ }
604
604
 
605
605
  //temperature sensor service outdoor
606
606
  if (this.temperatureOutdoorSensor && supportsOutdoorTemperature && this.accessory.outdoorTemperature !== null) {
@@ -614,7 +614,7 @@ class DeviceErv extends EventEmitter {
614
614
  return state;
615
615
  })
616
616
  accessory.addService(this.outdoorTemperatureSensorService);
617
- };
617
+ }
618
618
 
619
619
  //core maintenance
620
620
  if (this.accessory.coreMaintenanceRequired !== null) {
@@ -849,7 +849,7 @@ class DeviceErv extends EventEmitter {
849
849
  accessory.addService(presetControlSensorService);
850
850
  }
851
851
  });
852
- };
852
+ }
853
853
 
854
854
  //schedules services
855
855
  if (this.schedules.length > 0 && this.accessory.scheduleEnabled !== null) {
@@ -923,7 +923,7 @@ class DeviceErv extends EventEmitter {
923
923
  accessory.addService(scheduleSensorService);
924
924
  }
925
925
  });
926
- };
926
+ }
927
927
 
928
928
  //scenes
929
929
  if (this.scenes.length > 0) {
@@ -982,7 +982,7 @@ class DeviceErv extends EventEmitter {
982
982
  accessory.addService(sceneControlSensorService);
983
983
  }
984
984
  });
985
- };
985
+ }
986
986
 
987
987
  //buttons services
988
988
  if (this.buttons.length > 0) {
@@ -1118,7 +1118,7 @@ class DeviceErv extends EventEmitter {
1118
1118
  accessory.addService(buttonControlSensorService);
1119
1119
  }
1120
1120
  });
1121
- };
1121
+ }
1122
1122
 
1123
1123
  return accessory;
1124
1124
  } catch (error) {
@@ -1454,7 +1454,7 @@ class DeviceErv extends EventEmitter {
1454
1454
  //sensor
1455
1455
  if (preset.displayType < 7) this.presetControlSensorServices?.[i]?.updateCharacteristic(characteristicType, preset.state);
1456
1456
  });
1457
- };
1457
+ }
1458
1458
 
1459
1459
  ///schedules
1460
1460
  if (this.schedules.length > 0 && scheduleEnabled !== null) {
@@ -1474,7 +1474,7 @@ class DeviceErv extends EventEmitter {
1474
1474
  //sensor
1475
1475
  if (schedule.displayType < 7) this.scheduleSensorServices?.[i]?.updateCharacteristic(characteristicType, schedule.state);
1476
1476
  });
1477
- };
1477
+ }
1478
1478
 
1479
1479
  //scenes
1480
1480
  if (this.scenes.length > 0) {
@@ -1491,7 +1491,7 @@ class DeviceErv extends EventEmitter {
1491
1491
  //sensor
1492
1492
  if (scene.displayType < 7) this.sceneControlSensorServices?.[i]?.updateCharacteristic(characteristicType, scene.state);
1493
1493
  });
1494
- };
1494
+ }
1495
1495
 
1496
1496
  //buttons
1497
1497
  if (this.buttons.length > 0) {
@@ -1552,7 +1552,7 @@ class DeviceErv extends EventEmitter {
1552
1552
  //sensor
1553
1553
  if (button.displayType < 7) this.buttonControlSensorServices?.[i]?.updateCharacteristic(characteristicType, button.state);
1554
1554
  });
1555
- };
1555
+ }
1556
1556
 
1557
1557
  //log current state
1558
1558
  if (this.logInfo) {
@@ -1572,7 +1572,7 @@ class DeviceErv extends EventEmitter {
1572
1572
  if (supportsPM25Sensor) this.emit('info', `PM2.5 air quality: ${Ventilation.PM25AirQualityMapEnumToString[pM25AirQuality]}`);
1573
1573
  if (supportsPM25Sensor) this.emit('info', `PM2.5 level: ${pM25Level} µg/m`);
1574
1574
  if (this.accountType === 'melcloudhome') this.emit('info', `Signal strength: ${deviceData.Rssi}dBm`);
1575
- };
1575
+ }
1576
1576
  })
1577
1577
  .on('success', (success) => this.emit('success', success))
1578
1578
  .on('info', (info) => this.emit('info', info))
package/src/functions.js CHANGED
@@ -160,5 +160,12 @@ class Functions extends EventEmitter {
160
160
  return v !== undefined && v !== null && !(typeof v === 'number' && Number.isNaN(v));
161
161
  }
162
162
 
163
+ convertValue(v) {
164
+ let parsedValue = v;
165
+ if (v === "True") parsedValue = true;
166
+ else if (v === "False") parsedValue = false;
167
+ else if (!isNaN(v) && v !== "") parsedValue = Number(v);
168
+ return parsedValue;
169
+ }
163
170
  }
164
171
  export default Functions
@@ -70,17 +70,8 @@ class MelCloudAta extends EventEmitter {
70
70
  this.socketConnected = false;
71
71
  }
72
72
 
73
- async checkState() {
73
+ async updateState(deviceData) {
74
74
  try {
75
-
76
- //read device info from file
77
- const devicesData = await this.functions.readData(this.devicesFile, true);
78
- if (!devicesData) return;
79
-
80
- this.headers = devicesData.Headers;
81
- const deviceData = devicesData.Devices.find(device => device.DeviceID === this.deviceId);
82
- deviceData.Scenes = devicesData.Scenes ?? [];
83
-
84
75
  if (this.accountType === 'melcloudhome') {
85
76
  deviceData.Device.OperationMode = AirConditioner.OperationModeMapStringToEnum[deviceData.Device.OperationMode] ?? deviceData.Device.OperationMode;
86
77
  deviceData.Device.ActualFanSpeed = AirConditioner.FanSpeedMapStringToEnum[deviceData.Device.ActualFanSpeed] ?? deviceData.Device.ActualFanSpeed;
@@ -93,87 +84,6 @@ class MelCloudAta extends EventEmitter {
93
84
  deviceData.Device.DefaultHeatingSetTemperature = temps?.defaultHeatingSetTemperature ?? 20;
94
85
  deviceData.Device.DefaultCoolingSetTemperature = temps?.defaultCoolingSetTemperature ?? 24;
95
86
 
96
- //web cocket connection
97
- if (!this.connecting && !this.socketConnected) {
98
- this.connecting = true;
99
-
100
- const url = `${ApiUrlsHome.WebSocketURL}${devicesData.WebSocketOptions.Hash}`;
101
- try {
102
- const socket = new WebSocket(url, { headers: devicesData.WebSocketOptions.Headers })
103
- .on('error', (error) => {
104
- if (this.logError) this.emit('error', `Socket error: ${error}`);
105
- socket.close();
106
- })
107
- .on('close', () => {
108
- if (this.logDebug) this.emit('debug', `Socket closed`);
109
- this.cleanupSocket();
110
- })
111
- .on('open', () => {
112
- this.socket = socket;
113
- this.socketConnected = true;
114
- this.connecting = false;
115
- if (this.logSuccess) this.emit('success', `Socket Connect Success`);
116
-
117
- // heartbeat
118
- this.heartbeat = setInterval(() => {
119
- if (socket.readyState === socket.OPEN) {
120
- if (this.logDebug) this.emit('debug', `Socket send heartbeat`);
121
- socket.ping();
122
- }
123
- }, 30000);
124
- })
125
- .on('pong', () => {
126
- if (this.logDebug) this.emit('debug', `Socket received heartbeat`);
127
- })
128
- .on('message', (message) => {
129
- const parsedMessage = JSON.parse(message);
130
- const stringifyMessage = JSON.stringify(parsedMessage, null, 2);
131
- if (this.logDebug) this.emit('debug', `Incoming message: ${stringifyMessage}`);
132
- if (parsedMessage.message === 'Forbidden') return;
133
-
134
- const messageData = parsedMessage?.[0]?.Data;
135
- if (!messageData) return;
136
-
137
- let updateDeviceState = false;
138
- const unitId = messageData?.id;
139
- switch (unitId) {
140
- case this.deviceId:
141
- const messageType = parsedMessage[0].messageType;
142
- switch (messageType) {
143
- case 'unitStateChanged':
144
- const settings = Object.fromEntries(
145
- messageData.settings.map(({ name, value }) => {
146
- let parsedValue = value;
147
- if (value === "True") parsedValue = true;
148
- else if (value === "False") parsedValue = false;
149
- else if (!isNaN(value) && value !== "") parsedValue = Number(value);
150
- return [name, parsedValue];
151
- })
152
- );
153
- Object.assign(deviceData.Device, settings);
154
- updateDeviceState = true;
155
- break;
156
- case 'unitWifiSignalChanged':
157
- Object.assign(deviceData, messageData.rssi);
158
- updateDeviceState = true;
159
- break;
160
- default:
161
- if (!this.logDebug) this.emit('debug', `Unit ${unitId}, received unknown message type: ${stringifyMessage}`);
162
- return;
163
- }
164
- break;
165
- default:
166
- if (!this.logDebug) this.emit('debug', `Incoming unknown unit id: ${stringifyMessage}`);
167
- return;
168
- }
169
-
170
- if (updateDeviceState) this.emit('deviceState', deviceData);
171
- });
172
- } catch (error) {
173
- if (this.logError) this.emit('error', `Socket connection failed: ${error}`);
174
- this.cleanupSocket();
175
- }
176
- }
177
87
  }
178
88
  if (this.logDebug) this.emit('debug', `Device Data: ${JSON.stringify(deviceData, null, 2)}`);
179
89
 
@@ -216,11 +126,6 @@ class MelCloudAta extends EventEmitter {
216
126
  this.emit('mqtt', 'State', deviceData.Device);
217
127
  }
218
128
 
219
- //check state changes
220
- const deviceDataHasNotChanged = JSON.stringify(deviceData) === JSON.stringify(this.deviceData);
221
- if (deviceDataHasNotChanged) return;
222
- this.deviceData = deviceData;
223
-
224
129
  //emit info
225
130
  this.emit('deviceInfo', indoor.model, outdoor.model, serialNumber, firmwareAppVersion);
226
131
 
@@ -233,6 +138,114 @@ class MelCloudAta extends EventEmitter {
233
138
  };
234
139
  };
235
140
 
141
+ async checkState() {
142
+ try {
143
+
144
+ //read device info from file
145
+ const devicesData = await this.functions.readData(this.devicesFile, true);
146
+ if (!devicesData) return;
147
+
148
+ this.headers = devicesData.Headers;
149
+ const deviceData = devicesData.Devices.find(device => device.DeviceID === this.deviceId);
150
+ deviceData.Scenes = devicesData.Scenes ?? [];
151
+
152
+ //web cocket connection
153
+ if (this.accountType === 'melcloudhome' && !this.connecting && !this.socketConnected) {
154
+ this.connecting = true;
155
+
156
+ const url = `${ApiUrlsHome.WebSocketURL}${devicesData.WebSocketOptions.Hash}`;
157
+ try {
158
+ const socket = new WebSocket(url, { headers: devicesData.WebSocketOptions.Headers })
159
+ .on('error', (error) => {
160
+ if (this.logError) this.emit('error', `Socket error: ${error}`);
161
+ socket.close();
162
+ })
163
+ .on('close', () => {
164
+ if (this.logDebug) this.emit('debug', `Socket closed`);
165
+ this.cleanupSocket();
166
+ })
167
+ .on('open', () => {
168
+ this.socket = socket;
169
+ this.socketConnected = true;
170
+ this.connecting = false;
171
+ if (this.logSuccess) this.emit('success', `Socket Connect Success`);
172
+
173
+ // heartbeat
174
+ this.heartbeat = setInterval(() => {
175
+ if (socket.readyState === socket.OPEN) {
176
+ if (this.logDebug) this.emit('debug', `Socket send heartbeat`);
177
+ socket.ping();
178
+ }
179
+ }, 30000);
180
+ })
181
+ .on('pong', () => {
182
+ if (this.logDebug) this.emit('debug', `Socket received heartbeat`);
183
+ })
184
+ .on('message', async (message) => {
185
+ const parsedMessage = JSON.parse(message);
186
+ const stringifyMessage = JSON.stringify(parsedMessage, null, 2);
187
+ if (this.logDebug) this.emit('debug', `Incoming message: ${stringifyMessage}`);
188
+ if (parsedMessage.message === 'Forbidden') return;
189
+
190
+ const messageData = parsedMessage?.[0]?.Data;
191
+ if (!messageData) return;
192
+
193
+ let updateState = false;
194
+ const unitId = messageData?.id;
195
+ switch (unitId) {
196
+ case this.deviceId:
197
+ const messageType = parsedMessage[0].messageType;
198
+ switch (messageType) {
199
+ case 'unitStateChanged':
200
+ const settings = Object.fromEntries(
201
+ messageData.settings.map(({ name, value }) => {
202
+ let parsedValue = this.functions.convertValue(value);
203
+ return [name, parsedValue];
204
+ })
205
+ );
206
+ Object.assign(deviceData.Device, settings);
207
+ updateState = true;
208
+ break;
209
+ case 'unitWifiSignalChanged':
210
+ deviceData.Rssi = messageData.rssi;
211
+ updateState = true;
212
+ break;
213
+ default:
214
+ if (!this.logDebug) this.emit('debug', `Unit ${unitId}, received unknown message type: ${stringifyMessage}`);
215
+ return;
216
+ }
217
+ break;
218
+ default:
219
+ if (!this.logDebug) this.emit('debug', `Incoming unknown unit id: ${stringifyMessage}`);
220
+ return;
221
+ }
222
+
223
+ //update state
224
+ if (updateState) {
225
+ this.deviceData = deviceData;
226
+ await this.updateState(deviceData);
227
+ }
228
+ });
229
+ } catch (error) {
230
+ if (this.logError) this.emit('error', `Socket connection failed: ${error}`);
231
+ this.cleanupSocket();
232
+ }
233
+ }
234
+
235
+ //check state changes
236
+ const deviceDataNotChanged = JSON.stringify(deviceData) === JSON.stringify(this.deviceData);
237
+ if (deviceDataNotChanged) return;
238
+ this.deviceData = deviceData;
239
+
240
+ //update state
241
+ await this.updateState(deviceData);
242
+
243
+ return true;
244
+ } catch (error) {
245
+ throw new Error(`Check state error: ${error.message}`);
246
+ };
247
+ };
248
+
236
249
  async send(accountType, displayType, deviceData, flag, flagData) {
237
250
  try {
238
251
  let method = null
@@ -145,11 +145,7 @@ class MelCloudHome extends EventEmitter {
145
145
 
146
146
  const settingsObject = Object.fromEntries(
147
147
  settingsArray.map(({ name, value }) => {
148
- let parsedValue = value;
149
- if (value === "True") parsedValue = true;
150
- else if (value === "False") parsedValue = false;
151
- else if (!isNaN(value) && value !== "") parsedValue = Number(value);
152
-
148
+ let parsedValue = this.functions.convertValue(value);
153
149
  const key = name.charAt(0).toUpperCase() + name.slice(1);
154
150
  return [key, parsedValue];
155
151
  })