I was interested in the opposite… How to get a list of Apps that are “not used” (but consuming memory)… Asking help to Gemini, here is something that works for me.
/**
* Universal script to list unused apps.
* This version uses a broad inclusion check to avoid false positives.
*/
const apps = await Homey.apps.getApps();
const devices = await Homey.devices.getDevices();
const unusedApps = Object.values(apps).filter(app => {
// We check if ANY device points to this app's ID
const isUsed = Object.values(devices).some(device => {
if (!device) return false;
const uri = device.driverUri || "";
const driverId = device.driverId || "";
// Check if the app ID is mentioned in the URI or the Driver ID
return uri.includes(app.id) || driverId.includes(app.id);
});
// We only keep apps that are NOT used
return !isUsed;
});
// Formatting the output
const results = unusedApps.map(app => `- ${app.name} [v${app.version}] (${app.id})`);
console.log("--- Analysis of Installed Apps ---");
if (results.length > 0) {
console.log(`Found ${results.length} app(s) with no devices configured:`);
console.log(results.join('\n'));
} else {
console.log("All installed apps are currently used by at least one device.");
}
return results.length > 0;
I did ask now to get a script that list all Apps and their devices… It gives me the very same list as the Homey web page “Devices” in “List” mode…
/**
* Script to list ALL devices, including those without an explicit app ("-" in the page "devices".
*/
const apps = await Homey.apps.getApps();
const devices = await Homey.devices.getDevices();
const zones = await Homey.zones.getZones();
const zoneMap = {};
Object.values(zones).forEach(z => zoneMap[z.id] = z.name);
const appDeviceMap = {};
const orphanDevices = [];
// Init map
Object.values(apps).forEach(app => {
appDeviceMap[app.id] = { name: app.name, version: app.version, devices: [] };
});
Object.values(devices).forEach(device => {
if (!device) return;
const uri = device.driverUri || "";
const driverId = device.driverId || "";
const zoneName = zoneMap[device.zone] || "Unknown Zone";
const deviceLabel = `${device.name} [${zoneName}]`;
const parentApp = Object.values(apps).find(app =>
uri.includes(app.id) || driverId.includes(app.id)
);
if (parentApp) {
appDeviceMap[parentApp.id].devices.push(deviceLabel);
} else {
// Capture devices that don't match any installed app
orphanDevices.push(deviceLabel);
}
});
// Output
console.log("--- Apps and their associated Devices ---");
Object.keys(appDeviceMap).sort().forEach(appId => {
const data = appDeviceMap[appId];
if (data.devices.length > 0) {
console.log(`\n📦 ${data.name} (${appId})`);
data.devices.sort().forEach(d => console.log(` âž” ${d}`));
}
});
if (orphanDevices.length > 0) {
console.log(`\n⚠️ Internal / Unlinked Devices (No App ID found)`);
orphanDevices.sort().forEach(d => console.log(` âž” ${d}`));
}
return true;