homebridge-melcloud-control 4.4.1-beta.3 → 4.4.1-beta.31
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 +10 -0
- package/README.md +55 -55
- package/config.schema.json +54 -54
- package/index.js +4 -4
- package/package.json +2 -2
- package/src/constants.js +62 -50
- package/src/deviceata.js +21 -14
- package/src/deviceatw.js +2 -6
- package/src/deviceerv.js +57 -56
- package/src/functions.js +105 -111
- package/src/melcloud.js +4 -4
- package/src/melcloudata.js +9 -9
- package/src/melcloudatw.js +8 -8
- package/src/melclouderv.js +7 -7
- package/src/melcloudhome.js +34 -32
package/src/deviceata.js
CHANGED
|
@@ -65,7 +65,6 @@ class DeviceAta extends EventEmitter {
|
|
|
65
65
|
|
|
66
66
|
//presets configured
|
|
67
67
|
for (const preset of this.presets) {
|
|
68
|
-
preset.name = preset.name;
|
|
69
68
|
preset.serviceType = serviceType[preset.displayType];
|
|
70
69
|
preset.characteristicType = characteristicType[preset.displayType];
|
|
71
70
|
preset.state = false;
|
|
@@ -74,7 +73,6 @@ class DeviceAta extends EventEmitter {
|
|
|
74
73
|
|
|
75
74
|
//schedules configured
|
|
76
75
|
for (const schedule of this.schedules) {
|
|
77
|
-
schedule.name = schedule.name;
|
|
78
76
|
schedule.serviceType = serviceType[schedule.displayType];
|
|
79
77
|
schedule.characteristicType = characteristicType[schedule.displayType];
|
|
80
78
|
schedule.state = false;
|
|
@@ -82,7 +80,6 @@ class DeviceAta extends EventEmitter {
|
|
|
82
80
|
|
|
83
81
|
//scenes configured
|
|
84
82
|
for (const scene of this.scenes) {
|
|
85
|
-
scene.name = scene.name;
|
|
86
83
|
scene.serviceType = serviceType[scene.displayType];
|
|
87
84
|
scene.characteristicType = characteristicType[scene.displayType];
|
|
88
85
|
scene.state = false;
|
|
@@ -90,7 +87,6 @@ class DeviceAta extends EventEmitter {
|
|
|
90
87
|
|
|
91
88
|
//buttons configured
|
|
92
89
|
for (const button of this.buttons) {
|
|
93
|
-
button.name = button.name;
|
|
94
90
|
button.serviceType = serviceType[button.displayType];
|
|
95
91
|
button.characteristicType = characteristicType[button.displayType];
|
|
96
92
|
button.state = false;
|
|
@@ -522,8 +518,8 @@ class DeviceAta extends EventEmitter {
|
|
|
522
518
|
|
|
523
519
|
try {
|
|
524
520
|
this.accessory.useFahrenheit = value ? true : false;
|
|
525
|
-
if (this.logInfo) this.emit('info', `Set temperature display unit: ${TemperatureDisplayUnits[value]}`);
|
|
526
521
|
this.accountInfo.UseFahrenheit = value ? true : false;
|
|
522
|
+
if (this.logInfo) this.emit('info', `Set temperature display unit: ${TemperatureDisplayUnits[value]}`);
|
|
527
523
|
await this.melCloudAta.send(this.accountType, this.displayType, deviceData, 'account', this.accountInfo);
|
|
528
524
|
} catch (error) {
|
|
529
525
|
if (this.logWarn) this.emit('warn', `Set temperature display unit error: ${error}`);
|
|
@@ -615,8 +611,8 @@ class DeviceAta extends EventEmitter {
|
|
|
615
611
|
|
|
616
612
|
try {
|
|
617
613
|
this.accessory.useFahrenheit = value ? true : false;
|
|
618
|
-
if (this.logInfo) this.emit('info', `Set temperature display unit: ${TemperatureDisplayUnits[value]}`);
|
|
619
614
|
this.accountInfo.UseFahrenheit = value ? true : false;
|
|
615
|
+
if (this.logInfo) this.emit('info', `Set temperature display unit: ${TemperatureDisplayUnits[value]}`);
|
|
620
616
|
await this.melCloudAta.send(this.accountType, this.displayType, deviceData, 'account', this.accountInfo);
|
|
621
617
|
} catch (error) {
|
|
622
618
|
if (this.logWarn) this.emit('warn', `Set temperature display unit error: ${error}`);
|
|
@@ -697,7 +693,7 @@ class DeviceAta extends EventEmitter {
|
|
|
697
693
|
}
|
|
698
694
|
|
|
699
695
|
//frost protection
|
|
700
|
-
if (this.frostProtectionSupport && this.accessory.frostProtection.Enabled !== null) {
|
|
696
|
+
if (supportsHeat && this.frostProtectionSupport && this.accessory.frostProtection.Enabled !== null) {
|
|
701
697
|
//control
|
|
702
698
|
if (this.logDebug) this.emit('debug', `Prepare frost protection control service`);
|
|
703
699
|
const frostProtectionControlService = new Service.HeaterCooler(`${serviceName} Frost Protection`, `frostProtectionControlService${deviceId}`);
|
|
@@ -1614,6 +1610,7 @@ class DeviceAta extends EventEmitter {
|
|
|
1614
1610
|
|
|
1615
1611
|
//characteristics array
|
|
1616
1612
|
const characteristics = [];
|
|
1613
|
+
const operationModevalidValues = [];
|
|
1617
1614
|
|
|
1618
1615
|
//operating mode 0, HEAT, DRY, COOL, 4, 5, 6, FAN, AUTO, ISEE HEAT, ISEE DRY, ISEE COOL
|
|
1619
1616
|
switch (this.displayType) {
|
|
@@ -1659,11 +1656,15 @@ class DeviceAta extends EventEmitter {
|
|
|
1659
1656
|
default:
|
|
1660
1657
|
if (this.logWarn) this.emit('warn', `Unknown operating mode: ${operationMode}`);
|
|
1661
1658
|
}
|
|
1662
|
-
|
|
1663
1659
|
obj.currentOperationMode = !power ? 0 : (inStandbyMode ? 1 : obj.currentOperationMode);
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1660
|
+
|
|
1661
|
+
if (supportsAuto) operationModevalidValues.push(0);
|
|
1662
|
+
if (supportsHeat) operationModevalidValues.push(1);
|
|
1663
|
+
if (supportsCool) operationModevalidValues.push(2);
|
|
1664
|
+
|
|
1665
|
+
obj.operationModeSetPropsMinValue = operationModevalidValues[0];
|
|
1666
|
+
obj.operationModeSetPropsMaxValue = operationModevalidValues.at(-1);
|
|
1667
|
+
obj.operationModeSetPropsValidValues = operationModevalidValues;
|
|
1667
1668
|
|
|
1668
1669
|
//fan speed mode
|
|
1669
1670
|
if (supportsFanSpeed) {
|
|
@@ -1740,9 +1741,15 @@ class DeviceAta extends EventEmitter {
|
|
|
1740
1741
|
|
|
1741
1742
|
obj.currentOperationMode = !power ? 0 : obj.currentOperationMode;
|
|
1742
1743
|
obj.targetOperationMode = !power ? 0 : obj.targetOperationMode;
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1744
|
+
|
|
1745
|
+
operationModevalidValues.push(0);
|
|
1746
|
+
if (supportsHeat) operationModevalidValues.push(1);
|
|
1747
|
+
if (supportsCool) operationModevalidValues.push(2);
|
|
1748
|
+
if (supportsAuto) operationModevalidValues.push(3);
|
|
1749
|
+
|
|
1750
|
+
obj.operationModeSetPropsMinValue = operationModevalidValues[0];
|
|
1751
|
+
obj.operationModeSetPropsMaxValue = operationModevalidValues.at(-1);
|
|
1752
|
+
obj.operationModeSetPropsValidValues = operationModevalidValues;
|
|
1746
1753
|
|
|
1747
1754
|
//create characteristics
|
|
1748
1755
|
characteristics.push(
|
package/src/deviceatw.js
CHANGED
|
@@ -69,7 +69,6 @@ class DeviceAtw extends EventEmitter {
|
|
|
69
69
|
|
|
70
70
|
//presets configured
|
|
71
71
|
for (const preset of this.presets) {
|
|
72
|
-
preset.name = preset.name;
|
|
73
72
|
preset.serviceType = serviceType[preset.displayType];
|
|
74
73
|
preset.characteristicType = characteristicType[preset.displayType];
|
|
75
74
|
preset.state = false;
|
|
@@ -78,7 +77,6 @@ class DeviceAtw extends EventEmitter {
|
|
|
78
77
|
|
|
79
78
|
//schedules configured
|
|
80
79
|
for (const schedule of this.schedules) {
|
|
81
|
-
schedule.name = schedule.name;
|
|
82
80
|
schedule.serviceType = serviceType[schedule.displayType];
|
|
83
81
|
schedule.characteristicType = characteristicType[schedule.displayType];
|
|
84
82
|
schedule.state = false;
|
|
@@ -86,7 +84,6 @@ class DeviceAtw extends EventEmitter {
|
|
|
86
84
|
|
|
87
85
|
//scenes configured
|
|
88
86
|
for (const scene of this.scenes) {
|
|
89
|
-
scene.name = scene.name;
|
|
90
87
|
scene.serviceType = serviceType[scene.displayType];
|
|
91
88
|
scene.characteristicType = characteristicType[scene.displayType];
|
|
92
89
|
scene.state = false;
|
|
@@ -94,7 +91,6 @@ class DeviceAtw extends EventEmitter {
|
|
|
94
91
|
|
|
95
92
|
//buttons configured
|
|
96
93
|
for (const button of this.buttons) {
|
|
97
|
-
button.name = button.name;
|
|
98
94
|
button.serviceType = serviceType[button.displayType];
|
|
99
95
|
button.characteristicType = characteristicType[button.displayType];
|
|
100
96
|
button.state = false;
|
|
@@ -645,8 +641,8 @@ class DeviceAtw extends EventEmitter {
|
|
|
645
641
|
|
|
646
642
|
try {
|
|
647
643
|
this.accessory.useFahrenheit = value ? true : false;
|
|
648
|
-
if (this.logInfo) this.emit('info', `Set temperature display unit: ${TemperatureDisplayUnits[value]}`);
|
|
649
644
|
this.accountInfo.UseFahrenheit = value ? true : false;
|
|
645
|
+
if (this.logInfo) this.emit('info', `Set temperature display unit: ${TemperatureDisplayUnits[value]}`);
|
|
650
646
|
await this.melCloudAtw.send(this.accountType, this.displayType, deviceData, 'account', this.accountInfo);
|
|
651
647
|
} catch (error) {
|
|
652
648
|
if (this.logWarn) this.emit('warn', `Set temperature display unit error: ${error}`);
|
|
@@ -826,8 +822,8 @@ class DeviceAtw extends EventEmitter {
|
|
|
826
822
|
|
|
827
823
|
try {
|
|
828
824
|
this.accessory.useFahrenheit = value ? true : false;
|
|
829
|
-
if (this.logInfo) this.emit('info', `Set temperature display unit: ${TemperatureDisplayUnits[value]}`);
|
|
830
825
|
this.accountInfo.UseFahrenheit = value ? true : false;
|
|
826
|
+
if (this.logInfo) this.emit('info', `Set temperature display unit: ${TemperatureDisplayUnits[value]}`);
|
|
831
827
|
await this.melCloudAtw.send(this.accountType, this.displayType, deviceData, 'account', this.accountInfo);
|
|
832
828
|
} catch (error) {
|
|
833
829
|
if (this.logWarn) this.emit('warn', `Set temperature display unit error: ${error}`);
|
package/src/deviceerv.js
CHANGED
|
@@ -61,7 +61,6 @@ class DeviceErv extends EventEmitter {
|
|
|
61
61
|
|
|
62
62
|
//presets configured
|
|
63
63
|
for (const preset of this.presets) {
|
|
64
|
-
preset.name = preset.name;
|
|
65
64
|
preset.serviceType = serviceType[preset.displayType];
|
|
66
65
|
preset.characteristicType = characteristicType[preset.displayType];
|
|
67
66
|
preset.state = false;
|
|
@@ -70,7 +69,6 @@ class DeviceErv extends EventEmitter {
|
|
|
70
69
|
|
|
71
70
|
//schedules configured
|
|
72
71
|
for (const schedule of this.schedules) {
|
|
73
|
-
schedule.name = schedule.name;
|
|
74
72
|
schedule.serviceType = serviceType[schedule.displayType];
|
|
75
73
|
schedule.characteristicType = characteristicType[schedule.displayType];
|
|
76
74
|
schedule.state = false;
|
|
@@ -78,7 +76,6 @@ class DeviceErv extends EventEmitter {
|
|
|
78
76
|
|
|
79
77
|
//scenes configured
|
|
80
78
|
for (const scene of this.scenes) {
|
|
81
|
-
scene.name = scene.name;
|
|
82
79
|
scene.serviceType = serviceType[scene.displayType];
|
|
83
80
|
scene.characteristicType = characteristicType[scene.displayType];
|
|
84
81
|
scene.state = false;
|
|
@@ -86,7 +83,6 @@ class DeviceErv extends EventEmitter {
|
|
|
86
83
|
|
|
87
84
|
//buttons configured
|
|
88
85
|
for (const button of this.buttons) {
|
|
89
|
-
button.name = button.name;
|
|
90
86
|
button.serviceType = serviceType[button.displayType];
|
|
91
87
|
button.characteristicType = characteristicType[button.displayType];
|
|
92
88
|
button.state = false;
|
|
@@ -454,8 +450,8 @@ class DeviceErv extends EventEmitter {
|
|
|
454
450
|
|
|
455
451
|
try {
|
|
456
452
|
this.accessory.useFahrenheit = value ? true : false;
|
|
457
|
-
if (this.logInfo) this.emit('info', `Set temperature display unit: ${TemperatureDisplayUnits[value]}`);
|
|
458
453
|
this.accountInfo.UseFahrenheit = value ? true : false;
|
|
454
|
+
if (this.logInfo) this.emit('info', `Set temperature display unit: ${TemperatureDisplayUnits[value]}`);
|
|
459
455
|
await this.melCloudErv.send(this.accountType, this.displayType, deviceData, 'account', this.accountInfo);
|
|
460
456
|
} catch (error) {
|
|
461
457
|
if (this.logWarn) this.emit('warn', `Set temperature display unit error: ${error}`);
|
|
@@ -548,8 +544,8 @@ class DeviceErv extends EventEmitter {
|
|
|
548
544
|
|
|
549
545
|
try {
|
|
550
546
|
this.accessory.useFahrenheit = value ? true : false;
|
|
551
|
-
if (this.logInfo) this.emit('info', `Set temperature display unit: ${TemperatureDisplayUnits[value]}`);
|
|
552
547
|
this.accountInfo.UseFahrenheit = value ? true : false;
|
|
548
|
+
if (this.logInfo) this.emit('info', `Set temperature display unit: ${TemperatureDisplayUnits[value]}`);
|
|
553
549
|
await this.melCloudErv.send(this.accountType, this.displayType, deviceData, 'account', this.accountInfo);
|
|
554
550
|
} catch (error) {
|
|
555
551
|
if (this.logWarn) this.emit('warn', `Set temperature display unit error: ${error}`);
|
|
@@ -1261,43 +1257,44 @@ class DeviceErv extends EventEmitter {
|
|
|
1261
1257
|
|
|
1262
1258
|
//characteristics array
|
|
1263
1259
|
const characteristics = [];
|
|
1260
|
+
const operationModevalidValues = [];
|
|
1264
1261
|
|
|
1265
1262
|
//ventilation mode - 0, HEAT, 2, COOL, 4, 5, 6, FAN, AUTO
|
|
1266
1263
|
switch (this.displayType) {
|
|
1267
1264
|
case 1: //Heater Cooler
|
|
1268
1265
|
switch (ventilationMode) {
|
|
1269
|
-
case 0: //LOSSNAY
|
|
1270
|
-
obj.currentOperationMode = 2; //
|
|
1271
|
-
obj.targetOperationMode = 1;
|
|
1266
|
+
case 0: // LOSSNAY
|
|
1267
|
+
obj.currentOperationMode = 2; // heating
|
|
1268
|
+
obj.targetOperationMode = 1; // heat
|
|
1272
1269
|
break;
|
|
1273
|
-
case 1: //BYPASS
|
|
1274
|
-
obj.currentOperationMode = 3;
|
|
1275
|
-
obj.targetOperationMode = 2;
|
|
1270
|
+
case 1: // BYPASS
|
|
1271
|
+
obj.currentOperationMode = 3; // cooling
|
|
1272
|
+
obj.targetOperationMode = 2; // cool
|
|
1276
1273
|
break;
|
|
1277
|
-
case 2: //AUTO
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
default:
|
|
1286
|
-
if (this.logWarn) this.emit('warn', `Unknown actual ventilation mode: ${actualVentilationMode}`);
|
|
1287
|
-
break;
|
|
1288
|
-
};
|
|
1289
|
-
obj.targetOperationMode = 0;
|
|
1274
|
+
case 2: // AUTO
|
|
1275
|
+
if (actualVentilationMode === 0) {
|
|
1276
|
+
obj.currentOperationMode = 2; // heating
|
|
1277
|
+
} else if (actualVentilationMode === 1) {
|
|
1278
|
+
obj.currentOperationMode = 3; // cooling
|
|
1279
|
+
} else if (this.logWarn) this.emit('warn', `Unknown actual ventilation mode: ${actualVentilationMode}`);
|
|
1280
|
+
|
|
1281
|
+
obj.targetOperationMode = 0; // auto
|
|
1290
1282
|
break;
|
|
1291
1283
|
default:
|
|
1292
1284
|
if (this.logWarn) this.emit('warn', `Unknown ventilation mode: ${ventilationMode}`);
|
|
1293
1285
|
break;
|
|
1294
|
-
}
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
// power override
|
|
1289
|
+
if (!power) obj.currentOperationMode = 0; // inactive
|
|
1295
1290
|
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
obj.
|
|
1291
|
+
if (supportsAutoVentilationMode) operationModevalidValues.push(0);
|
|
1292
|
+
if (supportsBypassVentilationMode) operationModevalidValues.push(1);
|
|
1293
|
+
operationModevalidValues.push(2); // manual zawsze dostępny
|
|
1294
|
+
|
|
1295
|
+
obj.operationModeSetPropsMinValue = operationModevalidValues[0];
|
|
1296
|
+
obj.operationModeSetPropsMaxValue = operationModevalidValues.at(-1);
|
|
1297
|
+
obj.operationModeSetPropsValidValues = operationModevalidValues;
|
|
1301
1298
|
|
|
1302
1299
|
//fan speed mode
|
|
1303
1300
|
obj.fanSpeedSetPropsMaxValue = 2;
|
|
@@ -1334,38 +1331,42 @@ class DeviceErv extends EventEmitter {
|
|
|
1334
1331
|
case 2: //Thermostat
|
|
1335
1332
|
//operation mode - 0, HEAT, 2, COOL, 4, 5, 6, FAN, AUTO
|
|
1336
1333
|
switch (ventilationMode) {
|
|
1337
|
-
case 0: //LOSSNAY
|
|
1338
|
-
obj.currentOperationMode = 1; //
|
|
1339
|
-
obj.targetOperationMode = 1;
|
|
1334
|
+
case 0: // LOSSNAY
|
|
1335
|
+
obj.currentOperationMode = 1; // HEAT
|
|
1336
|
+
obj.targetOperationMode = 1; // HEAT
|
|
1340
1337
|
break;
|
|
1341
|
-
case 1: //BYPASS
|
|
1342
|
-
obj.currentOperationMode = 2;
|
|
1343
|
-
obj.targetOperationMode = 2;
|
|
1338
|
+
case 1: // BYPASS
|
|
1339
|
+
obj.currentOperationMode = 2; // COOL
|
|
1340
|
+
obj.targetOperationMode = 2; // COOL
|
|
1344
1341
|
break;
|
|
1345
|
-
case 2: //AUTO
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
default:
|
|
1354
|
-
if (this.logWarn) this.emit('warn', `Unknown actual ventilation mode: ${actualVentilationMode}`);
|
|
1355
|
-
break;
|
|
1356
|
-
};
|
|
1357
|
-
obj.targetOperationMode = 3;
|
|
1342
|
+
case 2: // AUTO
|
|
1343
|
+
if (actualVentilationMode === 0) {
|
|
1344
|
+
obj.currentOperationMode = 1; // HEAT
|
|
1345
|
+
} else if (actualVentilationMode === 1) {
|
|
1346
|
+
obj.currentOperationMode = 2; // COOL
|
|
1347
|
+
} else if (this.logWarn) this.emit('warn', `Unknown actual ventilation mode: ${actualVentilationMode}`);
|
|
1348
|
+
|
|
1349
|
+
obj.targetOperationMode = 3; // AUTO
|
|
1358
1350
|
break;
|
|
1359
1351
|
default:
|
|
1360
1352
|
if (this.logWarn) this.emit('warn', `Unknown ventilation mode: ${ventilationMode}`);
|
|
1361
1353
|
break;
|
|
1362
|
-
}
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
// power override (single source of truth)
|
|
1357
|
+
if (!power) {
|
|
1358
|
+
obj.currentOperationMode = 0;
|
|
1359
|
+
obj.targetOperationMode = 0;
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
operationModevalidValues.push(0); // manual zawsze dostępny
|
|
1363
|
+
if (supportsBypassVentilationMode) operationModevalidValues.push(1);
|
|
1364
|
+
operationModevalidValues.push(2); // manual / normal
|
|
1365
|
+
if (supportsAutoVentilationMode) operationModevalidValues.push(3);
|
|
1363
1366
|
|
|
1364
|
-
obj.
|
|
1365
|
-
obj.
|
|
1366
|
-
obj.
|
|
1367
|
-
obj.operationModeSetPropsMaxValue = supportsAutoVentilationMode ? 3 : 2;
|
|
1368
|
-
obj.operationModeSetPropsValidValues = supportsAutoVentilationMode ? (supportsBypassVentilationMode ? [0, 1, 2, 3] : [0, 2, 3]) : (supportsBypassVentilationMode ? [0, 1, 2] : [0, 2]);
|
|
1367
|
+
obj.operationModeSetPropsMinValue = operationModevalidValues[0];
|
|
1368
|
+
obj.operationModeSetPropsMaxValue = operationModevalidValues.at(-1);
|
|
1369
|
+
obj.operationModeSetPropsValidValues = operationModevalidValues;
|
|
1369
1370
|
|
|
1370
1371
|
//create characteristics
|
|
1371
1372
|
characteristics.push(
|
package/src/functions.js
CHANGED
|
@@ -56,162 +56,157 @@ class Functions extends EventEmitter {
|
|
|
56
56
|
|
|
57
57
|
async ensureChromiumInstalled() {
|
|
58
58
|
try {
|
|
59
|
-
|
|
60
|
-
const { stdout: osOut } = await execPromise("uname -s");
|
|
59
|
+
const { stdout: osOut } = await execPromise('uname -s');
|
|
61
60
|
const osName = osOut.trim();
|
|
62
|
-
const { stdout: archOut } = await execPromise("uname -m");
|
|
63
|
-
const arch = archOut.trim();
|
|
64
61
|
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
62
|
+
const { stdout: archOut } = await execPromise('uname -m');
|
|
63
|
+
let arch = archOut.trim() || 'unknown';
|
|
64
|
+
|
|
65
|
+
// Normalizacja architektury
|
|
66
|
+
if (arch.startsWith('arm') || arch.startsWith('aarch')) arch = 'arm';
|
|
67
|
+
else if (arch.includes('64')) arch = 'x64';
|
|
68
|
+
else arch = 'x86';
|
|
69
|
+
|
|
70
|
+
const isARM = arch === 'arm';
|
|
71
|
+
const isMac = osName === 'Darwin';
|
|
72
|
+
const isLinux = osName === 'Linux';
|
|
73
|
+
const isQnap = fs.existsSync('/etc/config/uLinux.conf') || fs.existsSync('/etc/config/qpkg.conf');
|
|
68
74
|
|
|
69
75
|
// Detect Docker
|
|
70
76
|
let isDocker = false;
|
|
71
77
|
try {
|
|
72
|
-
await access(
|
|
78
|
+
await access('/.dockerenv');
|
|
73
79
|
isDocker = true;
|
|
74
80
|
} catch { }
|
|
81
|
+
|
|
75
82
|
try {
|
|
76
|
-
const { stdout } = await execPromise(
|
|
77
|
-
if (stdout.includes(
|
|
83
|
+
const { stdout } = await execPromise('cat /proc/1/cgroup');
|
|
84
|
+
if (stdout.includes('docker') || stdout.includes('containerd')) isDocker = true;
|
|
78
85
|
} catch { }
|
|
79
86
|
|
|
80
|
-
|
|
87
|
+
const result = { path: null, arch, system: 'unknown' };
|
|
88
|
+
|
|
89
|
+
/* ===================== macOS ===================== */
|
|
81
90
|
if (isMac) {
|
|
82
|
-
const macCandidates = [
|
|
83
|
-
|
|
84
|
-
"/Applications/Chromium.app/Contents/MacOS/Chromium"
|
|
85
|
-
];
|
|
86
|
-
for (const p of macCandidates) {
|
|
91
|
+
const macCandidates = ['/Applications/Google Chrome.app/Contents/MacOS/Google Chrome', '/Applications/Chromium.app/Contents/MacOS/Chromium'];
|
|
92
|
+
for (const path of macCandidates) {
|
|
87
93
|
try {
|
|
88
|
-
await access(
|
|
89
|
-
|
|
94
|
+
await access(path, fs.constants.X_OK);
|
|
95
|
+
result.path = path;
|
|
96
|
+
result.system = 'macOS';
|
|
97
|
+
return result;
|
|
90
98
|
} catch { }
|
|
91
99
|
}
|
|
92
|
-
return
|
|
100
|
+
return result;
|
|
93
101
|
}
|
|
94
102
|
|
|
95
|
-
|
|
96
|
-
if (
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
"/usr/bin/chromium",
|
|
100
|
-
"/snap/bin/chromium"
|
|
101
|
-
];
|
|
102
|
-
|
|
103
|
-
// Try existing
|
|
104
|
-
for (const p of armCandidates) {
|
|
103
|
+
/* ===================== QNAP ===================== */
|
|
104
|
+
if (isQnap) {
|
|
105
|
+
const qnapCandidates = ['/opt/bin/chromium', '/opt/bin/chromium-browser'];
|
|
106
|
+
for (const path of qnapCandidates) {
|
|
105
107
|
try {
|
|
106
|
-
await access(
|
|
107
|
-
|
|
108
|
+
await access(path, fs.constants.X_OK);
|
|
109
|
+
result.path = path;
|
|
110
|
+
result.system = 'Qnap';
|
|
111
|
+
return result;
|
|
108
112
|
} catch { }
|
|
109
113
|
}
|
|
110
114
|
|
|
111
|
-
|
|
112
|
-
|
|
115
|
+
try {
|
|
116
|
+
await access('/opt/bin/opkg', fs.constants.X_OK);
|
|
117
|
+
await execPromise('/opt/bin/opkg update');
|
|
118
|
+
await execPromise('opkg install chromium nspr nss libx11 libxcomposite libxdamage libxrandr atk libcups libdrm libgbm alsa-lib');
|
|
119
|
+
process.env.LD_LIBRARY_PATH = `/opt/lib:${process.env.LD_LIBRARY_PATH || ''}`;
|
|
120
|
+
} catch (error) {
|
|
121
|
+
if (this.logError) this.emit('error', `Install package for Qnap error: ${error}`);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
for (const path of qnapCandidates) {
|
|
113
125
|
try {
|
|
114
|
-
await
|
|
126
|
+
await access(path, fs.constants.X_OK);
|
|
127
|
+
result.path = path;
|
|
128
|
+
result.system = 'Qnap';
|
|
129
|
+
return result;
|
|
115
130
|
} catch { }
|
|
131
|
+
}
|
|
132
|
+
return result;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/* ===================== Linux ARM ===================== */
|
|
136
|
+
if (isLinux && isARM) {
|
|
137
|
+
const armCandidates = ['/usr/bin/chromium-browser', '/usr/bin/chromium', '/snap/bin/chromium'];
|
|
138
|
+
for (const path of armCandidates) {
|
|
116
139
|
try {
|
|
117
|
-
await
|
|
140
|
+
await access(path, fs.constants.X_OK);
|
|
141
|
+
result.path = path;
|
|
142
|
+
result.system = 'Linux';
|
|
143
|
+
return result;
|
|
118
144
|
} catch { }
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (!isDocker) {
|
|
119
148
|
try {
|
|
120
|
-
await execPromise(
|
|
121
|
-
|
|
149
|
+
await execPromise('sudo apt update -y');
|
|
150
|
+
await execPromise('sudo apt install -y libnspr4 libnss3 libx11-6 libxcomposite1 libxdamage1 libxrandr2 libatk1.0-0 libcups2 libdrm2 libgbm1 libasound2');
|
|
151
|
+
await execPromise('sudo apt install -y chromium chromium-browser chromium-codecs-ffmpeg');
|
|
152
|
+
} catch (error) {
|
|
153
|
+
if (this.logError) this.emit('error', `Install package for Linux ARM error: ${error}`);
|
|
154
|
+
}
|
|
122
155
|
}
|
|
123
156
|
|
|
124
|
-
|
|
125
|
-
for (const p of armCandidates) {
|
|
157
|
+
for (const path of armCandidates) {
|
|
126
158
|
try {
|
|
127
|
-
await access(
|
|
128
|
-
|
|
159
|
+
await access(path, fs.constants.X_OK);
|
|
160
|
+
result.path = path;
|
|
161
|
+
result.system = 'Linux';
|
|
162
|
+
return result;
|
|
129
163
|
} catch { }
|
|
130
164
|
}
|
|
131
|
-
|
|
132
|
-
return null;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// QNAP / Entware
|
|
136
|
-
let entwareExists = false;
|
|
137
|
-
try {
|
|
138
|
-
await access("/opt/bin/opkg", fs.constants.X_OK);
|
|
139
|
-
entwareExists = true;
|
|
140
|
-
} catch { }
|
|
141
|
-
|
|
142
|
-
if (entwareExists) {
|
|
143
|
-
try {
|
|
144
|
-
await execPromise("/opt/bin/opkg update");
|
|
145
|
-
await execPromise("/opt/bin/opkg install nspr nss libx11 libxcomposite libxdamage libxrandr atk libcups libdrm libgbm alsa-lib");
|
|
146
|
-
process.env.LD_LIBRARY_PATH = `/opt/lib:${process.env.LD_LIBRARY_PATH || ""}`;
|
|
147
|
-
} catch { }
|
|
165
|
+
return result;
|
|
148
166
|
}
|
|
149
167
|
|
|
150
|
-
|
|
151
|
-
const synoCandidates = [
|
|
152
|
-
"/var/packages/Chromium/target/usr/bin/chromium",
|
|
153
|
-
"/usr/local/chromium/bin/chromium"
|
|
154
|
-
];
|
|
155
|
-
for (const p of synoCandidates) {
|
|
156
|
-
try {
|
|
157
|
-
await access(p, fs.constants.X_OK);
|
|
158
|
-
return p;
|
|
159
|
-
} catch { }
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// Linux x64
|
|
168
|
+
/* ===================== Linux x64 ===================== */
|
|
163
169
|
if (isLinux) {
|
|
164
|
-
const linuxCandidates = [
|
|
165
|
-
"/usr/bin/chromium",
|
|
166
|
-
"/usr/bin/chromium-browser",
|
|
167
|
-
"/usr/bin/google-chrome",
|
|
168
|
-
"/snap/bin/chromium",
|
|
169
|
-
"/usr/local/bin/chromium"
|
|
170
|
-
];
|
|
171
|
-
|
|
170
|
+
const linuxCandidates = ['/usr/bin/chromium', '/usr/bin/chromium-browser', '/usr/bin/google-chrome', '/snap/bin/chromium', '/usr/local/bin/chromium'];
|
|
172
171
|
try {
|
|
173
|
-
const { stdout } = await execPromise(
|
|
174
|
-
|
|
175
|
-
|
|
172
|
+
const { stdout } = await execPromise('which chromium || which chromium-browser || which google-chrome');
|
|
173
|
+
if (stdout.trim()) {
|
|
174
|
+
result.path = stdout.trim();
|
|
175
|
+
return result;
|
|
176
|
+
}
|
|
176
177
|
} catch { }
|
|
177
178
|
|
|
178
|
-
for (const
|
|
179
|
+
for (const path of linuxCandidates) {
|
|
179
180
|
try {
|
|
180
|
-
await access(
|
|
181
|
-
|
|
181
|
+
await access(path, fs.constants.X_OK);
|
|
182
|
+
result.path = path;
|
|
183
|
+
result.system = 'Linux';
|
|
184
|
+
return result;
|
|
182
185
|
} catch { }
|
|
183
186
|
}
|
|
184
187
|
|
|
185
|
-
// Docker: try installing chromium inside container (if allowed)
|
|
186
188
|
if (isDocker) {
|
|
187
189
|
try {
|
|
188
|
-
await execPromise(
|
|
189
|
-
} catch {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
];
|
|
202
|
-
for (const cmd of depCommands) {
|
|
203
|
-
try {
|
|
204
|
-
await execPromise(`sudo ${cmd}`);
|
|
205
|
-
} catch { }
|
|
190
|
+
await execPromise('apt update -y && apt install -y chromium');
|
|
191
|
+
} catch (error) {
|
|
192
|
+
if (this.logError) this.emit('error', `Install package for Linux Docker error: ${error}`);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
for (const path of linuxCandidates) {
|
|
196
|
+
try {
|
|
197
|
+
await access(path, fs.constants.X_OK);
|
|
198
|
+
result.path = path;
|
|
199
|
+
result.system = 'Linux Docker';
|
|
200
|
+
return result;
|
|
201
|
+
} catch { }
|
|
202
|
+
}
|
|
206
203
|
}
|
|
207
|
-
|
|
208
|
-
return null;
|
|
209
204
|
}
|
|
210
205
|
|
|
211
|
-
return
|
|
212
|
-
} catch (
|
|
213
|
-
if (this.logError) this.emit(
|
|
214
|
-
return null;
|
|
206
|
+
return result;
|
|
207
|
+
} catch (error) {
|
|
208
|
+
if (this.logError) this.emit('error', `Chromium detection error: ${error.message}`);
|
|
209
|
+
return { path: null, arch: 'unknown', system: 'unknown' };
|
|
215
210
|
}
|
|
216
211
|
}
|
|
217
212
|
|
|
@@ -280,7 +275,6 @@ class Functions extends EventEmitter {
|
|
|
280
275
|
|
|
281
276
|
return { min, max };
|
|
282
277
|
}
|
|
283
|
-
|
|
284
278
|
}
|
|
285
279
|
|
|
286
280
|
export default Functions
|