homebridge-melcloud-control 4.3.11-beta.1 → 4.3.11-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/package.json +1 -1
- package/src/constants.js +1 -1
- package/src/deviceata.js +37 -35
- package/src/deviceatw.js +2 -2
- package/src/deviceerv.js +2 -2
- package/src/functions.js +18 -44
- package/src/melcloud.js +1 -1
- package/src/melcloudata.js +3 -7
- package/src/melcloudatw.js +3 -7
- package/src/melclouderv.js +3 -7
- package/src/melcloudhome.js +19 -12
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.11-beta.
|
|
4
|
+
"version": "4.3.11-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
|
@@ -60,7 +60,7 @@ export const AirConditioner = {
|
|
|
60
60
|
SystemMapEnumToString: { 0: "Air Conditioner Off", 1: "Air Conditioner On", 2: "Air Conditioner Offline" },
|
|
61
61
|
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 },
|
|
62
62
|
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" },
|
|
63
|
-
OperationModeMapEnumToEnumWs: { 0: 0, 1: 1, 2: 2, 3: 3, 4: 7, 5: 8
|
|
63
|
+
OperationModeMapEnumToEnumWs: { 0: 0, 1: 1, 2: 2, 3: 3, 4: 7, 5: 8 },
|
|
64
64
|
FanSpeedMapStringToEnum: { "Auto": 0, "One": 1, "Two": 2, "Three": 3, "Four": 4, "Five": 5, "0": 0, "1": 1, "2": 2, "3": 3, "4": 4, "5": 5 },
|
|
65
65
|
FanSpeedMapEnumToString: { 0: "Auto", 1: "One", 2: "Two", 3: "Three", 4: "Four", 5: "Five" },
|
|
66
66
|
SetFanSpeedMapStringToEnum: { "Auto": 0, "One": 1, "Two": 2, "Three": 3, "Four": 4, "Five": 5, "0": 0, "1": 1, "2": 2, "3": 3, "4": 4, "5": 5 },
|
package/src/deviceata.js
CHANGED
|
@@ -142,7 +142,7 @@ class DeviceAta extends EventEmitter {
|
|
|
142
142
|
});
|
|
143
143
|
}
|
|
144
144
|
} catch (error) {
|
|
145
|
-
this.emit('warn', `RESTFul integration start error: ${error}`);
|
|
145
|
+
if (this.logWarn) this.emit('warn', `RESTFul integration start error: ${error}`);
|
|
146
146
|
};
|
|
147
147
|
}
|
|
148
148
|
|
|
@@ -186,7 +186,7 @@ class DeviceAta extends EventEmitter {
|
|
|
186
186
|
});
|
|
187
187
|
}
|
|
188
188
|
} catch (error) {
|
|
189
|
-
this.emit('warn', `MQTT integration start error: ${error}`);
|
|
189
|
+
if (this.logWarn) this.emit('warn', `MQTT integration start error: ${error}`);
|
|
190
190
|
};
|
|
191
191
|
}
|
|
192
192
|
|
|
@@ -317,6 +317,7 @@ class DeviceAta extends EventEmitter {
|
|
|
317
317
|
const supportsOutdoorTemperature = this.accessory.supportsOutdoorTemperature;
|
|
318
318
|
const numberOfFanSpeeds = this.accessory.numberOfFanSpeeds;
|
|
319
319
|
const supportsSwingFunction = this.accessory.supportsSwingFunction;
|
|
320
|
+
const supportsVideWane = this.accessory.supportsVideWane;
|
|
320
321
|
const autoDryFanMode = [this.accessory.operationMode, 8, supportsDry ? 2 : 8, 7][this.autoDryFanMode]; //NONE, AUTO - 8, DRY - 2, FAN - 7
|
|
321
322
|
const heatDryFanMode = [this.accessory.operationMode, 1, supportsDry ? 2 : 1, 7][this.heatDryFanMode]; //NONE, HEAT - 1, DRY - 2, FAN - 7
|
|
322
323
|
const coolDryFanMode = [this.accessory.operationMode, 3, supportsDry ? 2 : 3, 7][this.coolDryFanMode]; //NONE, COOL - 3, DRY - 2, FAN - 7
|
|
@@ -446,7 +447,7 @@ class DeviceAta extends EventEmitter {
|
|
|
446
447
|
})
|
|
447
448
|
.onSet(async (value) => {
|
|
448
449
|
try {
|
|
449
|
-
deviceData.Device.VaneHorizontalDirection = value ? 12 : 0;
|
|
450
|
+
if (supportsVideWane) deviceData.Device.VaneHorizontalDirection = value ? 12 : 0;
|
|
450
451
|
deviceData.Device.VaneVerticalDirection = value ? 7 : 0;
|
|
451
452
|
if (this.logInfo) this.emit('info', `Set air direction mode: ${AirConditioner.AirDirectionMapEnumToString[value]}`);
|
|
452
453
|
await this.melCloudAta.send(this.accountType, this.displayType, deviceData, AirConditioner.EffectiveFlags.VaneVerticalVaneHorizontal);
|
|
@@ -1129,91 +1130,91 @@ class DeviceAta extends EventEmitter {
|
|
|
1129
1130
|
case 7: //OPERATING MODE DRY CONTROL HIDE
|
|
1130
1131
|
deviceData.HideDryModeControl = state;
|
|
1131
1132
|
break;
|
|
1132
|
-
case 10: //VANE H
|
|
1133
|
+
case 10: //VANE H MODE AUTO
|
|
1133
1134
|
button.previousValue = state ? deviceData.Device.VaneHorizontalDirection : button.previousValue ?? deviceData.Device.VaneHorizontalDirection;
|
|
1134
1135
|
deviceData.Device.Power = true;
|
|
1135
1136
|
deviceData.Device.VaneHorizontalDirection = state ? 0 : button.previousValue;
|
|
1136
1137
|
flag = AirConditioner.EffectiveFlags.PowerVaneHorizontal;
|
|
1137
1138
|
break;
|
|
1138
|
-
case 11: //VANE H
|
|
1139
|
+
case 11: //VANE H MODE 1
|
|
1139
1140
|
button.previousValue = state ? deviceData.Device.VaneHorizontalDirection : button.previousValue ?? deviceData.Device.VaneHorizontalDirection;
|
|
1140
1141
|
deviceData.Device.Power = true;
|
|
1141
1142
|
deviceData.Device.VaneHorizontalDirection = state ? 1 : button.previousValue;
|
|
1142
1143
|
flag = AirConditioner.EffectiveFlags.PowerVaneHorizontal;
|
|
1143
1144
|
break;
|
|
1144
|
-
case 12: //VANE H
|
|
1145
|
+
case 12: //VANE H MODE 2
|
|
1145
1146
|
button.previousValue = state ? deviceData.Device.VaneHorizontalDirection : button.previousValue ?? deviceData.Device.VaneHorizontalDirection;
|
|
1146
1147
|
deviceData.Device.Power = true;
|
|
1147
1148
|
deviceData.Device.VaneHorizontalDirection = state ? 2 : button.previousValue;
|
|
1148
1149
|
flag = AirConditioner.EffectiveFlags.PowerVaneHorizontal;
|
|
1149
1150
|
break;
|
|
1150
|
-
case 13: //VANE H
|
|
1151
|
+
case 13: //VANE H MODE 3
|
|
1151
1152
|
button.previousValue = state ? deviceData.Device.VaneHorizontalDirection : button.previousValue ?? deviceData.Device.VaneHorizontalDirection;
|
|
1152
1153
|
deviceData.Device.Power = true;
|
|
1153
1154
|
deviceData.Device.VaneHorizontalDirection = state ? 3 : button.previousValue;
|
|
1154
1155
|
flag = AirConditioner.EffectiveFlags.PowerVaneHorizontal;
|
|
1155
1156
|
break;
|
|
1156
|
-
case 14: //VANE H
|
|
1157
|
+
case 14: //VANE H MODE 4
|
|
1157
1158
|
button.previousValue = state ? deviceData.Device.VaneHorizontalDirection : button.previousValue ?? deviceData.Device.VaneHorizontalDirection;
|
|
1158
1159
|
deviceData.Device.Power = true;
|
|
1159
1160
|
deviceData.Device.VaneHorizontalDirection = state ? 4 : button.previousValue;
|
|
1160
1161
|
flag = AirConditioner.EffectiveFlags.PowerVaneHorizontal;
|
|
1161
1162
|
break;
|
|
1162
|
-
case 15: //VANE H
|
|
1163
|
+
case 15: //VANE H MODE 5
|
|
1163
1164
|
button.previousValue = state ? deviceData.Device.VaneHorizontalDirection : button.previousValue ?? deviceData.Device.VaneHorizontalDirection;
|
|
1164
1165
|
deviceData.Device.Power = true;
|
|
1165
1166
|
deviceData.Device.VaneHorizontalDirection = state ? 5 : button.previousValue;
|
|
1166
1167
|
flag = AirConditioner.EffectiveFlags.PowerVaneHorizontal;
|
|
1167
1168
|
break;
|
|
1168
|
-
case 16: //VANE H
|
|
1169
|
+
case 16: //VANE H MODE SPLIT
|
|
1169
1170
|
button.previousValue = state ? deviceData.Device.VaneHorizontalDirection : button.previousValue ?? deviceData.Device.VaneHorizontalDirection;
|
|
1170
1171
|
deviceData.Device.Power = true;
|
|
1171
1172
|
deviceData.Device.VaneHorizontalDirection = state ? 8 : button.previousValue;
|
|
1172
1173
|
flag = AirConditioner.EffectiveFlags.PowerVaneHorizontal;
|
|
1173
1174
|
break;
|
|
1174
|
-
case 17: //VANE H
|
|
1175
|
+
case 17: //VANE H MODE SWING
|
|
1175
1176
|
button.previousValue = state ? deviceData.Device.VaneHorizontalDirection : button.previousValue ?? deviceData.Device.VaneHorizontalDirection;
|
|
1176
1177
|
deviceData.Device.Power = true;
|
|
1177
1178
|
deviceData.Device.VaneHorizontalDirection = state ? 12 : button.previousValue;
|
|
1178
1179
|
flag = AirConditioner.EffectiveFlags.PowerVaneHorizontal;
|
|
1179
1180
|
break;
|
|
1180
|
-
case 20: //VANE V
|
|
1181
|
+
case 20: //VANE V MODE AUTO
|
|
1181
1182
|
button.previousValue = state ? deviceData.Device.VaneVerticalDirection : button.previousValue ?? deviceData.Device.VaneVerticalDirection;
|
|
1182
1183
|
deviceData.Device.Power = true;
|
|
1183
1184
|
deviceData.Device.VaneVerticalDirection = state ? 0 : button.previousValue;
|
|
1184
1185
|
flag = AirConditioner.EffectiveFlags.PowerVaneVertical;
|
|
1185
1186
|
break;
|
|
1186
|
-
case 21: //VANE V
|
|
1187
|
+
case 21: //VANE V MODE 1
|
|
1187
1188
|
button.previousValue = state ? deviceData.Device.VaneVerticalDirection : button.previousValue ?? deviceData.Device.VaneVerticalDirection;
|
|
1188
1189
|
deviceData.Device.Power = true;
|
|
1189
1190
|
deviceData.Device.VaneVerticalDirection = state ? 1 : button.previousValue;
|
|
1190
1191
|
flag = AirConditioner.EffectiveFlags.PowerVaneVertical;
|
|
1191
1192
|
break;
|
|
1192
|
-
case 22: //VANE V
|
|
1193
|
+
case 22: //VANE V MODE 2
|
|
1193
1194
|
button.previousValue = state ? deviceData.Device.VaneVerticalDirection : button.previousValue ?? deviceData.Device.VaneVerticalDirection;
|
|
1194
1195
|
deviceData.Device.Power = true;
|
|
1195
1196
|
deviceData.Device.VaneVerticalDirection = state ? 2 : button.previousValue;
|
|
1196
1197
|
flag = AirConditioner.EffectiveFlags.PowerVaneVertical;
|
|
1197
1198
|
break;
|
|
1198
|
-
case 23: //VANE V
|
|
1199
|
+
case 23: //VANE V MODE 3
|
|
1199
1200
|
button.previousValue = state ? deviceData.Device.VaneVerticalDirection : button.previousValue ?? deviceData.Device.VaneVerticalDirection;
|
|
1200
1201
|
deviceData.Device.Power = true;
|
|
1201
1202
|
deviceData.Device.VaneVerticalDirection = state ? 3 : button.previousValue;
|
|
1202
1203
|
flag = AirConditioner.EffectiveFlags.PowerVaneVertical;
|
|
1203
1204
|
break;
|
|
1204
|
-
case 24: //VANE V
|
|
1205
|
+
case 24: //VANE V MODE 4
|
|
1205
1206
|
button.previousValue = state ? deviceData.Device.VaneVerticalDirection : button.previousValue ?? deviceData.Device.VaneVerticalDirection;
|
|
1206
1207
|
deviceData.Device.Power = true;
|
|
1207
1208
|
deviceData.Device.VaneVerticalDirection = state ? 4 : button.previousValue;
|
|
1208
1209
|
flag = AirConditioner.EffectiveFlags.PowerVaneVertical;
|
|
1209
1210
|
break;
|
|
1210
|
-
case 25: //VANE V
|
|
1211
|
+
case 25: //VANE V MODE 5
|
|
1211
1212
|
button.previousValue = state ? deviceData.Device.VaneVerticalDirection : button.previousValue ?? deviceData.Device.VaneVerticalDirection;
|
|
1212
1213
|
deviceData.Device.Power = true;
|
|
1213
1214
|
deviceData.Device.VaneVerticalDirection = state ? 5 : button.previousValue;
|
|
1214
1215
|
flag = AirConditioner.EffectiveFlags.PowerVaneVertical;
|
|
1215
1216
|
break;
|
|
1216
|
-
case 26: //VANE V
|
|
1217
|
+
case 26: //VANE V MODE SWING
|
|
1217
1218
|
button.previousValue = state ? deviceData.Device.VaneVerticalDirection : button.previousValue ?? deviceData.Device.VaneVerticalDirection;
|
|
1218
1219
|
deviceData.Device.Power = true;
|
|
1219
1220
|
deviceData.Device.VaneVerticalDirection = state ? 7 : button.previousValue;
|
|
@@ -1425,6 +1426,7 @@ class DeviceAta extends EventEmitter {
|
|
|
1425
1426
|
const outdoorTemperature = deviceData.Device.OutdoorTemperature;
|
|
1426
1427
|
const isConnected = accountTypeMelcloud ? !deviceData.Device[connectKey] : deviceData.Device[connectKey];
|
|
1427
1428
|
const isInError = deviceData.Device[errorKey];
|
|
1429
|
+
const currentSwingMode = supportsSwingFunction ? (supportsWideVane ? vaneHorizontalDirection === 12 && vaneVerticalDirection === 7 ? 1 : 0 : vaneVerticalDirection === 7 ? 1 : 0) : 0;
|
|
1428
1430
|
|
|
1429
1431
|
//accessory
|
|
1430
1432
|
const obj = {
|
|
@@ -1461,7 +1463,7 @@ class DeviceAta extends EventEmitter {
|
|
|
1461
1463
|
automaticFanSpeed: automaticFanSpeed,
|
|
1462
1464
|
vaneVerticalSwing: vaneVerticalSwing,
|
|
1463
1465
|
vaneHorizontalSwing: vaneHorizontalSwing,
|
|
1464
|
-
currentSwingMode:
|
|
1466
|
+
currentSwingMode: currentSwingMode,
|
|
1465
1467
|
lockPhysicalControl: prohibitSetTemperature && prohibitOperationMode && prohibitPower ? 1 : 0,
|
|
1466
1468
|
temperatureStep: temperatureStep,
|
|
1467
1469
|
useFahrenheit: this.accountInfo.useFahrenheit ? 1 : 0,
|
|
@@ -1753,49 +1755,49 @@ class DeviceAta extends EventEmitter {
|
|
|
1753
1755
|
case 7: //OPERATING MODE DRY CONTROL HIDE
|
|
1754
1756
|
button.state = power ? (hideDryModeControl === true) : false;
|
|
1755
1757
|
break;
|
|
1756
|
-
case 10: //VANE H
|
|
1758
|
+
case 10: //VANE H MODE AUTO
|
|
1757
1759
|
button.state = power ? (vaneHorizontalDirection === 0) : false;
|
|
1758
1760
|
break;
|
|
1759
|
-
case 11: //VANE H
|
|
1761
|
+
case 11: //VANE H MODE 1
|
|
1760
1762
|
button.state = power ? (vaneHorizontalDirection === 1) : false;
|
|
1761
1763
|
break;
|
|
1762
|
-
case 12: //VANE H
|
|
1764
|
+
case 12: //VANE H MODE 2
|
|
1763
1765
|
button.state = power ? (vaneHorizontalDirection === 2) : false;
|
|
1764
1766
|
break;
|
|
1765
|
-
case 13: //VANE H
|
|
1767
|
+
case 13: //VANE H MODE 3
|
|
1766
1768
|
button.state = power ? (vaneHorizontalDirection === 3) : false;
|
|
1767
1769
|
break;
|
|
1768
|
-
case 14: //VANE H
|
|
1770
|
+
case 14: //VANE H MODE 4
|
|
1769
1771
|
button.state = power ? (vaneHorizontalDirection === 4) : false;
|
|
1770
1772
|
break;
|
|
1771
|
-
case 15: //VANE H
|
|
1773
|
+
case 15: //VANE H MODE 5
|
|
1772
1774
|
button.state = power ? (vaneHorizontalDirection === 5) : false;
|
|
1773
1775
|
break;
|
|
1774
|
-
case 16: //VANE H
|
|
1776
|
+
case 16: //VANE H MODE SPLIT
|
|
1775
1777
|
button.state = power ? (vaneHorizontalDirection === 8) : false;
|
|
1776
1778
|
break;
|
|
1777
|
-
case 17: //VANE H
|
|
1779
|
+
case 17: //VANE H MODE SWING
|
|
1778
1780
|
button.state = power ? (vaneHorizontalDirection === 12) : false;
|
|
1779
1781
|
break;
|
|
1780
|
-
case 20: //VANE V
|
|
1782
|
+
case 20: //VANE V MODE AUTO
|
|
1781
1783
|
button.state = power ? (vaneVerticalDirection === 0) : false;
|
|
1782
1784
|
break;
|
|
1783
|
-
case 21: //VANE V
|
|
1785
|
+
case 21: //VANE V MODE 1
|
|
1784
1786
|
button.state = power ? (vaneVerticalDirection === 1) : false;
|
|
1785
1787
|
break;
|
|
1786
|
-
case 22: //VANE V
|
|
1788
|
+
case 22: //VANE V MODE 2
|
|
1787
1789
|
button.state = power ? (vaneVerticalDirection === 2) : false;
|
|
1788
1790
|
break;
|
|
1789
|
-
case 23: //VANE V
|
|
1791
|
+
case 23: //VANE V MODE 3
|
|
1790
1792
|
button.state = power ? (vaneVerticalDirection === 3) : false;
|
|
1791
1793
|
break;
|
|
1792
|
-
case 24: //VANE V
|
|
1794
|
+
case 24: //VANE V MODE 4
|
|
1793
1795
|
button.state = power ? (vaneVerticalDirection === 4) : false;
|
|
1794
1796
|
break;
|
|
1795
|
-
case 25: //VANE V
|
|
1797
|
+
case 25: //VANE V MODE 5
|
|
1796
1798
|
button.state = power ? (vaneVerticalDirection === 5) : false;
|
|
1797
1799
|
break;
|
|
1798
|
-
case 26: //VANE V
|
|
1800
|
+
case 26: //VANE V MODE SWING
|
|
1799
1801
|
button.state = power ? (vaneVerticalDirection === 7) : false;
|
|
1800
1802
|
break;
|
|
1801
1803
|
case 27: //VANE H/V CONTROLS HIDE
|
|
@@ -1859,7 +1861,7 @@ class DeviceAta extends EventEmitter {
|
|
|
1859
1861
|
if (supportsFanSpeed) this.emit('info', `Current fan speed: ${AirConditioner.AktualFanSpeedMapEnumToString[actualFanSpeed]}`);
|
|
1860
1862
|
if (vaneHorizontalDirection !== null) this.emit('info', `Vane horizontal: ${AirConditioner.VaneHorizontalDirectionMapEnumToString[vaneHorizontalDirection]}`);
|
|
1861
1863
|
if (vaneVerticalDirection !== null) this.emit('info', `Vane vertical: ${AirConditioner.VaneVerticalDirectionMapEnumToString[vaneVerticalDirection]}`);
|
|
1862
|
-
if (supportsSwingFunction) this.emit('info', `Air direction: ${AirConditioner.AirDirectionMapEnumToString[
|
|
1864
|
+
if (supportsSwingFunction) this.emit('info', `Air direction: ${AirConditioner.AirDirectionMapEnumToString[currentSwingMode]}`);
|
|
1863
1865
|
this.emit('info', `Temperature display unit: ${obj.temperatureUnit}`);
|
|
1864
1866
|
this.emit('info', `Lock physical controls: ${obj.lockPhysicalControl ? 'Locked' : 'Unlocked'}`);
|
|
1865
1867
|
if (this.accountType === 'melcloudhome') this.emit('info', `Signal strength: ${deviceData.Rssi}dBm`);
|
package/src/deviceatw.js
CHANGED
|
@@ -146,7 +146,7 @@ class DeviceAtw extends EventEmitter {
|
|
|
146
146
|
});
|
|
147
147
|
}
|
|
148
148
|
} catch (error) {
|
|
149
|
-
this.emit('warn', `RESTFul integration start error: ${error}`);
|
|
149
|
+
if (this.logWarn) this.emit('warn', `RESTFul integration start error: ${error}`);
|
|
150
150
|
};
|
|
151
151
|
}
|
|
152
152
|
|
|
@@ -190,7 +190,7 @@ class DeviceAtw extends EventEmitter {
|
|
|
190
190
|
});
|
|
191
191
|
}
|
|
192
192
|
} catch (error) {
|
|
193
|
-
this.emit('warn', `MQTT integration start error: ${error}`);
|
|
193
|
+
if (this.logWarn) this.emit('warn', `MQTT integration start error: ${error}`);
|
|
194
194
|
};
|
|
195
195
|
}
|
|
196
196
|
}
|
package/src/deviceerv.js
CHANGED
|
@@ -138,7 +138,7 @@ class DeviceErv extends EventEmitter {
|
|
|
138
138
|
});
|
|
139
139
|
}
|
|
140
140
|
} catch (error) {
|
|
141
|
-
this.emit('warn', `RESTFul integration start error: ${error}`);
|
|
141
|
+
if (this.logWarn) this.emit('warn', `RESTFul integration start error: ${error}`);
|
|
142
142
|
};
|
|
143
143
|
}
|
|
144
144
|
|
|
@@ -182,7 +182,7 @@ class DeviceErv extends EventEmitter {
|
|
|
182
182
|
});
|
|
183
183
|
}
|
|
184
184
|
} catch (error) {
|
|
185
|
-
this.emit('warn', `MQTT integration start error: ${error}`);
|
|
185
|
+
if (this.logWarn) this.emit('warn', `MQTT integration start error: ${error}`);
|
|
186
186
|
};
|
|
187
187
|
}
|
|
188
188
|
}
|
package/src/functions.js
CHANGED
|
@@ -58,57 +58,39 @@ class Functions extends EventEmitter {
|
|
|
58
58
|
let chromiumPath = '/usr/bin/chromium-browser';
|
|
59
59
|
|
|
60
60
|
try {
|
|
61
|
-
// --- Detect OS ---
|
|
62
61
|
const { stdout: osOut } = await execPromise('uname -s');
|
|
63
62
|
const osName = osOut.trim();
|
|
64
63
|
if (this.logDebug) this.emit('debug', `Detected OS: ${osName}`);
|
|
65
64
|
|
|
66
|
-
// --- Detect Architecture ---
|
|
67
65
|
const { stdout: archOut } = await execPromise('uname -m');
|
|
68
66
|
const arch = archOut.trim();
|
|
69
67
|
if (this.logDebug) this.emit('debug', `Detected architecture: ${arch}`);
|
|
70
68
|
|
|
71
|
-
//
|
|
69
|
+
// Docker detection
|
|
72
70
|
let isDocker = false;
|
|
73
|
-
try {
|
|
74
|
-
await access('/.dockerenv', fs.constants.F_OK); isDocker = true;
|
|
75
|
-
} catch { }
|
|
76
|
-
|
|
71
|
+
try { await access('/.dockerenv', fs.constants.F_OK); isDocker = true; } catch { }
|
|
77
72
|
try {
|
|
78
73
|
const { stdout } = await execPromise('cat /proc/1/cgroup || true');
|
|
79
74
|
if (stdout.includes('docker') || stdout.includes('containerd')) isDocker = true;
|
|
80
75
|
} catch { }
|
|
81
|
-
|
|
82
76
|
if (isDocker && this.logDebug) this.emit('debug', 'Running inside Docker container.');
|
|
83
77
|
|
|
84
|
-
//
|
|
78
|
+
// macOS
|
|
85
79
|
if (osName === 'Darwin') {
|
|
86
80
|
chromiumPath = '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
|
|
87
|
-
try {
|
|
88
|
-
await access(chromiumPath, fs.constants.X_OK);
|
|
89
|
-
return chromiumPath;
|
|
90
|
-
} catch {
|
|
91
|
-
return null;
|
|
92
|
-
}
|
|
81
|
+
try { await access(chromiumPath, fs.constants.X_OK); return chromiumPath; } catch { return null; }
|
|
93
82
|
}
|
|
94
83
|
|
|
95
|
-
//
|
|
96
|
-
if (arch.startsWith('arm')) {
|
|
97
|
-
try {
|
|
98
|
-
|
|
99
|
-
await
|
|
100
|
-
return
|
|
101
|
-
} catch {
|
|
102
|
-
try {
|
|
103
|
-
await execPromise('sudo apt-get update -y && sudo apt-get install -y chromium-browser chromium-codecs-ffmpeg');
|
|
104
|
-
return chromiumPath;
|
|
105
|
-
} catch {
|
|
106
|
-
return null;
|
|
107
|
-
}
|
|
84
|
+
// ARM
|
|
85
|
+
if (arch.startsWith('arm') || arch.startsWith('aarch')) {
|
|
86
|
+
try { await access(chromiumPath, fs.constants.X_OK); return chromiumPath; }
|
|
87
|
+
catch {
|
|
88
|
+
try { await execPromise('sudo apt-get update -y && sudo apt-get install -y chromium-browser chromium-codecs-ffmpeg'); return chromiumPath; }
|
|
89
|
+
catch { return null; }
|
|
108
90
|
}
|
|
109
91
|
}
|
|
110
92
|
|
|
111
|
-
//
|
|
93
|
+
// Linux x64
|
|
112
94
|
if (osName === 'Linux') {
|
|
113
95
|
let systemChromium = null;
|
|
114
96
|
try {
|
|
@@ -116,13 +98,9 @@ class Functions extends EventEmitter {
|
|
|
116
98
|
systemChromium = checkOut.trim() || null;
|
|
117
99
|
} catch { }
|
|
118
100
|
|
|
119
|
-
//
|
|
101
|
+
// Entware (QNAP)
|
|
120
102
|
let entwareExists = false;
|
|
121
|
-
try {
|
|
122
|
-
await access('/opt/bin/opkg', fs.constants.X_OK);
|
|
123
|
-
entwareExists = true;
|
|
124
|
-
} catch { }
|
|
125
|
-
|
|
103
|
+
try { await access('/opt/bin/opkg', fs.constants.X_OK); entwareExists = true; } catch { }
|
|
126
104
|
if (entwareExists) {
|
|
127
105
|
try {
|
|
128
106
|
await execPromise('/opt/bin/opkg update');
|
|
@@ -131,25 +109,21 @@ class Functions extends EventEmitter {
|
|
|
131
109
|
} catch { }
|
|
132
110
|
}
|
|
133
111
|
|
|
134
|
-
//
|
|
135
|
-
const
|
|
112
|
+
// Install missing libs
|
|
113
|
+
const depCommands = [
|
|
136
114
|
'apt-get update -y && apt-get install -y libnspr4 libnss3 libx11-6 libxcomposite1 libxdamage1 libxrandr2 libatk1.0-0 libcups2 libdrm2 libgbm1 libasound2',
|
|
137
115
|
'apk add --no-cache nspr nss libx11 libxcomposite libxdamage libxrandr atk cups libdrm libgbm alsa-lib',
|
|
138
116
|
'yum install -y nspr nss libX11 libXcomposite libXdamage libXrandr atk cups libdrm libgbm alsa-lib'
|
|
139
117
|
];
|
|
140
|
-
for (const cmd of
|
|
141
|
-
try {
|
|
142
|
-
await execPromise(`sudo ${cmd}`);
|
|
143
|
-
} catch { }
|
|
144
|
-
}
|
|
118
|
+
for (const cmd of depCommands) { try { await execPromise(`sudo ${cmd}`); } catch { } }
|
|
145
119
|
|
|
146
|
-
// Set LD_LIBRARY_PATH so Puppeteer's Chromium can find libs
|
|
147
120
|
process.env.LD_LIBRARY_PATH = `/usr/lib:/usr/lib64:${process.env.LD_LIBRARY_PATH || ''}`;
|
|
148
121
|
return systemChromium;
|
|
149
122
|
}
|
|
150
123
|
|
|
151
|
-
if (this.logDebug) this.emit('debug', `Unsupported OS: ${osName}
|
|
124
|
+
if (this.logDebug) this.emit('debug', `Unsupported OS: ${osName}`);
|
|
152
125
|
return null;
|
|
126
|
+
|
|
153
127
|
} catch (error) {
|
|
154
128
|
if (this.logError) this.emit('error', `Chromium detection/install error: ${error.message}`);
|
|
155
129
|
return null;
|
package/src/melcloud.js
CHANGED
|
@@ -109,7 +109,6 @@ class MelCloud extends EventEmitter {
|
|
|
109
109
|
devicesList.State = true;
|
|
110
110
|
devicesList.Info = `Found ${devicesCount} devices`;
|
|
111
111
|
devicesList.Devices = devices;
|
|
112
|
-
devicesList.Headers = this.headers;
|
|
113
112
|
this.emit('devicesList', devicesList);
|
|
114
113
|
|
|
115
114
|
return devicesList;
|
|
@@ -164,6 +163,7 @@ class MelCloud extends EventEmitter {
|
|
|
164
163
|
'Content-Type': 'application/json'
|
|
165
164
|
};
|
|
166
165
|
this.emit('headers', headers);
|
|
166
|
+
|
|
167
167
|
this.headers = headers;
|
|
168
168
|
this.axiosInstance = axios.create({
|
|
169
169
|
baseURL: ApiUrls.BaseURL,
|
package/src/melcloudata.js
CHANGED
|
@@ -24,7 +24,7 @@ class MelCloudAta extends EventEmitter {
|
|
|
24
24
|
|
|
25
25
|
//set default values
|
|
26
26
|
this.deviceData = {};
|
|
27
|
-
this.headers =
|
|
27
|
+
this.headers = melcloud.headers;
|
|
28
28
|
|
|
29
29
|
//handle melcloud events
|
|
30
30
|
let deviceData = null;
|
|
@@ -148,9 +148,6 @@ class MelCloudAta extends EventEmitter {
|
|
|
148
148
|
return acc;
|
|
149
149
|
}, { indoor: {}, outdoor: {} });
|
|
150
150
|
|
|
151
|
-
//display info if units are not configured in MELCloud service
|
|
152
|
-
if (unitsCount === 0 && this.logDebug) if (this.logDebug) this.emit('debug', `Units are not configured in MELCloud service`);
|
|
153
|
-
|
|
154
151
|
//filter info
|
|
155
152
|
const { Device: _ignored, ...info } = deviceData;
|
|
156
153
|
|
|
@@ -185,7 +182,6 @@ class MelCloudAta extends EventEmitter {
|
|
|
185
182
|
|
|
186
183
|
async checkState(devicesData) {
|
|
187
184
|
try {
|
|
188
|
-
this.headers = devicesData.Headers;
|
|
189
185
|
const deviceData = devicesData.Devices.find(device => device.DeviceID === this.deviceId);
|
|
190
186
|
deviceData.Scenes = devicesData.Scenes ?? [];
|
|
191
187
|
await this.updateState('request', deviceData);
|
|
@@ -238,7 +234,7 @@ class MelCloudAta extends EventEmitter {
|
|
|
238
234
|
break;
|
|
239
235
|
}
|
|
240
236
|
|
|
241
|
-
if (this.logDebug) this.emit('debug', `Send
|
|
237
|
+
if (this.logDebug) this.emit('debug', `Send data: ${JSON.stringify(payload, null, 2)}`);
|
|
242
238
|
|
|
243
239
|
await axios(path, {
|
|
244
240
|
method: 'POST',
|
|
@@ -328,7 +324,7 @@ class MelCloudAta extends EventEmitter {
|
|
|
328
324
|
//sens payload
|
|
329
325
|
headers['Content-Type'] = 'application/json; charset=utf-8';
|
|
330
326
|
headers.Origin = ApiUrlsHome.Origin;
|
|
331
|
-
if (this.logDebug) this.emit('debug', `Send
|
|
327
|
+
if (this.logDebug) this.emit('debug', `Send data: ${JSON.stringify(payload, null, 2)}`);
|
|
332
328
|
|
|
333
329
|
await axios(path, {
|
|
334
330
|
method: method,
|
package/src/melcloudatw.js
CHANGED
|
@@ -24,7 +24,7 @@ class MelCloudAtw extends EventEmitter {
|
|
|
24
24
|
|
|
25
25
|
//set default values
|
|
26
26
|
this.deviceData = {};
|
|
27
|
-
this.headers =
|
|
27
|
+
this.headers = melcloud.headers;
|
|
28
28
|
|
|
29
29
|
//handle melcloud events
|
|
30
30
|
let deviceData = null;
|
|
@@ -135,9 +135,6 @@ class MelCloudAtw extends EventEmitter {
|
|
|
135
135
|
return acc;
|
|
136
136
|
}, { indoor: {}, outdoor: {} });
|
|
137
137
|
|
|
138
|
-
//display info if units are not configured in MELCloud service
|
|
139
|
-
if (unitsCount === 0 && this.logDebug) if (this.logDebug) this.emit('debug', `Units are not configured in MELCloud service`);
|
|
140
|
-
|
|
141
138
|
//filter info
|
|
142
139
|
const { Device: _ignored, ...info } = deviceData;
|
|
143
140
|
|
|
@@ -172,7 +169,6 @@ class MelCloudAtw extends EventEmitter {
|
|
|
172
169
|
|
|
173
170
|
async checkState(devicesData) {
|
|
174
171
|
try {
|
|
175
|
-
this.headers = devicesData.Headers;
|
|
176
172
|
const deviceData = devicesData.Devices.find(device => device.DeviceID === this.deviceId);
|
|
177
173
|
deviceData.Scenes = devicesData.Scenes ?? [];
|
|
178
174
|
await this.updateState('request', deviceData);
|
|
@@ -240,7 +236,7 @@ class MelCloudAtw extends EventEmitter {
|
|
|
240
236
|
break;
|
|
241
237
|
}
|
|
242
238
|
|
|
243
|
-
if (this.logDebug) this.emit('debug', `Send
|
|
239
|
+
if (this.logDebug) this.emit('debug', `Send data: ${JSON.stringify(payload, null, 2)}`);
|
|
244
240
|
|
|
245
241
|
await axios(path, {
|
|
246
242
|
method: 'POST',
|
|
@@ -300,7 +296,7 @@ class MelCloudAtw extends EventEmitter {
|
|
|
300
296
|
|
|
301
297
|
headers['Content-Type'] = 'application/json; charset=utf-8';
|
|
302
298
|
headers.Origin = ApiUrlsHome.Origin;
|
|
303
|
-
if (this.logDebug) this.emit('debug', `Send
|
|
299
|
+
if (this.logDebug) this.emit('debug', `Send data: ${JSON.stringify(payload, null, 2)}`);
|
|
304
300
|
|
|
305
301
|
await axios(path, {
|
|
306
302
|
method: method,
|
package/src/melclouderv.js
CHANGED
|
@@ -24,7 +24,7 @@ class MelCloudErv extends EventEmitter {
|
|
|
24
24
|
|
|
25
25
|
//set default values
|
|
26
26
|
this.deviceData = {};
|
|
27
|
-
this.headers =
|
|
27
|
+
this.headers = melcloud.headers;
|
|
28
28
|
|
|
29
29
|
//handle melcloud events
|
|
30
30
|
let deviceData = null;
|
|
@@ -134,9 +134,6 @@ class MelCloudErv extends EventEmitter {
|
|
|
134
134
|
return acc;
|
|
135
135
|
}, { indoor: {}, outdoor: {} });
|
|
136
136
|
|
|
137
|
-
//display info if units are not configured in MELCloud service
|
|
138
|
-
if (unitsCount === 0 && this.logDebug) if (this.logDebug) this.emit('debug', `Units are not configured in MELCloud service`);
|
|
139
|
-
|
|
140
137
|
//filter info
|
|
141
138
|
const { Device: _ignored, ...info } = deviceData;
|
|
142
139
|
|
|
@@ -171,7 +168,6 @@ class MelCloudErv extends EventEmitter {
|
|
|
171
168
|
|
|
172
169
|
async checkState(devicesData) {
|
|
173
170
|
try {
|
|
174
|
-
this.headers = devicesData.Headers;
|
|
175
171
|
const deviceData = devicesData.Devices.find(device => device.DeviceID === this.deviceId);
|
|
176
172
|
deviceData.Scenes = devicesData.Scenes ?? [];
|
|
177
173
|
await this.updateState('request', deviceData);
|
|
@@ -240,7 +236,7 @@ class MelCloudErv extends EventEmitter {
|
|
|
240
236
|
break;
|
|
241
237
|
}
|
|
242
238
|
|
|
243
|
-
if (this.logDebug) this.emit('debug', `Send
|
|
239
|
+
if (this.logDebug) this.emit('debug', `Send data: ${JSON.stringify(payload, null, 2)}`);
|
|
244
240
|
|
|
245
241
|
await axios(path, {
|
|
246
242
|
method: 'POST',
|
|
@@ -304,7 +300,7 @@ class MelCloudErv extends EventEmitter {
|
|
|
304
300
|
|
|
305
301
|
headers['Content-Type'] = 'application/json; charset=utf-8';
|
|
306
302
|
headers.Origin = ApiUrlsHome.Origin;
|
|
307
|
-
if (this.logDebug) this.emit('debug', `Send
|
|
303
|
+
if (this.logDebug) this.emit('debug', `Send data: ${JSON.stringify(payload, null, 2)}`);
|
|
308
304
|
|
|
309
305
|
await axios(path, {
|
|
310
306
|
method: method,
|
package/src/melcloudhome.js
CHANGED
|
@@ -202,8 +202,11 @@ class MelCloudHome extends EventEmitter {
|
|
|
202
202
|
// Get scenes
|
|
203
203
|
let scenes = [];
|
|
204
204
|
try {
|
|
205
|
-
|
|
206
|
-
if (this.logDebug) this.emit('debug', `Found ${
|
|
205
|
+
const scenesList = await this.checkScenesList();
|
|
206
|
+
if (this.logDebug) this.emit('debug', `Found ${scenesList.length} scenes`);
|
|
207
|
+
if (scenesList.length > 0) {
|
|
208
|
+
scenes = scenesList;
|
|
209
|
+
}
|
|
207
210
|
} catch (error) {
|
|
208
211
|
if (this.logError) this.emit('error', `Get scenes error: ${error}`);
|
|
209
212
|
}
|
|
@@ -256,7 +259,6 @@ class MelCloudHome extends EventEmitter {
|
|
|
256
259
|
devicesList.Info = `Found ${devicesCount} devices ${scenes.length > 0 ? `and ${scenes.length} scenes` : ''}`;
|
|
257
260
|
devicesList.Devices = devices;
|
|
258
261
|
devicesList.Scenes = scenes;
|
|
259
|
-
devicesList.Headers = this.headers;
|
|
260
262
|
this.emit('devicesList', devicesList);
|
|
261
263
|
|
|
262
264
|
return devicesList;
|
|
@@ -272,19 +274,23 @@ class MelCloudHome extends EventEmitter {
|
|
|
272
274
|
let browser;
|
|
273
275
|
try {
|
|
274
276
|
const accountInfo = { State: false, Info: '', Account: {}, UseFahrenheit: false };
|
|
277
|
+
|
|
278
|
+
// Get Chromium path
|
|
275
279
|
let chromiumPath = await this.functions.ensureChromiumInstalled();
|
|
276
280
|
|
|
277
281
|
// === Fallback to Puppeteer's built-in Chromium ===
|
|
278
282
|
if (!chromiumPath) {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
283
|
+
if (!arch.startsWith('arm')) {
|
|
284
|
+
try {
|
|
285
|
+
const puppeteerPath = puppeteer.executablePath();
|
|
286
|
+
if (puppeteerPath && fs.existsSync(puppeteerPath)) {
|
|
287
|
+
chromiumPath = puppeteerPath;
|
|
288
|
+
if (this.logDebug) this.emit('debug', `Using Puppeteer Chromium at ${chromiumPath}`);
|
|
289
|
+
}
|
|
290
|
+
} catch { }
|
|
291
|
+
} else {
|
|
292
|
+
if (this.logDebug) this.emit('debug', 'Skipping Puppeteer Chromium on ARM (incompatible)');
|
|
293
|
+
}
|
|
288
294
|
}
|
|
289
295
|
|
|
290
296
|
if (!chromiumPath) {
|
|
@@ -301,6 +307,7 @@ class MelCloudHome extends EventEmitter {
|
|
|
301
307
|
return accountInfo;
|
|
302
308
|
}
|
|
303
309
|
|
|
310
|
+
// Launch Chromium
|
|
304
311
|
if (this.logDebug) this.emit('debug', `Launching Chromium...`);
|
|
305
312
|
browser = await puppeteer.launch({
|
|
306
313
|
headless: true,
|