homebridge-melcloud-control 3.9.4 → 3.9.6
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 +12 -0
- package/package.json +1 -1
- package/src/deviceata.js +27 -44
- package/src/deviceatw.js +38 -88
- package/src/deviceerv.js +36 -67
- package/src/functions.js +31 -0
- package/src/melcloud.js +71 -80
- package/src/melcloudata.js +27 -31
- package/src/melcloudatw.js +27 -30
- package/src/melclouderv.js +27 -30
package/CHANGELOG.md
CHANGED
|
@@ -16,6 +16,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
16
16
|
- do not configure it manually, always using Config UI X
|
|
17
17
|
- required Homebridge v2.0.0 and above
|
|
18
18
|
|
|
19
|
+
## [3.9.5] - (02.09.2025)
|
|
20
|
+
|
|
21
|
+
## Changes
|
|
22
|
+
|
|
23
|
+
- fix ERV start error
|
|
24
|
+
|
|
25
|
+
## [3.9.4] - (02.09.2025)
|
|
26
|
+
|
|
27
|
+
## Changes
|
|
28
|
+
|
|
29
|
+
- fix [#213](https://github.com/grzegorz914/homebridge-melcloud-control/issues/213)
|
|
30
|
+
|
|
19
31
|
## [3.9.0] - (18.08.2025)
|
|
20
32
|
|
|
21
33
|
## Changes
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"displayName": "MELCloud Control",
|
|
3
3
|
"name": "homebridge-melcloud-control",
|
|
4
|
-
"version": "3.9.
|
|
4
|
+
"version": "3.9.6",
|
|
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
|
@@ -46,8 +46,8 @@ class DeviceAta extends EventEmitter {
|
|
|
46
46
|
//presets configured
|
|
47
47
|
this.presetsConfigured = [];
|
|
48
48
|
for (const preset of this.presets) {
|
|
49
|
-
const displayType = preset.displayType
|
|
50
|
-
if (displayType
|
|
49
|
+
const displayType = preset.displayType;
|
|
50
|
+
if (!displayType) {
|
|
51
51
|
continue;
|
|
52
52
|
};
|
|
53
53
|
|
|
@@ -65,8 +65,8 @@ class DeviceAta extends EventEmitter {
|
|
|
65
65
|
//buttons configured
|
|
66
66
|
this.buttonsConfigured = [];
|
|
67
67
|
for (const button of this.buttons) {
|
|
68
|
-
const displayType = button.displayType
|
|
69
|
-
if (displayType
|
|
68
|
+
const displayType = button.displayType;
|
|
69
|
+
if (!displayType) {
|
|
70
70
|
continue;
|
|
71
71
|
};
|
|
72
72
|
|
|
@@ -1128,19 +1128,17 @@ class DeviceAta extends EventEmitter {
|
|
|
1128
1128
|
};
|
|
1129
1129
|
|
|
1130
1130
|
//update characteristics
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
const updateSM = swingFunction ? this.melCloudService.updateCharacteristic(Characteristic.SwingMode, obj.swingMode) : false;
|
|
1143
|
-
};
|
|
1131
|
+
this.melCloudService
|
|
1132
|
+
?.updateCharacteristic(Characteristic.Active, power ? 1 : 0)
|
|
1133
|
+
.updateCharacteristic(Characteristic.CurrentHeaterCoolerState, obj.currentOperationMode)
|
|
1134
|
+
.updateCharacteristic(Characteristic.TargetHeaterCoolerState, obj.targetOperationMode)
|
|
1135
|
+
.updateCharacteristic(Characteristic.CurrentTemperature, roomTemperature)
|
|
1136
|
+
.updateCharacteristic(Characteristic.LockPhysicalControls, obj.lockPhysicalControl)
|
|
1137
|
+
.updateCharacteristic(Characteristic.TemperatureDisplayUnits, obj.useFahrenheit)
|
|
1138
|
+
.updateCharacteristic(Characteristic.CoolingThresholdTemperature, defaultCoolingSetTemperature);
|
|
1139
|
+
const updateDefHeat = modelSupportsHeat ? this.melCloudService?.updateCharacteristic(Characteristic.HeatingThresholdTemperature, defaultHeatingSetTemperature) : false;
|
|
1140
|
+
const updateRS = modelSupportsFanSpeed ? this.melCloudService?.updateCharacteristic(Characteristic.RotationSpeed, obj.fanSpeed) : false;
|
|
1141
|
+
const updateSM = swingFunction ? this.melCloudService?.updateCharacteristic(Characteristic.SwingMode, obj.swingMode) : false;
|
|
1144
1142
|
break;
|
|
1145
1143
|
case 2: //Thermostat
|
|
1146
1144
|
switch (operationMode) {
|
|
@@ -1188,27 +1186,18 @@ class DeviceAta extends EventEmitter {
|
|
|
1188
1186
|
obj.operationModeSetPropsValidValues = modelSupportsAuto && modelSupportsHeat ? [0, 1, 2, 3] : !modelSupportsAuto && modelSupportsHeat ? [0, 1, 2] : modelSupportsAuto && !modelSupportsHeat ? [0, 2, 3] : [0, 2];
|
|
1189
1187
|
|
|
1190
1188
|
//update characteristics
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
.updateCharacteristic(Characteristic.TemperatureDisplayUnits, obj.useFahrenheit);
|
|
1198
|
-
};
|
|
1189
|
+
this.melCloudService
|
|
1190
|
+
?.updateCharacteristic(Characteristic.CurrentHeatingCoolingState, obj.currentOperationMode)
|
|
1191
|
+
.updateCharacteristic(Characteristic.TargetHeatingCoolingState, obj.targetOperationMode)
|
|
1192
|
+
.updateCharacteristic(Characteristic.CurrentTemperature, roomTemperature)
|
|
1193
|
+
.updateCharacteristic(Characteristic.TargetTemperature, setTemperature)
|
|
1194
|
+
.updateCharacteristic(Characteristic.TemperatureDisplayUnits, obj.useFahrenheit);
|
|
1199
1195
|
break;
|
|
1200
1196
|
};
|
|
1201
1197
|
this.accessory = obj;
|
|
1202
1198
|
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
.updateCharacteristic(Characteristic.CurrentTemperature, roomTemperature)
|
|
1206
|
-
};
|
|
1207
|
-
|
|
1208
|
-
if (this.outdoorTemperatureSensorService) {
|
|
1209
|
-
this.outdoorTemperatureSensorService
|
|
1210
|
-
.updateCharacteristic(Characteristic.CurrentTemperature, outdoorTemperature)
|
|
1211
|
-
};
|
|
1199
|
+
this.roomTemperatureSensorService?.updateCharacteristic(Characteristic.CurrentTemperature, roomTemperature);
|
|
1200
|
+
this.outdoorTemperatureSensorService?.updateCharacteristic(Characteristic.CurrentTemperature, outdoorTemperature);
|
|
1212
1201
|
|
|
1213
1202
|
//update presets state
|
|
1214
1203
|
if (this.presetsConfigured.length > 0) {
|
|
@@ -1222,11 +1211,8 @@ class DeviceAta extends EventEmitter {
|
|
|
1222
1211
|
&& presetData.VaneVertical === vaneVerticalDirection
|
|
1223
1212
|
&& presetData.FanSpeed === fanSpeed) : false;
|
|
1224
1213
|
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
this.presetsServices[i]
|
|
1228
|
-
.updateCharacteristic(characteristicType, preset.state)
|
|
1229
|
-
};
|
|
1214
|
+
const characteristicType = preset.characteristicType;
|
|
1215
|
+
this.presetsServices?.[i]?.updateCharacteristic(characteristicType, preset.state);
|
|
1230
1216
|
});
|
|
1231
1217
|
};
|
|
1232
1218
|
|
|
@@ -1346,11 +1332,8 @@ class DeviceAta extends EventEmitter {
|
|
|
1346
1332
|
};
|
|
1347
1333
|
|
|
1348
1334
|
//update services
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
this.buttonsServices[i]
|
|
1352
|
-
.updateCharacteristic(characteristicType, button.state)
|
|
1353
|
-
};
|
|
1335
|
+
const characteristicType = button.characteristicType;
|
|
1336
|
+
this.buttonsServices?.[i]?.updateCharacteristic(characteristicType, button.state);
|
|
1354
1337
|
});
|
|
1355
1338
|
};
|
|
1356
1339
|
|
package/src/deviceatw.js
CHANGED
|
@@ -51,8 +51,8 @@ class DeviceAtw extends EventEmitter {
|
|
|
51
51
|
//presets configured
|
|
52
52
|
this.presetsConfigured = [];
|
|
53
53
|
for (const preset of this.presets) {
|
|
54
|
-
const displayType = preset.displayType
|
|
55
|
-
if (displayType
|
|
54
|
+
const displayType = preset.displayType;
|
|
55
|
+
if (!displayType) {
|
|
56
56
|
continue;
|
|
57
57
|
};
|
|
58
58
|
|
|
@@ -70,8 +70,8 @@ class DeviceAtw extends EventEmitter {
|
|
|
70
70
|
//buttons configured
|
|
71
71
|
this.buttonsConfigured = [];
|
|
72
72
|
for (const button of this.buttons) {
|
|
73
|
-
const displayType = button.displayType
|
|
74
|
-
if (displayType
|
|
73
|
+
const displayType = button.displayType;
|
|
74
|
+
if (!displayType) {
|
|
75
75
|
continue;
|
|
76
76
|
};
|
|
77
77
|
|
|
@@ -271,7 +271,6 @@ class DeviceAtw extends EventEmitter {
|
|
|
271
271
|
};
|
|
272
272
|
}
|
|
273
273
|
|
|
274
|
-
|
|
275
274
|
async startImpulseGenerator() {
|
|
276
275
|
try {
|
|
277
276
|
//start impule generator
|
|
@@ -1564,17 +1563,14 @@ class DeviceAtw extends EventEmitter {
|
|
|
1564
1563
|
};
|
|
1565
1564
|
|
|
1566
1565
|
//update characteristics
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
const updateDefCool = heatCoolModes === 0 || heatCoolModes === 2 ? this.melCloudServices[i].updateCharacteristic(Characteristic.CoolingThresholdTemperature, setTemperature) : false;
|
|
1576
|
-
const updateDefHeat = heatCoolModes === 0 || heatCoolModes === 1 ? this.melCloudServices[i].updateCharacteristic(Characteristic.HeatingThresholdTemperature, setTemperature) : false;
|
|
1577
|
-
}
|
|
1566
|
+
this.melCloudServices?.[i]
|
|
1567
|
+
?.updateCharacteristic(Characteristic.Active, power)
|
|
1568
|
+
.updateCharacteristic(Characteristic.CurrentHeaterCoolerState, currentOperationMode)
|
|
1569
|
+
.updateCharacteristic(Characteristic.TargetHeaterCoolerState, targetOperationMode)
|
|
1570
|
+
.updateCharacteristic(Characteristic.CurrentTemperature, roomTemperature)
|
|
1571
|
+
.updateCharacteristic(Characteristic.LockPhysicalControls, lockPhysicalControl)
|
|
1572
|
+
.updateCharacteristic(Characteristic.TemperatureDisplayUnits, obj.useFahrenheit);
|
|
1573
|
+
const updateDefCool = heatCoolModes === 0 || heatCoolModes === 2 ? this.melCloudServices?.[i]?.updateCharacteristic(Characteristic.CoolingThresholdTemperature, setTemperature) : false;
|
|
1578
1574
|
break;
|
|
1579
1575
|
case 2: //Thermostat
|
|
1580
1576
|
switch (i) {
|
|
@@ -1671,14 +1667,12 @@ class DeviceAtw extends EventEmitter {
|
|
|
1671
1667
|
};
|
|
1672
1668
|
|
|
1673
1669
|
//update characteristics
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
.updateCharacteristic(Characteristic.TemperatureDisplayUnits, obj.useFahrenheit);
|
|
1681
|
-
}
|
|
1670
|
+
this.melCloudServices?.[i]
|
|
1671
|
+
?.updateCharacteristic(Characteristic.CurrentHeatingCoolingState, currentOperationMode)
|
|
1672
|
+
.updateCharacteristic(Characteristic.TargetHeatingCoolingState, targetOperationMode)
|
|
1673
|
+
.updateCharacteristic(Characteristic.CurrentTemperature, roomTemperature)
|
|
1674
|
+
.updateCharacteristic(Characteristic.TargetTemperature, setTemperature)
|
|
1675
|
+
.updateCharacteristic(Characteristic.TemperatureDisplayUnits, obj.useFahrenheit);
|
|
1682
1676
|
break;
|
|
1683
1677
|
};
|
|
1684
1678
|
|
|
@@ -1748,20 +1742,9 @@ class DeviceAtw extends EventEmitter {
|
|
|
1748
1742
|
returnTemperature = returnTemperatureHeatPump;
|
|
1749
1743
|
|
|
1750
1744
|
//updte characteristics
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
};
|
|
1755
|
-
|
|
1756
|
-
if (this.flowTemperatureSensorService) {
|
|
1757
|
-
this.flowTemperatureSensorService
|
|
1758
|
-
.updateCharacteristic(Characteristic.CurrentTemperature, flowTemperatureHeatPump)
|
|
1759
|
-
};
|
|
1760
|
-
|
|
1761
|
-
if (this.returnTemperatureSensorService) {
|
|
1762
|
-
this.returnTemperatureSensorService
|
|
1763
|
-
.updateCharacteristic(Characteristic.CurrentTemperature, returnTemperatureHeatPump)
|
|
1764
|
-
};
|
|
1745
|
+
this.roomTemperatureSensorService?.updateCharacteristic(Characteristic.CurrentTemperature, outdoorTemperature);
|
|
1746
|
+
this.flowTemperatureSensorService?.updateCharacteristic(Characteristic.CurrentTemperature, flowTemperatureHeatPump);
|
|
1747
|
+
this.returnTemperatureSensorService?.updateCharacteristic(Characteristic.CurrentTemperature, returnTemperatureHeatPump);
|
|
1765
1748
|
break;
|
|
1766
1749
|
case caseZone1Sensor: //Zone 1
|
|
1767
1750
|
name = zone1Name;
|
|
@@ -1770,20 +1753,9 @@ class DeviceAtw extends EventEmitter {
|
|
|
1770
1753
|
returnTemperature = returnTemperatureZone1;
|
|
1771
1754
|
|
|
1772
1755
|
//updte characteristics
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
};
|
|
1777
|
-
|
|
1778
|
-
if (this.flowTemperatureZone1SensorService) {
|
|
1779
|
-
this.flowTemperatureZone1SensorService
|
|
1780
|
-
.updateCharacteristic(Characteristic.CurrentTemperature, flowTemperatureZone1)
|
|
1781
|
-
};
|
|
1782
|
-
|
|
1783
|
-
if (this.returnTemperatureZone1SensorService) {
|
|
1784
|
-
this.returnTemperatureZone1SensorService
|
|
1785
|
-
.updateCharacteristic(Characteristic.CurrentTemperature, returnTemperatureZone1)
|
|
1786
|
-
};
|
|
1756
|
+
this.roomTemperatureZone1SensorService?.updateCharacteristic(Characteristic.CurrentTemperature, roomTemperatureZone1);
|
|
1757
|
+
this.flowTemperatureZone1SensorService?.updateCharacteristic(Characteristic.CurrentTemperature, flowTemperatureZone1);
|
|
1758
|
+
this.returnTemperatureZone1SensorService?.updateCharacteristic(Characteristic.CurrentTemperature, returnTemperatureZone1);
|
|
1787
1759
|
break;
|
|
1788
1760
|
case caseHotWaterSensor: //Hot Water
|
|
1789
1761
|
name = hotWaterName;
|
|
@@ -1792,20 +1764,9 @@ class DeviceAtw extends EventEmitter {
|
|
|
1792
1764
|
returnTemperature = returnTemperatureWaterTank;
|
|
1793
1765
|
|
|
1794
1766
|
//updte characteristics
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
};
|
|
1799
|
-
|
|
1800
|
-
if (this.flowTemperatureWaterTankSensorService) {
|
|
1801
|
-
this.flowTemperatureWaterTankSensorService
|
|
1802
|
-
.updateCharacteristic(Characteristic.CurrentTemperature, flowTemperatureWaterTank)
|
|
1803
|
-
};
|
|
1804
|
-
|
|
1805
|
-
if (this.returnTemperatureWaterTankSensorService) {
|
|
1806
|
-
this.returnTemperatureWaterTankSensorService
|
|
1807
|
-
.updateCharacteristic(Characteristic.CurrentTemperature, returnTemperatureWaterTank)
|
|
1808
|
-
};
|
|
1767
|
+
this.roomTemperatureWaterTankSensorService?.updateCharacteristic(Characteristic.CurrentTemperature, tankWaterTemperature);
|
|
1768
|
+
this.flowTemperatureWaterTankSensorService?.updateCharacteristic(Characteristic.CurrentTemperature, flowTemperatureWaterTank);
|
|
1769
|
+
this.returnTemperatureWaterTankSensorService?.updateCharacteristic(Characteristic.CurrentTemperature, returnTemperatureWaterTank);
|
|
1809
1770
|
break;
|
|
1810
1771
|
case caseZone2Sensor: //Zone 2
|
|
1811
1772
|
name = zone2Name;
|
|
@@ -1814,20 +1775,9 @@ class DeviceAtw extends EventEmitter {
|
|
|
1814
1775
|
returnTemperature = returnTemperatureZone2;
|
|
1815
1776
|
|
|
1816
1777
|
//updte characteristics
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
};
|
|
1821
|
-
|
|
1822
|
-
if (this.flowTemperatureZone2SensorService) {
|
|
1823
|
-
this.flowTemperatureZone2SensorService
|
|
1824
|
-
.updateCharacteristic(Characteristic.CurrentTemperature, flowTemperatureZone2)
|
|
1825
|
-
};
|
|
1826
|
-
|
|
1827
|
-
if (this.returnTemperatureZone2SensorService) {
|
|
1828
|
-
this.returnTemperatureZone2SensorService
|
|
1829
|
-
.updateCharacteristic(Characteristic.CurrentTemperature, returnTemperatureZone2)
|
|
1830
|
-
};
|
|
1778
|
+
this.roomTemperatureZone2SensorService?.updateCharacteristic(Characteristic.CurrentTemperature, roomTemperatureZone2);
|
|
1779
|
+
this.flowTemperatureZone2SensorService?.updateCharacteristic(Characteristic.CurrentTemperature, flowTemperatureZone2);
|
|
1780
|
+
this.returnTemperatureZone2SensorService?.updateCharacteristic(Characteristic.CurrentTemperature, returnTemperatureZone2);
|
|
1831
1781
|
break;
|
|
1832
1782
|
};
|
|
1833
1783
|
|
|
@@ -1886,18 +1836,14 @@ class DeviceAtw extends EventEmitter {
|
|
|
1886
1836
|
&& presetData.SetCoolFlowTemperatureZone1 === setCoolFlowTemperatureZone1
|
|
1887
1837
|
&& presetData.SetCoolFlowTemperatureZone2 === setCoolFlowTemperatureZone2) : false;
|
|
1888
1838
|
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
this.presetsServices[i]
|
|
1892
|
-
.updateCharacteristic(characteristicType, preset.state)
|
|
1893
|
-
};
|
|
1839
|
+
const characteristicType = preset.characteristicType;
|
|
1840
|
+
this.presetsServices?.[i]?.updateCharacteristic(characteristicType, preset.state);
|
|
1894
1841
|
});
|
|
1895
1842
|
};
|
|
1896
1843
|
|
|
1897
1844
|
//update buttons state
|
|
1898
1845
|
if (this.buttonsConfiguredCount > 0) {
|
|
1899
|
-
|
|
1900
|
-
const button = this.buttonsConfigured[i];
|
|
1846
|
+
this.buttonsConfigured.forEach((button, i) => {
|
|
1901
1847
|
const mode = button.mode;
|
|
1902
1848
|
switch (mode) {
|
|
1903
1849
|
case 0: //POWER ON,OFF
|
|
@@ -1973,7 +1919,11 @@ class DeviceAtw extends EventEmitter {
|
|
|
1973
1919
|
this.emit('warn', `Unknown button mode: ${mode} detected`);
|
|
1974
1920
|
break;
|
|
1975
1921
|
};
|
|
1976
|
-
|
|
1922
|
+
|
|
1923
|
+
//update services
|
|
1924
|
+
const characteristicType = button.characteristicType;
|
|
1925
|
+
this.buttonsServices?.[i]?.updateCharacteristic(characteristicType, button.state);
|
|
1926
|
+
});
|
|
1977
1927
|
};
|
|
1978
1928
|
})
|
|
1979
1929
|
.on('success', (success) => this.emit('success', success))
|
package/src/deviceerv.js
CHANGED
|
@@ -44,8 +44,8 @@ class DeviceErv extends EventEmitter {
|
|
|
44
44
|
//presets configured
|
|
45
45
|
this.presetsConfigured = [];
|
|
46
46
|
for (const preset of this.presets) {
|
|
47
|
-
const displayType = preset.displayType
|
|
48
|
-
if (displayType
|
|
47
|
+
const displayType = preset.displayType;
|
|
48
|
+
if (!displayType) {
|
|
49
49
|
continue;
|
|
50
50
|
};
|
|
51
51
|
|
|
@@ -63,8 +63,8 @@ class DeviceErv extends EventEmitter {
|
|
|
63
63
|
//buttons configured
|
|
64
64
|
this.buttonsConfigured = [];
|
|
65
65
|
for (const button of this.buttons) {
|
|
66
|
-
const displayType = button.displayType
|
|
67
|
-
if (displayType
|
|
66
|
+
const displayType = button.displayType;
|
|
67
|
+
if (!displayType) {
|
|
68
68
|
continue;
|
|
69
69
|
};
|
|
70
70
|
|
|
@@ -1038,18 +1038,16 @@ class DeviceErv extends EventEmitter {
|
|
|
1038
1038
|
};
|
|
1039
1039
|
|
|
1040
1040
|
//update characteristics
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
const updateDefHeat = hasHeatOperationMode ? this.melCloudService.updateCharacteristic(Characteristic.HeatingThresholdTemperature, defaultHeatingSetTemperature) : false;
|
|
1052
|
-
};
|
|
1041
|
+
this.melCloudService
|
|
1042
|
+
?.updateCharacteristic(Characteristic.Active, power)
|
|
1043
|
+
.updateCharacteristic(Characteristic.CurrentHeaterCoolerState, obj.currentOperationMode)
|
|
1044
|
+
.updateCharacteristic(Characteristic.TargetHeaterCoolerState, obj.targetOperationMode)
|
|
1045
|
+
.updateCharacteristic(Characteristic.CurrentTemperature, roomTemperature)
|
|
1046
|
+
.updateCharacteristic(Characteristic.RotationSpeed, obj.fanSpeed)
|
|
1047
|
+
.updateCharacteristic(Characteristic.LockPhysicalControls, obj.lockPhysicalControl)
|
|
1048
|
+
.updateCharacteristic(Characteristic.TemperatureDisplayUnits, obj.useFahrenheit);
|
|
1049
|
+
const updateDefCool = hasCoolOperationMode ? this.melCloudService?.updateCharacteristic(Characteristic.CoolingThresholdTemperature, defaultCoolingSetTemperature) : false;
|
|
1050
|
+
const updateDefHeat = hasHeatOperationMode ? this.melCloudService?.updateCharacteristic(Characteristic.HeatingThresholdTemperature, defaultHeatingSetTemperature) : false;
|
|
1053
1051
|
break;
|
|
1054
1052
|
case 2: //Thermostat
|
|
1055
1053
|
//operation mode - 0, HEAT, 2, COOL, 4, 5, 6, FAN, AUTO
|
|
@@ -1088,59 +1086,36 @@ class DeviceErv extends EventEmitter {
|
|
|
1088
1086
|
obj.operationModeSetPropsValidValues = hasAutoVentilationMode ? (hasBypassVentilationMode ? [0, 1, 2, 3] : [0, 2, 3]) : (hasBypassVentilationMode ? [0, 1, 2] : [0, 2]);
|
|
1089
1087
|
|
|
1090
1088
|
//update characteristics
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
.updateCharacteristic(Characteristic.TemperatureDisplayUnits, obj.useFahrenheit);
|
|
1098
|
-
};
|
|
1089
|
+
this.melCloudService
|
|
1090
|
+
?.updateCharacteristic(Characteristic.CurrentHeatingCoolingState, obj.currentOperationMode)
|
|
1091
|
+
.updateCharacteristic(Characteristic.TargetHeatingCoolingState, obj.targetOperationMode)
|
|
1092
|
+
.updateCharacteristic(Characteristic.CurrentTemperature, roomTemperature)
|
|
1093
|
+
.updateCharacteristic(Characteristic.TargetTemperature, setTemperature)
|
|
1094
|
+
.updateCharacteristic(Characteristic.TemperatureDisplayUnits, obj.useFahrenheit);
|
|
1099
1095
|
break;
|
|
1100
1096
|
};
|
|
1101
1097
|
this.accessory = obj;
|
|
1102
1098
|
|
|
1103
1099
|
//update temperature sensors
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
};
|
|
1108
|
-
|
|
1109
|
-
if (this.outdoorTemperatureSensorService) {
|
|
1110
|
-
this.outdoorTemperatureSensorService
|
|
1111
|
-
.updateCharacteristic(Characteristic.CurrentTemperature, outdoorTemperature)
|
|
1112
|
-
};
|
|
1113
|
-
|
|
1114
|
-
if (this.supplyTemperatureSensorService) {
|
|
1115
|
-
this.supplyTemperatureSensorService
|
|
1116
|
-
.updateCharacteristic(Characteristic.CurrentTemperature, supplyTemperature)
|
|
1117
|
-
};
|
|
1100
|
+
this.roomTemperatureSensorService?.updateCharacteristic(Characteristic.CurrentTemperature, roomTemperature);
|
|
1101
|
+
this.outdoorTemperatureSensorService?.updateCharacteristic(Characteristic.CurrentTemperature, outdoorTemperature);
|
|
1102
|
+
this.supplyTemperatureSensorService?.updateCharacteristic(Characteristic.CurrentTemperature, supplyTemperature);
|
|
1118
1103
|
|
|
1119
1104
|
//update core maintenance
|
|
1120
|
-
|
|
1121
|
-
this.coreMaintenanceService
|
|
1122
|
-
.updateCharacteristic(Characteristic.FilterChangeIndication, coreMaintenanceRequired)
|
|
1123
|
-
}
|
|
1105
|
+
this.coreMaintenanceService?.updateCharacteristic(Characteristic.FilterChangeIndication, coreMaintenanceRequired);
|
|
1124
1106
|
|
|
1125
1107
|
//update filter maintenance
|
|
1126
|
-
|
|
1127
|
-
this.filterMaintenanceService
|
|
1128
|
-
.updateCharacteristic(Characteristic.FilterChangeIndication, filterMaintenanceRequired)
|
|
1129
|
-
}
|
|
1108
|
+
this.filterMaintenanceService?.updateCharacteristic(Characteristic.FilterChangeIndication, filterMaintenanceRequired);
|
|
1130
1109
|
|
|
1131
1110
|
//update CO2 sensor
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
.updateCharacteristic(Characteristic.CarbonDioxideLevel, roomCO2Level)
|
|
1136
|
-
}
|
|
1111
|
+
this.carbonDioxideSensorService
|
|
1112
|
+
?.updateCharacteristic(Characteristic.CarbonDioxideDetected, roomCO2Detected)
|
|
1113
|
+
.updateCharacteristic(Characteristic.CarbonDioxideLevel, roomCO2Level);
|
|
1137
1114
|
|
|
1138
1115
|
//update PM2.5 sensor
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
.updateCharacteristic(Characteristic.PM2_5Density, pM25Level)
|
|
1143
|
-
}
|
|
1116
|
+
this.airQualitySensorService
|
|
1117
|
+
?.updateCharacteristic(Characteristic.AirQuality, pM25AirQuality)
|
|
1118
|
+
.updateCharacteristic(Characteristic.PM2_5Density, pM25Level);
|
|
1144
1119
|
|
|
1145
1120
|
//update presets state
|
|
1146
1121
|
if (this.presetsConfigured.length > 0) {
|
|
@@ -1153,11 +1128,8 @@ class DeviceErv extends EventEmitter {
|
|
|
1153
1128
|
&& presetData.VentilationMode === ventilationMode
|
|
1154
1129
|
&& presetData.FanSpeed === setFanSpeed) : false;
|
|
1155
1130
|
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
this.presetsServices[i]
|
|
1159
|
-
.updateCharacteristic(characteristicType, preset.state)
|
|
1160
|
-
};
|
|
1131
|
+
const characteristicType = preset.characteristicType;
|
|
1132
|
+
this.presetsServices?.[i]?.updateCharacteristic(characteristicType, preset.state);
|
|
1161
1133
|
});
|
|
1162
1134
|
};
|
|
1163
1135
|
|
|
@@ -1214,11 +1186,8 @@ class DeviceErv extends EventEmitter {
|
|
|
1214
1186
|
};
|
|
1215
1187
|
|
|
1216
1188
|
//update services
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
this.buttonsServices[i]
|
|
1220
|
-
.updateCharacteristic(characteristicType, button.state)
|
|
1221
|
-
};
|
|
1189
|
+
const characteristicType = button.characteristicType;
|
|
1190
|
+
this.buttonsServices?.[i]?.updateCharacteristic(characteristicType, button.state);
|
|
1222
1191
|
});
|
|
1223
1192
|
};
|
|
1224
1193
|
|
|
@@ -1260,7 +1229,7 @@ class DeviceErv extends EventEmitter {
|
|
|
1260
1229
|
await this.melCloudErv.checkState();
|
|
1261
1230
|
|
|
1262
1231
|
//prepare accessory
|
|
1263
|
-
const accessory = await this.prepareAccessory(
|
|
1232
|
+
const accessory = await this.prepareAccessory();
|
|
1264
1233
|
return accessory;
|
|
1265
1234
|
} catch (error) {
|
|
1266
1235
|
throw new Error(`Start error: ${error}`);
|
package/src/functions.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { promises as fsPromises } from 'fs';
|
|
2
|
+
|
|
3
|
+
class Functions {
|
|
4
|
+
constructor(config) {
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
async saveData(path, data) {
|
|
8
|
+
try {
|
|
9
|
+
data = JSON.stringify(data, null, 2);
|
|
10
|
+
await fsPromises.writeFile(path, data);
|
|
11
|
+
return true;
|
|
12
|
+
} catch (error) {
|
|
13
|
+
throw new Error(`Save data error: ${error}`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async readData(path) {
|
|
18
|
+
try {
|
|
19
|
+
const data = await fsPromises.readFile(path);
|
|
20
|
+
return data;
|
|
21
|
+
} catch (error) {
|
|
22
|
+
throw new Error(`Read data error: ${error}`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async scaleValue(value, inMin, inMax, outMin, outMax) {
|
|
27
|
+
const scaledValue = parseFloat((((Math.max(inMin, Math.min(inMax, value)) - inMin) * (outMax - outMin)) / (inMax - inMin) + outMin).toFixed(0));
|
|
28
|
+
return scaledValue;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export default Functions
|
package/src/melcloud.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { promises as fsPromises } from 'fs';
|
|
2
1
|
import { Agent } from 'https';
|
|
3
2
|
import axios from 'axios';
|
|
4
3
|
import EventEmitter from 'events';
|
|
5
4
|
import ImpulseGenerator from './impulsegenerator.js';
|
|
5
|
+
import Functions from './functions.js';
|
|
6
6
|
import { ApiUrls } from './constants.js';
|
|
7
7
|
|
|
8
8
|
class MelCloud extends EventEmitter {
|
|
@@ -15,6 +15,7 @@ class MelCloud extends EventEmitter {
|
|
|
15
15
|
this.requestConfig = requestConfig;
|
|
16
16
|
this.devicesId = [];
|
|
17
17
|
this.contextKey = '';
|
|
18
|
+
this.functions = new Functions();
|
|
18
19
|
|
|
19
20
|
this.options = {
|
|
20
21
|
data: {
|
|
@@ -42,8 +43,73 @@ class MelCloud extends EventEmitter {
|
|
|
42
43
|
};
|
|
43
44
|
};
|
|
44
45
|
|
|
46
|
+
async chackDevicesList(contextKey) {
|
|
47
|
+
try {
|
|
48
|
+
//create axios instance get
|
|
49
|
+
const axiosInstanceGet = axios.create({
|
|
50
|
+
method: 'GET',
|
|
51
|
+
baseURL: ApiUrls.BaseURL,
|
|
52
|
+
timeout: 10000,
|
|
53
|
+
headers: {
|
|
54
|
+
'X-MitsContextKey': contextKey
|
|
55
|
+
},
|
|
56
|
+
maxContentLength: 100000000,
|
|
57
|
+
maxBodyLength: 1000000000,
|
|
58
|
+
withCredentials: true,
|
|
59
|
+
httpsAgent: new Agent({
|
|
60
|
+
keepAlive: false,
|
|
61
|
+
rejectUnauthorized: false
|
|
62
|
+
})
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
if (this.enableDebugMode) this.emit('debug', `Scanning for devices`);
|
|
66
|
+
const listDevicesData = await axiosInstanceGet(ApiUrls.ListDevices);
|
|
67
|
+
const buildingsList = listDevicesData.data;
|
|
68
|
+
if (this.enableDebugMode) this.emit('debug', `Buildings: ${JSON.stringify(buildingsList, null, 2)}`);
|
|
69
|
+
|
|
70
|
+
if (!buildingsList) {
|
|
71
|
+
this.emit('warn', `No building found`);
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
//save buildings to the file
|
|
76
|
+
await this.functions.saveData(this.buildingsFile, buildingsList);
|
|
77
|
+
if (this.enableDebugMode) this.emit('debug', `Buildings list saved`);
|
|
78
|
+
|
|
79
|
+
//read buildings structure and get the devices
|
|
80
|
+
const devices = [];
|
|
81
|
+
for (const building of buildingsList) {
|
|
82
|
+
const buildingStructure = building.Structure;
|
|
83
|
+
|
|
84
|
+
//get all devices from the building structure
|
|
85
|
+
const allDevices = [
|
|
86
|
+
...buildingStructure.Floors.flatMap(floor => [...floor.Areas.flatMap(area => area.Devices), ...floor.Devices]),
|
|
87
|
+
...buildingStructure.Areas.flatMap(area => area.Devices),
|
|
88
|
+
...buildingStructure.Devices
|
|
89
|
+
];
|
|
90
|
+
|
|
91
|
+
//add all devices to the devices array
|
|
92
|
+
devices.push(...allDevices);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const devicesCount = devices.length;
|
|
96
|
+
if (devicesCount === 0) {
|
|
97
|
+
this.emit('warn', `No devices found`);
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
//save buildings to the file
|
|
102
|
+
await this.functions.saveData(this.devicesFile, devices);
|
|
103
|
+
if (this.enableDebugMode) this.emit('debug', `${devicesCount} devices saved`);
|
|
104
|
+
|
|
105
|
+
return devices;
|
|
106
|
+
} catch (error) {
|
|
107
|
+
throw new Error(`Check devices list error: ${error}`);
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
45
111
|
async connect() {
|
|
46
|
-
|
|
112
|
+
if (this.enableDebugMode) this.emit('debug', `Connecting to MELCloud`);
|
|
47
113
|
|
|
48
114
|
try {
|
|
49
115
|
const axiosInstanceLogin = axios.create({
|
|
@@ -75,7 +141,7 @@ class MelCloud extends EventEmitter {
|
|
|
75
141
|
MapLongitude: 'removed',
|
|
76
142
|
MapLatitude: 'removed'
|
|
77
143
|
};
|
|
78
|
-
|
|
144
|
+
if (this.enableDebugMode) this.emit('debug', `MELCloud Info: ${JSON.stringify(debugData, null, 2)}`);
|
|
79
145
|
|
|
80
146
|
if (contextKey === undefined || contextKey === null) {
|
|
81
147
|
this.emit('warn', `Context key: ${contextKey}, missing`)
|
|
@@ -101,7 +167,7 @@ class MelCloud extends EventEmitter {
|
|
|
101
167
|
});
|
|
102
168
|
|
|
103
169
|
//save melcloud info to the file
|
|
104
|
-
await this.saveData(this.accountFile, accountInfo);
|
|
170
|
+
await this.functions.saveData(this.accountFile, accountInfo);
|
|
105
171
|
|
|
106
172
|
//emit connect success
|
|
107
173
|
this.emit('success', `Connect to MELCloud Success`)
|
|
@@ -118,81 +184,6 @@ class MelCloud extends EventEmitter {
|
|
|
118
184
|
};
|
|
119
185
|
}
|
|
120
186
|
|
|
121
|
-
async chackDevicesList(contextKey) {
|
|
122
|
-
try {
|
|
123
|
-
//create axios instance get
|
|
124
|
-
const axiosInstanceGet = axios.create({
|
|
125
|
-
method: 'GET',
|
|
126
|
-
baseURL: ApiUrls.BaseURL,
|
|
127
|
-
timeout: 10000,
|
|
128
|
-
headers: {
|
|
129
|
-
'X-MitsContextKey': contextKey
|
|
130
|
-
},
|
|
131
|
-
maxContentLength: 100000000,
|
|
132
|
-
maxBodyLength: 1000000000,
|
|
133
|
-
withCredentials: true,
|
|
134
|
-
httpsAgent: new Agent({
|
|
135
|
-
keepAlive: false,
|
|
136
|
-
rejectUnauthorized: false
|
|
137
|
-
})
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
if (this.enableDebugMode) this.emit('debug', `Scanning for devices`);
|
|
141
|
-
const listDevicesData = await axiosInstanceGet(ApiUrls.ListDevices);
|
|
142
|
-
const buildingsList = listDevicesData.data;
|
|
143
|
-
if (this.enableDebugMode) this.emit('debug', `Buildings: ${JSON.stringify(buildingsList, null, 2)}`);
|
|
144
|
-
|
|
145
|
-
if (!buildingsList) {
|
|
146
|
-
this.emit('warn', `No building found`);
|
|
147
|
-
return null;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
//save buildings to the file
|
|
151
|
-
await this.saveData(this.buildingsFile, buildingsList);
|
|
152
|
-
if (this.enableDebugMode) this.emit('debug', `Buildings list saved`);
|
|
153
|
-
|
|
154
|
-
//read buildings structure and get the devices
|
|
155
|
-
const devices = [];
|
|
156
|
-
for (const building of buildingsList) {
|
|
157
|
-
const buildingStructure = building.Structure;
|
|
158
|
-
|
|
159
|
-
//get all devices from the building structure
|
|
160
|
-
const allDevices = [
|
|
161
|
-
...buildingStructure.Floors.flatMap(floor => [...floor.Areas.flatMap(area => area.Devices), ...floor.Devices]),
|
|
162
|
-
...buildingStructure.Areas.flatMap(area => area.Devices),
|
|
163
|
-
...buildingStructure.Devices
|
|
164
|
-
];
|
|
165
|
-
|
|
166
|
-
//add all devices to the devices array
|
|
167
|
-
devices.push(...allDevices);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
const devicesCount = devices.length;
|
|
171
|
-
if (devicesCount === 0) {
|
|
172
|
-
this.emit('warn', `No devices found`);
|
|
173
|
-
return null;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
//save buildings to the file
|
|
177
|
-
await this.saveData(this.devicesFile, devices);
|
|
178
|
-
if (this.enableDebugMode) this.emit('debug', `${devicesCount} devices saved`);
|
|
179
|
-
|
|
180
|
-
return devices;
|
|
181
|
-
} catch (error) {
|
|
182
|
-
throw new Error(`Check devices list error: ${error}`);
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
async saveData(path, data) {
|
|
187
|
-
try {
|
|
188
|
-
await fsPromises.writeFile(path, JSON.stringify(data, null, 2));
|
|
189
|
-
if (this.enableDebugMode) this.emit('debug', `Data saved to: ${path}`);
|
|
190
|
-
return true;
|
|
191
|
-
} catch (error) {
|
|
192
|
-
throw new Error(`Save data error: ${error}`);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
187
|
async send(accountInfo) {
|
|
197
188
|
try {
|
|
198
189
|
const options = {
|
|
@@ -200,7 +191,7 @@ class MelCloud extends EventEmitter {
|
|
|
200
191
|
};
|
|
201
192
|
|
|
202
193
|
await this.axiosInstancePost(ApiUrls.UpdateApplicationOptions, options);
|
|
203
|
-
await this.saveData(this.accountFile, accountInfo);
|
|
194
|
+
await this.functions.saveData(this.accountFile, accountInfo);
|
|
204
195
|
return true;
|
|
205
196
|
} catch (error) {
|
|
206
197
|
throw new Error(`Send data error: ${error}`);
|
package/src/melcloudata.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { promises as fsPromises } from 'fs';
|
|
2
1
|
import { Agent } from 'https';
|
|
3
2
|
import axios from 'axios';
|
|
4
3
|
import EventEmitter from 'events';
|
|
5
4
|
import ImpulseGenerator from './impulsegenerator.js';
|
|
5
|
+
import Functions from './functions.js';
|
|
6
6
|
import { ApiUrls } from './constants.js';
|
|
7
7
|
|
|
8
8
|
class MelCloudAta extends EventEmitter {
|
|
@@ -11,6 +11,7 @@ class MelCloudAta extends EventEmitter {
|
|
|
11
11
|
this.devicesFile = config.devicesFile;
|
|
12
12
|
this.deviceId = config.deviceId;
|
|
13
13
|
this.enableDebugMode = config.enableDebugMode;
|
|
14
|
+
this.functions = new Functions();
|
|
14
15
|
|
|
15
16
|
//set default values
|
|
16
17
|
this.deviceState = {};
|
|
@@ -30,22 +31,36 @@ class MelCloudAta extends EventEmitter {
|
|
|
30
31
|
})
|
|
31
32
|
});
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
this.
|
|
35
|
-
|
|
34
|
+
//lock flags
|
|
35
|
+
this.locks = {
|
|
36
|
+
checkState: false,
|
|
37
|
+
};
|
|
38
|
+
this.impulseGenerator = new ImpulseGenerator()
|
|
39
|
+
.on('checkState', () => this.handleWithLock('checkState', async () => {
|
|
36
40
|
await this.checkState();
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
}))
|
|
42
|
+
.on('state', (state) => {
|
|
43
|
+
this.emit('success', `Impulse generator ${state ? 'started' : 'stopped'}.`);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async handleWithLock(lockKey, fn) {
|
|
48
|
+
if (this.locks[lockKey]) return;
|
|
49
|
+
|
|
50
|
+
this.locks[lockKey] = true;
|
|
51
|
+
try {
|
|
52
|
+
await fn();
|
|
53
|
+
} catch (error) {
|
|
54
|
+
this.emit('error', `Inpulse generator error: ${error}`);
|
|
55
|
+
} finally {
|
|
56
|
+
this.locks[lockKey] = false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
44
59
|
|
|
45
60
|
async checkState() {
|
|
46
61
|
try {
|
|
47
62
|
//read device info from file
|
|
48
|
-
const devicesData = await this.readData(this.devicesFile);
|
|
63
|
+
const devicesData = await this.functions.readData(this.devicesFile);
|
|
49
64
|
|
|
50
65
|
if (!Array.isArray(devicesData)) {
|
|
51
66
|
this.emit('warn', `Device data not found`);
|
|
@@ -361,25 +376,6 @@ class MelCloudAta extends EventEmitter {
|
|
|
361
376
|
};
|
|
362
377
|
};
|
|
363
378
|
|
|
364
|
-
|
|
365
|
-
async readData(path) {
|
|
366
|
-
try {
|
|
367
|
-
const savedData = await fsPromises.readFile(path)
|
|
368
|
-
if (savedData.toString().trim().length === 0) {
|
|
369
|
-
return null;
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
try {
|
|
373
|
-
const data = JSON.parse(savedData);
|
|
374
|
-
return data;
|
|
375
|
-
} catch (error) {
|
|
376
|
-
throw new Error(`Parse JSON error: ${error}`);
|
|
377
|
-
}
|
|
378
|
-
} catch (error) {
|
|
379
|
-
throw new Error(`Read data error: ${error}`);
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
|
|
383
379
|
async send(deviceData, displayMode) {
|
|
384
380
|
try {
|
|
385
381
|
//set target temp based on display mode and operation mode
|
package/src/melcloudatw.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { promises as fsPromises } from 'fs';
|
|
2
1
|
import { Agent } from 'https';
|
|
3
2
|
import axios from 'axios';
|
|
4
3
|
import EventEmitter from 'events';
|
|
5
4
|
import ImpulseGenerator from './impulsegenerator.js';
|
|
5
|
+
import Functions from './functions.js';
|
|
6
6
|
import { ApiUrls } from './constants.js';
|
|
7
7
|
|
|
8
8
|
class MelCloudAtw extends EventEmitter {
|
|
@@ -11,6 +11,7 @@ class MelCloudAtw extends EventEmitter {
|
|
|
11
11
|
this.devicesFile = config.devicesFile;
|
|
12
12
|
this.deviceId = config.deviceId;
|
|
13
13
|
this.enableDebugMode = config.enableDebugMode;
|
|
14
|
+
this.functions = new Functions();
|
|
14
15
|
|
|
15
16
|
//set default values
|
|
16
17
|
this.deviceState = {};
|
|
@@ -30,22 +31,36 @@ class MelCloudAtw extends EventEmitter {
|
|
|
30
31
|
})
|
|
31
32
|
});
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
this.
|
|
35
|
-
|
|
34
|
+
//lock flags
|
|
35
|
+
this.locks = {
|
|
36
|
+
checkState: false,
|
|
37
|
+
};
|
|
38
|
+
this.impulseGenerator = new ImpulseGenerator()
|
|
39
|
+
.on('checkState', () => this.handleWithLock('checkState', async () => {
|
|
36
40
|
await this.checkState();
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
}))
|
|
42
|
+
.on('state', (state) => {
|
|
43
|
+
this.emit('success', `Impulse generator ${state ? 'started' : 'stopped'}.`);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async handleWithLock(lockKey, fn) {
|
|
48
|
+
if (this.locks[lockKey]) return;
|
|
49
|
+
|
|
50
|
+
this.locks[lockKey] = true;
|
|
51
|
+
try {
|
|
52
|
+
await fn();
|
|
53
|
+
} catch (error) {
|
|
54
|
+
this.emit('error', `Inpulse generator error: ${error}`);
|
|
55
|
+
} finally {
|
|
56
|
+
this.locks[lockKey] = false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
44
59
|
|
|
45
60
|
async checkState() {
|
|
46
61
|
try {
|
|
47
62
|
//read device info from file
|
|
48
|
-
const devicesData = await this.readData(this.devicesFile);
|
|
63
|
+
const devicesData = await this.functions.readData(this.devicesFile);
|
|
49
64
|
|
|
50
65
|
if (!Array.isArray(devicesData)) {
|
|
51
66
|
this.emit('warn', `Device data not found`);
|
|
@@ -425,24 +440,6 @@ class MelCloudAtw extends EventEmitter {
|
|
|
425
440
|
};
|
|
426
441
|
};
|
|
427
442
|
|
|
428
|
-
async readData(path) {
|
|
429
|
-
try {
|
|
430
|
-
const savedData = await fsPromises.readFile(path)
|
|
431
|
-
if (savedData.toString().trim().length === 0) {
|
|
432
|
-
return null;
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
try {
|
|
436
|
-
const data = JSON.parse(savedData);
|
|
437
|
-
return data;
|
|
438
|
-
} catch (error) {
|
|
439
|
-
throw new Error(`Parse JSON error: ${error}`);
|
|
440
|
-
}
|
|
441
|
-
} catch (error) {
|
|
442
|
-
throw new Error(`Read data error: ${error}`);
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
|
|
446
443
|
async send(deviceData) {
|
|
447
444
|
try {
|
|
448
445
|
//prevent to set out of range temp
|
package/src/melclouderv.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { promises as fsPromises } from 'fs';
|
|
2
1
|
import { Agent } from 'https';
|
|
3
2
|
import axios from 'axios';
|
|
4
3
|
import EventEmitter from 'events';
|
|
5
4
|
import ImpulseGenerator from './impulsegenerator.js';
|
|
5
|
+
import Functions from './functions.js';
|
|
6
6
|
import { ApiUrls } from './constants.js';
|
|
7
7
|
|
|
8
8
|
class MelCloudErv extends EventEmitter {
|
|
@@ -11,6 +11,7 @@ class MelCloudErv extends EventEmitter {
|
|
|
11
11
|
this.devicesFile = config.devicesFile;
|
|
12
12
|
this.deviceId = config.deviceId;
|
|
13
13
|
this.enableDebugMode = config.enableDebugMode;
|
|
14
|
+
this.functions = new Functions();
|
|
14
15
|
|
|
15
16
|
//set default values
|
|
16
17
|
this.deviceState = {};
|
|
@@ -30,22 +31,36 @@ class MelCloudErv extends EventEmitter {
|
|
|
30
31
|
})
|
|
31
32
|
});
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
this.
|
|
35
|
-
|
|
34
|
+
//lock flags
|
|
35
|
+
this.locks = {
|
|
36
|
+
checkState: false,
|
|
37
|
+
};
|
|
38
|
+
this.impulseGenerator = new ImpulseGenerator()
|
|
39
|
+
.on('checkState', () => this.handleWithLock('checkState', async () => {
|
|
36
40
|
await this.checkState();
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
}))
|
|
42
|
+
.on('state', (state) => {
|
|
43
|
+
this.emit('success', `Impulse generator ${state ? 'started' : 'stopped'}.`);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async handleWithLock(lockKey, fn) {
|
|
48
|
+
if (this.locks[lockKey]) return;
|
|
49
|
+
|
|
50
|
+
this.locks[lockKey] = true;
|
|
51
|
+
try {
|
|
52
|
+
await fn();
|
|
53
|
+
} catch (error) {
|
|
54
|
+
this.emit('error', `Inpulse generator error: ${error}`);
|
|
55
|
+
} finally {
|
|
56
|
+
this.locks[lockKey] = false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
44
59
|
|
|
45
60
|
async checkState() {
|
|
46
61
|
try {
|
|
47
62
|
//read device info from file
|
|
48
|
-
const devicesData = await this.readData(this.devicesFile);
|
|
63
|
+
const devicesData = await this.functions.readData(this.devicesFile);
|
|
49
64
|
|
|
50
65
|
if (!Array.isArray(devicesData)) {
|
|
51
66
|
this.emit('warn', `Device data not found`);
|
|
@@ -349,24 +364,6 @@ class MelCloudErv extends EventEmitter {
|
|
|
349
364
|
};
|
|
350
365
|
};
|
|
351
366
|
|
|
352
|
-
async readData(path) {
|
|
353
|
-
try {
|
|
354
|
-
const savedData = await fsPromises.readFile(path)
|
|
355
|
-
if (savedData.toString().trim().length === 0) {
|
|
356
|
-
return null;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
try {
|
|
360
|
-
const data = JSON.parse(savedData);
|
|
361
|
-
return data;
|
|
362
|
-
} catch (error) {
|
|
363
|
-
throw new Error(`Parse JSON error: ${error}`);
|
|
364
|
-
}
|
|
365
|
-
} catch (error) {
|
|
366
|
-
throw new Error(`Read data error: ${error}`);
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
|
|
370
367
|
async send(deviceData, displayMode) {
|
|
371
368
|
try {
|
|
372
369
|
//set target temp based on display mode and ventilation mode
|