homebridge-myplace 2.3.3 → 2.3.5
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 +3 -2
- package/Cmd5Platform.js +1 -1
- package/RUNNING_CHANGELOG.md +8 -0
- package/package.json +1 -1
- package/utils/createMyPlaceConfig.js +18 -21
- package/utils/devicesAutoDiscovery.js +1 -1
- package/utils/isIpAccessible.js +63 -0
- package/utils/updateConfig.js +95 -124
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
### Homebridge-myplace - An independent plugin for Homebridge bringing Advantage Air MyPlace system, its smaller siblings (E-zone, MyAir, MyAir4, etc) and its cousins (e.g. Fujitsu AnywAir) to Homekit
|
|
2
|
-
|
|
3
|
-
##### (
|
|
2
|
+
|
|
3
|
+
##### v2.3.5 (14-01-2026)
|
|
4
|
+
##### (1) Determine device accessibility by validating the port's availability rather than initiating a direct access request. This approach prevents multiple access attempts occuring in rapid succession during the stup porcess.
|
package/Cmd5Platform.js
CHANGED
|
@@ -123,7 +123,7 @@ class Cmd5Platform
|
|
|
123
123
|
this.processNewCharacteristicDefinitions( );
|
|
124
124
|
|
|
125
125
|
// scan the platform accessories (devices) to identify which ones to be restored from cache
|
|
126
|
-
this.log.info( chalk.yellow( "***Scanning the config and the cache for accessories to be removed or restored from cache..." ) );
|
|
126
|
+
this.log.info( chalk.yellow( "*** Scanning the config and the cache for accessories to be removed or restored from cache..." ) );
|
|
127
127
|
this.scanToBeRemovedOrRestored( this.log );
|
|
128
128
|
|
|
129
129
|
// Any accessory NOT to be restored should be removed, find them
|
package/RUNNING_CHANGELOG.md
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
### Homebridge-myplace - An independent plugin for Homebridge bringing Advantage Air MyPlace system, its smaller siblings (E-zone, MyAir, MyAir4, etc) and its cousins (e.g. Fujitsu AnywAir) to Homekit
|
|
2
|
+
|
|
3
|
+
##### v2.3.5 (14-01-2026)
|
|
4
|
+
##### (1) Determine device accessibility by validating the port's availability rather than initiating a direct access request. This approach prevents multiple access attempts occuring in rapid succession during the stup porces>
|
|
5
|
+
|
|
6
|
+
##### v2.3.4 (05-12-2025)
|
|
7
|
+
##### (1) Ensure that all valid devices defined in the configuration are processed, even when one or more configured devices are invalid or inaccessible.
|
|
8
|
+
##### (2) Improved the clarity and consistency of log messages.
|
|
9
|
+
|
|
2
10
|
##### v2.3.3 (18-11-2025)
|
|
3
11
|
##### (1) Bug fix - to fix an error of an undefined variable.
|
|
4
12
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// This async function is to generate a complete configuration file needed for the myPlace plugin
|
|
2
2
|
// It can handle up to 3 independent myPlace (BB) systems
|
|
3
3
|
|
|
4
|
-
async function createMyPlaceConfig(config, pluginPath) {
|
|
4
|
+
async function createMyPlaceConfig(config, IPs, pluginPath, log) {
|
|
5
5
|
const path = require("path");
|
|
6
6
|
|
|
7
7
|
const MYPLACE_SH_PATH = path.join(pluginPath, "MyPlace.sh");
|
|
@@ -415,18 +415,6 @@ async function createMyPlaceConfig(config, pluginPath) {
|
|
|
415
415
|
};
|
|
416
416
|
}
|
|
417
417
|
|
|
418
|
-
// Helper regex to validate IP and IP:port
|
|
419
|
-
const ipRegex = /^(\d{1,3}\.){3}\d{1,3}$/;
|
|
420
|
-
const ipPortRegex = /^(\d{1,3}\.){3}\d{1,3}:\d+$/;
|
|
421
|
-
|
|
422
|
-
// Validate and normalize IPs
|
|
423
|
-
function normalizeIP( ip, port = 2025 ) {
|
|
424
|
-
if (!ip || ip === "undefined" ) return "";
|
|
425
|
-
if (ipRegex.test(ip)) return `${ip}:${port}`;
|
|
426
|
-
if (ipPortRegex.test(ip)) return ip;
|
|
427
|
-
throw new Error(`ERROR: Device ${n + 1} - the specified IP address ${ip} is in wrong format`);
|
|
428
|
-
}
|
|
429
|
-
|
|
430
418
|
// Determine number of tablets/devices
|
|
431
419
|
let noOfTablets = config.devices.length;
|
|
432
420
|
|
|
@@ -440,31 +428,40 @@ async function createMyPlaceConfig(config, pluginPath) {
|
|
|
440
428
|
} else {
|
|
441
429
|
AAname = config.devices[n]?.name || `Aircon${n + 1}`;
|
|
442
430
|
}
|
|
443
|
-
|
|
444
|
-
const
|
|
431
|
+
|
|
432
|
+
const ip = IPs[n];
|
|
433
|
+
if (ip === "undefined") continue;
|
|
434
|
+
|
|
445
435
|
const extraTimers = config.devices[n]?.extraTimers || false;
|
|
446
436
|
const debug = config.devices[n]?.debug || false;
|
|
447
437
|
const queue=["AAA", "AAB", "AAC"][n]
|
|
448
438
|
|
|
449
|
-
const ip = normalizeIP(AAIP, AAport);
|
|
450
439
|
const IPA = `\${AAIP${n + 1}}`
|
|
451
440
|
|
|
452
|
-
// if (!ip || ip === "undefined" || !ipRegex.test(ip)) continue;
|
|
453
|
-
|
|
454
441
|
// Fetch system data
|
|
455
442
|
let myAirData;
|
|
456
443
|
try {
|
|
457
|
-
const response = await fetch(`http://${ip}/getSystemData
|
|
444
|
+
const response = await fetch(`http://${ip}/getSystemData`);
|
|
458
445
|
if (!response.ok) throw new Error(`HTTP error ${response.status}`);
|
|
459
446
|
myAirData = await response.json();
|
|
460
447
|
} catch {
|
|
461
|
-
|
|
448
|
+
if (n === noOfTablets - 1) {
|
|
449
|
+
throw new Error(`Device ${n + 1} with IP ${ip} is inaccessible (power OFF or wrong IP or wrong port).`);
|
|
450
|
+
} else {
|
|
451
|
+
log.warn(`⚠️ Device ${n + 1} with IP ${ip} is inaccessible (power OFF or wrong IP or wrong port).`);
|
|
452
|
+
continue;
|
|
453
|
+
}
|
|
462
454
|
}
|
|
463
455
|
|
|
464
456
|
// Extract system info (use safe chaining or checks as needed)
|
|
465
457
|
const sysName = (myAirData.system?.name ?? "").replace(/ /g, "_").replace(/['"]/g, "");
|
|
466
458
|
if (!sysName) {
|
|
467
|
-
|
|
459
|
+
if (n === noOfTablets - 1) {
|
|
460
|
+
throw new Error("Failed to get system info from your device ${n + 1}!");
|
|
461
|
+
} else {
|
|
462
|
+
log.error("⚠️ Failed to get system info from your device ${n + 1}!");
|
|
463
|
+
continue;
|
|
464
|
+
}
|
|
468
465
|
}
|
|
469
466
|
const sysType = (myAirData.system?.sysType ?? "").replace(/ /g, "_").replace(/"/g, "");
|
|
470
467
|
const tspModel = (myAirData.system?.tspModel ?? "").replace(/ /g, "_").replace(/"/g, "");
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
const net = require("net");
|
|
2
|
+
|
|
3
|
+
// Simple port check (returns true/false)
|
|
4
|
+
function isPortReachable( ip ) {
|
|
5
|
+
return new Promise((resolve) => {
|
|
6
|
+
const socket = new net.Socket();
|
|
7
|
+
|
|
8
|
+
socket.setTimeout(1000);
|
|
9
|
+
|
|
10
|
+
socket.on("connect", () => {
|
|
11
|
+
socket.destroy();
|
|
12
|
+
resolve(true);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
socket.on("timeout", () => {
|
|
16
|
+
socket.destroy();
|
|
17
|
+
resolve(false);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
socket.on("error", () => {
|
|
21
|
+
resolve(false);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const [ipStr, portStr] = ip.split(":");
|
|
25
|
+
const port = Number(portStr);
|
|
26
|
+
|
|
27
|
+
socket.connect(port, ipStr);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// If port is not reachable, retry up to 5 times...
|
|
32
|
+
async function isIpAccessible( ip, i, noOfDevices, log ) {
|
|
33
|
+
|
|
34
|
+
for (let attempt = 0; attempt < 6; attempt++) {
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
const reachable = await isPortReachable( ip );
|
|
38
|
+
|
|
39
|
+
if (reachable) {
|
|
40
|
+
return true; // success
|
|
41
|
+
} else {
|
|
42
|
+
throw new Error("Port unreachable");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
} catch (err) {
|
|
46
|
+
|
|
47
|
+
if (attempt === 5) {
|
|
48
|
+
log.warn(`⚠️ All 5 retry attempts on Device ${i + 1} failed!`);
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
log.warn(
|
|
53
|
+
`⚠️ Device ${i + 1}/${noOfDevices} with IP ${ip} is inaccessible. ` +
|
|
54
|
+
`Retrying (${attempt + 1}/5) in 5s...`
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
// wait 5 seconds before retry
|
|
58
|
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
module.exports = { isIpAccessible };
|
package/utils/updateConfig.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// Update myplaceConfig
|
|
2
|
+
const { isIpAccessible } = require("./isIpAccessible");
|
|
2
3
|
const { devicesAutoDiscovery } = require("./devicesAutoDiscovery");
|
|
3
4
|
const { createMyPlaceConfig } = require("./createMyPlaceConfig");
|
|
4
5
|
const { readConfig } = require("./readConfig");
|
|
@@ -9,6 +10,8 @@ function delay(ms) {
|
|
|
9
10
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
10
11
|
}
|
|
11
12
|
|
|
13
|
+
const isValidIp = (value) => /^(?:\d{1,3}\.){3}\d{1,3}$/.test(value);
|
|
14
|
+
|
|
12
15
|
async function updateConfig(config, log, storagePath, pluginPath) {
|
|
13
16
|
// Enforce maxAccessories: default 149 (Homebridge hard limit)
|
|
14
17
|
const maxAccessories = (typeof config.maxAccessories === "number"
|
|
@@ -35,145 +38,113 @@ async function updateConfig(config, log, storagePath, pluginPath) {
|
|
|
35
38
|
});
|
|
36
39
|
}
|
|
37
40
|
|
|
41
|
+
let IPs = [];
|
|
38
42
|
if (!Array.isArray(config.devices) || devicesMissingIPs) {
|
|
39
|
-
log.warn(
|
|
43
|
+
log.warn(`⚠️ No devices found in the original config!`);
|
|
44
|
+
log.warn(`🔍 *** Triggering device auto-discovery...`);
|
|
40
45
|
doDevicesAutoDiscovery = true;
|
|
46
|
+
} else {
|
|
47
|
+
// check if the device(s) in config is accessbile or not with retry up to 5 times, if not, set it to "undefined".
|
|
48
|
+
log.warn(`🕵️ *** Validating device IP address(es)...`);
|
|
49
|
+
const noOfDevices = config.devices.length;
|
|
50
|
+
for ( let i = 0; i < noOfDevices; i++ ) {
|
|
51
|
+
const ip = config.devices[i].ipAddress;
|
|
52
|
+
const port = config.devices[i].port || 2025;
|
|
53
|
+
if (ip) {
|
|
54
|
+
IPs.push(`${ip}:${port}`);
|
|
55
|
+
if ( !isValidIp(ip) ) {
|
|
56
|
+
log.warn(`⚠️ Device ${i + 1}/${noOfDevices} with IP ${ip}:${port} has its IP in wrong format!`);
|
|
57
|
+
log.warn(`⚠️ Device ${i + 1}/${noOfDevices} will NOT be processed!`);
|
|
58
|
+
IPs[i] = "undefined";
|
|
59
|
+
} else {
|
|
60
|
+
const isIpAccessibleTest = await isIpAccessible( `${ip}:${port}`, i, noOfDevices, log );
|
|
61
|
+
if ( !isIpAccessibleTest ) {
|
|
62
|
+
log.warn(`⚠️ Device ${i + 1}/${noOfDevices} with IP ${ip}:${port} is inaccessible! May be power OFF, wrong IP or wrong port.`);
|
|
63
|
+
log.warn(`⚠️ Device ${i + 1}/${noOfDevices} will NOT be processed!`);
|
|
64
|
+
IPs[i] = "undefined";
|
|
65
|
+
} else {
|
|
66
|
+
log.info(`✅ Device ${i + 1}/${noOfDevices} is reachable!`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
} else {
|
|
70
|
+
IPs.push("undefined");
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// check that not all IPs are "undefined", if so, do devucesAutoDiscovery...
|
|
74
|
+
if (IPs.every((el) => el === "undefined")) {
|
|
75
|
+
// final attempt to auto discover a Bond device
|
|
76
|
+
log.warn(`⚠️ No specified device is accessible on the LAN network!`);
|
|
77
|
+
log.warn(`🔍 *** Triggering device auto-discovery...`);
|
|
78
|
+
doDevicesAutoDiscovery = true;
|
|
79
|
+
}
|
|
41
80
|
}
|
|
42
81
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const { foundDevices, portsToTry: remainingPorts } =
|
|
48
|
-
await devicesAutoDiscovery(config, log, portsToTry);
|
|
82
|
+
// Auto-discovery stage
|
|
83
|
+
if ( doDevicesAutoDiscovery ) {
|
|
84
|
+
log.info("🔍 Ports to scan for devices:", portsToTry);
|
|
85
|
+
const foundDevices = await devicesAutoDiscovery(config, log, portsToTry);
|
|
49
86
|
|
|
50
|
-
|
|
51
|
-
|
|
87
|
+
const noOfDevices = foundDevices.length;
|
|
88
|
+
if (noOfDevices > 0) {
|
|
89
|
+
config.devices = foundDevices;
|
|
90
|
+
log.info("Devices config:\n" + JSON.stringify(config.devices, null, 2));
|
|
52
91
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
92
|
+
// Store found devices IPs
|
|
93
|
+
for ( let i = 0; i < noOfDevices; i++ ) {
|
|
94
|
+
IPs[i] = foundDevices[i].ipAddress + ':' + foundDevices[i].port;
|
|
95
|
+
}
|
|
96
|
+
} else {
|
|
97
|
+
log.warn("⚠️ No devices found on any ports.");
|
|
98
|
+
// check if an existing config.json is present in this.storagePath/.myplace, if so use it
|
|
99
|
+
existingConfig = readConfig( storagePath, log );
|
|
100
|
+
if (existingConfig) {
|
|
101
|
+
log.warn("⚠️ Proceeding with existing config — all cached accessories will be restored.");
|
|
102
|
+
return existingConfig;
|
|
56
103
|
} else {
|
|
57
|
-
log.warn("⚠️
|
|
58
|
-
|
|
59
|
-
existingConfig = readConfig( storagePath, log );
|
|
60
|
-
if (existingConfig) {
|
|
61
|
-
log.warn("⚠️ Proceeding with existing config — all cached accessories will be restored.");
|
|
62
|
-
return existingConfig;
|
|
63
|
-
} else {
|
|
64
|
-
log.warn("⚠️ Proceeding with original config — no accessories will be created and cached accessories will be removed!");
|
|
65
|
-
return config;
|
|
66
|
-
}
|
|
104
|
+
log.warn("⚠️ Proceeding with original config — no accessories will be created and cached accessories will be removed!");
|
|
105
|
+
return config;
|
|
67
106
|
}
|
|
68
107
|
}
|
|
108
|
+
}
|
|
69
109
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
));
|
|
76
|
-
|
|
77
|
-
try {
|
|
78
|
-
const myplaceConfig = await createMyPlaceConfig(config, pluginPath);
|
|
79
|
-
log.info(chalk.green("✅ DONE! createMyPlaceConfig completed successfully!"));
|
|
80
|
-
log.debug("Updated MyPlace config:\n" + JSON.stringify(myplaceConfig, null, 2));
|
|
81
|
-
|
|
82
|
-
// Enforce accessories limit
|
|
83
|
-
if (Array.isArray(myplaceConfig.accessories) &&
|
|
84
|
-
myplaceConfig.accessories.length > maxAccessories) {
|
|
85
|
-
log.warn(`⚠️ Configured accessories exceed limit of ${maxAccessories}. ` +
|
|
86
|
-
`Only the first ${maxAccessories} will be bridged, ` +
|
|
87
|
-
`${myplaceConfig.accessories.length - maxAccessories} ignored.`);
|
|
88
|
-
log.info("Note: Homebridge only allows a maximum of 149 bridged accessories per bridge.");
|
|
89
|
-
|
|
90
|
-
myplaceConfig.accessories = myplaceConfig.accessories.slice(0, maxAccessories);
|
|
91
|
-
}
|
|
110
|
+
// Run CreateMyPlaceConfig
|
|
111
|
+
log.warn(`*** Running createMyPlaceConfig...`);
|
|
112
|
+
try {
|
|
113
|
+
const noOfDevices = IPs.length;
|
|
114
|
+
const noOfDevicesProcessed = IPs.filter(ip => ip !== "undefined").length;
|
|
92
115
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
err.message.toLowerCase().includes(e)
|
|
100
|
-
);
|
|
101
|
-
|
|
102
|
-
if (doDevicesAutoDiscovery && portsToTry.length > 0) {
|
|
103
|
-
log.warn(`⚠️ ${err.message}`);
|
|
104
|
-
|
|
105
|
-
// Special handling for "inaccessible" errors - wait 5 seconds and retry up to 5 times
|
|
106
|
-
if (isInaccessibleError) {
|
|
107
|
-
const maxRetries = 5;
|
|
108
|
-
let retryCount = 0;
|
|
109
|
-
let retrySuccess = false;
|
|
110
|
-
let lastRetryError = err;
|
|
111
|
-
|
|
112
|
-
let deviceNumber = 1;
|
|
113
|
-
let ipAddress;
|
|
114
|
-
const match = err.message.match(/Device (\d+).*?IP ([\d.]+)/);
|
|
115
|
-
if (match) {
|
|
116
|
-
deviceNumber = parseInt(match[1], 10);
|
|
117
|
-
ipAddress = match[2];
|
|
118
|
-
}
|
|
116
|
+
const myplaceConfig = await createMyPlaceConfig(config, IPs, pluginPath, log);
|
|
117
|
+
if (doDevicesAutoDiscovery) {
|
|
118
|
+
log.info(`✅ DONE! createMyPlaceConfig completed successfully for ${noOfDevicesProcessed}/${noOfDevices} "auto-discovered" device(s)!`);
|
|
119
|
+
} else {
|
|
120
|
+
log.info(`✅ DONE! createMyPlaceConfig completed successfully for ${noOfDevicesProcessed}/${noOfDevices} device(s)!`);
|
|
121
|
+
}
|
|
119
122
|
|
|
120
|
-
|
|
121
|
-
retryCount++;
|
|
122
|
-
log.info(chalk.yellow(`⏳ Device ${deviceNumber} with IP ${ipAddress} is inaccessible, waiting 5 seconds before retry (${retryCount}/${maxRetries})...`));
|
|
123
|
-
await delay(5000);
|
|
124
|
-
|
|
125
|
-
// Retry createMyPlaceConfig immediately without auto-discovery
|
|
126
|
-
try {
|
|
127
|
-
log.info(chalk.yellow(`🔄 Retrying createMyPlaceConfig (attempt ${retryCount}/${maxRetries})...`));
|
|
128
|
-
const myplaceConfig = await createMyPlaceConfig(config, pluginPath);
|
|
129
|
-
log.info(chalk.green(`✅ SUCCESS! createMyPlaceConfig completed after ${retryCount} retry attempt(s)!`));
|
|
130
|
-
|
|
131
|
-
// Enforce accessories limit on retry success
|
|
132
|
-
if (Array.isArray(myplaceConfig.accessories) &&
|
|
133
|
-
myplaceConfig.accessories.length > maxAccessories) {
|
|
134
|
-
log.warn(`⚠️ Configured accessories exceed limit of ${maxAccessories}. ` +
|
|
135
|
-
`Only the first ${maxAccessories} will be bridged, ` +
|
|
136
|
-
`${myplaceConfig.accessories.length - maxAccessories} ignored.`);
|
|
137
|
-
myplaceConfig.accessories = myplaceConfig.accessories.slice(0, maxAccessories);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
return myplaceConfig;
|
|
141
|
-
} catch (retryErr) {
|
|
142
|
-
lastRetryError = retryErr;
|
|
143
|
-
log.warn(`⚠️ Retry attempt ${retryCount}/${maxRetries} failed: ${retryErr.message}`);
|
|
144
|
-
|
|
145
|
-
// Check if it's still an "inaccessible" error for the next retry
|
|
146
|
-
if (!retryErr.message.toLowerCase().includes("inaccessible")) {
|
|
147
|
-
log.warn("⚠️ Error type changed, stopping retries and proceeding to auto-discovery...");
|
|
148
|
-
break;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
}
|
|
123
|
+
log.debug("Updated MyPlace config:\n" + JSON.stringify(myplaceConfig));
|
|
152
124
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
125
|
+
// Enforce accessories limit
|
|
126
|
+
if (Array.isArray(myplaceConfig.accessories) &&
|
|
127
|
+
myplaceConfig.accessories.length > maxAccessories) {
|
|
128
|
+
log.warn(`⚠️ Configured accessories exceed limit of ${maxAccessories}. ` +
|
|
129
|
+
`Only the first ${maxAccessories} will be bridged, ` +
|
|
130
|
+
`${myplaceConfig.accessories.length - maxAccessories} ignored.`);
|
|
131
|
+
log.info("Note: Homebridge only allows a maximum of 149 bridged accessories per bridge.");
|
|
158
132
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
return existingConfig;
|
|
172
|
-
}
|
|
173
|
-
log.warn("⚠️ Proceeding with original config — no accessories will be created and cached accessories will be removed!");
|
|
174
|
-
return config;
|
|
175
|
-
}
|
|
133
|
+
myplaceConfig.accessories = myplaceConfig.accessories.slice(0, maxAccessories);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return myplaceConfig;
|
|
137
|
+
} catch (err) {
|
|
138
|
+
log.warn(`⚠️ ${err.message}`);
|
|
139
|
+
log.warn(`⚠️ Config not updated!`);
|
|
140
|
+
// check if an existing config.json is present in this.storagePath/.myplace, if so use it
|
|
141
|
+
existingConfig = readConfig( storagePath, log );
|
|
142
|
+
if (existingConfig) {
|
|
143
|
+
log.warn(`⚠️ Proceeding with existing config — all cached accessories will be restored.`);
|
|
144
|
+
return existingConfig;
|
|
176
145
|
}
|
|
146
|
+
log.warn(`⚠️ Proceeding with original config — no accessories will be created and cached accessories will be removed!`);
|
|
147
|
+
return config;
|
|
177
148
|
}
|
|
178
149
|
|
|
179
150
|
return config; // fallback
|