Recently Athom had a small poll on Slack to gauge how many devices people have.
This made me think of a script I had been working on for some time (also some time ago) using HomeyScript to make a (complete) overview of your current Homey Pro.
This means amount of flows, devices, apps, etc.
With this thread I was going to share this very Script, as I was also kind of curious what other people have (if they are willing to share their results of course).
It won’t expose any sensitive data, so you don’t have to worry about that. (the first reply will be my result if you want to see an example).
But have also added some extra (useful) options, to show names of for example broken or disabled flows, or disabled apps.
And just, doesn’t anyone else want to see what they have spent all their hard earned money on in an easy to see list?
How to use:
I’ve tried to make the script somewhat user friendly to use.
The only thing you need is an Homey Pro (any version, besides Homey (Cloud)) and the app HomeyScript.
When you have that app installed you can go to the Web GUI => Scripts and click on “New HomeyScript” on the bottom-left of the page.
A new script will get created and you can give it a name (not mandatory, just easier to find it back later on), “Homey Overview” is a good example
Then all you need to do is copy and paste the entire script below (it is pretty large, 460 lines) into the top field, and press the “Save” button.
Then to see the result all you have to do is press “Test”, and behold the results will show up below it (it can take a few seconds to retrieve all information from Homey Pro).
(Tip: you can increase the result’s view by dragging the “Output” line, up).
Changelog:
- v1.5 (14 March '23):
- Added error information for Homey Pro (early 2023) users as HomeyScript needs an update to support the
getAppSettings()
function - Fix when no HomeyScript tokens (again)
- Added error information for Homey Pro (early 2023) users as HomeyScript needs an update to support the
- v1.4 (11 March '23):
- Added amount of HomeyScripts
- v1.3 (11 March '23):
- Fix when no HomeyScript tokens
- v1.2 (11 March '23):
- Added amount of: HomeyScript tokens, Better Logic Variables;
- Added some error catching if anything fails, it will continue on;
- v1.1 (11 March '23):
- Fixed the Z-Wave count.
I used a bad way before, now it is more accurate and includes the different security levels; - Added Chronograph and Better Logic Library for Virtual Devices count;
- Fixed the Z-Wave count.
- v1 (10 March '23):
- Initial release;
Note:
The Z-Wave count for battery and router devices can be slightly wrong to your actual real life devices, as Homey doesn’t expose what a actual router or battery device is, there is a “battery” flag but that is false
for FLiRS devices like “newer” thermostats (Eurotronic Spirit or Fibaro Thermostatic).
I’ve tried to fix it as accurate as possible by also looking if there are batteries specified for the device.
But also this isn’t the case for every device like the Aeotec Siren 6, which has a battery, but that is only for backup reasons and thus pretty much always connected to the mains.
This is just the best I could do without having to manual configure every device that should be excluded, which is too much work for just an Overview Script.
Count down and/or other apps
I won’t be adding the countdown apps, there are 4 different ones, and is getting a bit too much that way.
Other apps will most likely also not be added, or in the end the script will contain all apps.
Disclaimer:
It should work with all Homey Pros, including the new 2023 version, but if you encounter an issue, feel free to say so and I will try to fix it as soon as possible.
Please do keep the thread clean, any non related replies will get deleted!
If you have (general) questions about HomeyScript or the used Web API, then this is not the thread for that.
The Script v1.5:
// Set any of these from `false;` to `true;` to see the corresponding Name(s) or Node ID('s) added to the list
const showUpdateableApps = false; // Names of Apps that can be updated
const showDisabledApps = false; // Names of Apps that are disabled or crashed
const showSDKv2Apps = false; // Names of Apps that are on SDKv2
const showSDKv3Apps = false; // Names of Apps that are on SDKv3
const showDisabledFlows = false; // Names of Flows that are disabled
const showBrokenFlows = false; // Names of Flows that are broken
const showDisabledAdvancedFlows = false; // Names of Advanced Flows that are disabled
const showBrokenAdvancedFlows = false; // Names of Advanced Flows that are broken
const showZwaveDevices = false; // Names of all Z-Wave devices
const showZwaveRouterDevices = false; // Names of Z-Wave router devices
const showZwaveUnsecureDevices = false; // Names of unsecure Z-Wave devices
const showZwaveSecureS0Devices = false; // Names of secure (S0) Z-Wave devices
const showZwaveSecureS2AuthenticatedDevices = false; // Names of secure (S2 Authenticated) Z-Wave devices
const showZwaveSecureS2UnauthenticatedDevices = false; // Names of secure (S2 Unauthenticated) Z-Wave devices
const showZwaveBatteryDevices = false; // Names of Z-Wave battery devices
const showZwaveUnreachableNodes = false; // Node ID's of unreachable (flagged) devices
const showZwaveUnknownNodes = false; // Node ID's of unknown nodes
const showZigbeeNodes = false; // Names of all ZigBee devices
const showZigbeeRouter = false; // Names of ZigBee: router devices
const showZigbeeEndDevice = false; // Names of ZigBee: end device devices
const showVirtualDevices = false; // Names of all Virtual devices
const showIRDevices = false; // Names of all InfraRed devices
// ================= Don't edit anything below here =================
log('--------------- Homey Pro Overview v1.5 --------------');
await Homey.system.getSystemName()
.then(result => log('Homey name:', result))
.catch(() => log('Failed: Getting Homey Name'));
let homeyPlatformVersion;
await Homey.system.getInfo()
.then(result => {
log('Homey version:', result.homeyVersion);
log('Homey model:', result.homeyModelName, '(' + result.cpus.length + ' core(s))');
homeyPlatformVersion = result.homeyPlatformVersion || 1;
const d = Math.floor(result.uptime / (3600*24));
const h = Math.floor(result.uptime % (3600*24) / 3600);
const m = Math.floor(result.uptime % 3600 / 60);
const s = Math.floor(result.uptime % 60);
const dDisplay = d > 0 ? d + (d == 1 ? " day, " : " days, ") : "";
const hDisplay = h > 0 ? h + (h == 1 ? " hour, " : " hours, ") : "";
const mDisplay = m > 0 ? m + (m == 1 ? " minute, " : " minutes, ") : "";
const sDisplay = s > 0 ? s + (s == 1 ? " second" : " seconds") : "";
log('Uptime:', result.uptime, '(' + dDisplay + hDisplay + mDisplay + sDisplay + ')');
if (homeyPlatformVersion === 2) {
log('WiFi:', (result.wifiConnected) ? 'connected' : 'not connected');
log('Ethernet:', (result.ethernetConnected) ? 'connected' : 'not connected');
}
})
.catch(() => log('Failed: Getting Homey Stats'));
await Homey.updates.getUpdates()
.then(result => {
if(result.length > 0) {
log('Update available:', result[0].version);
} else {
log('Update available: None');
}
})
.catch(() => log('Failed: Getting Updates'));
log('\r\n------------------ Main ---------------------');
await Homey.users.getUsers()
.then(result => {
let owner = 0, manager = 0, user = 0, guest = 0;
Object.keys(result).forEach(function(key) {
if (result[key].role === 'owner') owner++;
if (result[key].role === 'manager') manager++;
if (result[key].role === 'user') user++;
if (result[key].role === 'guest') guest++;
});
log(Object.keys(result).length, 'Users', '(' + owner + ' owner, ' + manager + ' manager(s), ' + user + ' user(s), ' + guest + ' guest(s))');
})
.catch(() => log('Failed: Getting Users'));
await Homey.apps.getApps()
.then(result => {
let sdkv2 = 0, sdkv2Apps = [], sdkv3 = 0, sdkv3Apps = [], updateable = 0, updateableApps = [], disabled = 0, disabledApps = [];
Object.keys(result).forEach(function(key) {
if (result[key].updateAvailable) {
updateable++;
updateableApps.push(result[key].name);
}
if (result[key].sdk === 2) {
sdkv2++;
sdkv2Apps.push(result[key].name);
}
if (
result[key].sdk === 3
|| homeyPlatformVersion === 2
) {
sdkv3++;
sdkv3Apps.push(result[key].name);
}
if (!result[key].ready) {
disabled++;
disabledApps.push(result[key].name);
}
});
if (showSDKv2Apps) {
log('---------------------------------------------')
log('SDKv2 apps:');
log(sdkv2Apps.join('\r\n'));
log('---------------------------------------------')
}
if (showSDKv3Apps) {
log('---------------------------------------------')
log('SDKv3 apps:');
log(sdkv3Apps.join('\r\n'));
log('---------------------------------------------')
}
if (showUpdateableApps) {
log('---------------------------------------------')
log('Updateable apps:');
log(updateableApps.join('\r\n'));
log('---------------------------------------------')
}
if (showDisabledApps) {
log('---------------------------------------------')
log('Disabled apps:');
log(disabledApps.join('\r\n'));
log('---------------------------------------------')
}
log(Object.keys(result).length, 'Apps', '(' + sdkv2 + ' SDKv2, ' + sdkv3 + ' SDKv3, ' + updateable + ' updateable, ' + disabled + ' disabled/crashed)');
})
.catch(() => log('Failed: Getting Apps'));
await Homey.zones.getZones()
.then(result => log(Object.keys(result).length, 'Zones'))
.catch(() => log('Failed: Getting Zones'));
await Homey.notifications.getNotifications()
.then(result => log(Object.keys(result).length || 0, 'Notifications (Timeline)'))
.catch(() => log('Failed: Getting Notifications'));
await Homey.logic.getVariables()
.then(result => {
let boolean = 0, number = 0, string = 0;
Object.keys(result).forEach(function(key) {
if (result[key].type === 'boolean') boolean++;
if (result[key].type === 'number') number++;
if (result[key].type === 'string') string++;
});
log(Object.keys(result).length, 'Logic Variables', '(' + boolean + ' boolean (yes/no), ' + number + ' number, ' + string + ' string)');
})
.catch(() => log('Failed: Getting Variables'));
await Homey.flow.getFlows()
.then(result => {
let disabled = 0, broken = 0, disabledNames = [], brokenNames = [];
Object.keys(result).forEach(function(key) {
if (!result[key].enabled) {
disabled++;
disabledNames.push(result[key].name);
}
if (result[key].broken) {
broken++;
brokenNames.push(result[key].name);
}
});
if (showDisabledFlows) {
log('---------------------------------------------')
log('Disabled flow names:');
log(disabledNames.join('\r\n'));
log('---------------------------------------------')
}
if (showBrokenFlows) {
log('---------------------------------------------')
log('Broken flow names:');
log(brokenNames.join('\r\n'));
log('---------------------------------------------')
}
log(Object.keys(result).length, 'Flows', '(' + broken + ' broken, ' + disabled + ' disabled)');
})
.catch(() => log('Failed: Getting Flows'));
await Homey.flow.getAdvancedFlows()
.then(result => {
let disabled = 0, broken = 0, disabledNames = [], brokenNames = [];
Object.keys(result).forEach(function(key) {
if (!result[key].enabled) {
disabled++;
disabledNames.push(result[key].name);
}
if (result[key].broken) {
broken++;
brokenNames.push(result[key].name);
}
});
if (showDisabledAdvancedFlows) {
log('---------------------------------------------')
log('Disabled advanced flow names:');
log(disabledNames.join('\r\n'));
log('---------------------------------------------')
}
if (showBrokenAdvancedFlows) {
log('---------------------------------------------')
log('Broken advanced flow names:');
log(brokenNames.join('\r\n'));
log('---------------------------------------------')
}
log(Object.keys(result).length, 'Advanced flows', '(' + broken + ' broken, ' + disabled + ' disabled)');
})
.catch(() => log('Failed: Getting Advanced Flows'));
await Homey.apps.getAppSettings({id: 'com.athom.homeyscript'})
.then(result => {
log(Object.keys(result.scripts).length, 'HomeyScript scripts', '(' + ((result.tokens) ? Object.keys(result.tokens).length : 0) + ' tokens/tags)');
})
.catch(() => {
if (homeyPlatformVersion === 2) {
log('Failed: Getting HomeyScript, Homey Pro (early 2023): getting information from apps is currently unavailable.');
}
else {
log('Failed: Getting HomeyScript');
}
});
await Homey.apps.getAppSettings({id: 'net.i-dev.betterlogic'})
.then(result => {
let boolean = 0, number = 0, string = 0;
Object.keys(result.variables).forEach(function(key) {
if (result.variables[key].type === 'boolean') boolean++;
if (result.variables[key].type === 'number') number++;
if (result.variables[key].type === 'string') string++;
});
log(Object.keys(result.variables).length, 'Better Logic Variables', '(' + boolean + ' boolean (yes/no), ' + number + ' number, ' + string + ' string)');
})
.catch(() => {
if (homeyPlatformVersion === 2) {
log('Failed: Getting Better logic, Homey Pro (early 2023): getting information from apps is currently unavailable.');
}
});
log('\r\n----------------- Devices -------------------');
let allDevices = 0, zwave = 0, zwaveDevices = [], zwaveNodes = [], zwaveRouter = 0, zwaveRouterDevices = [], zwaveBattery = 0, zwaveBatteryDevices = [], zwaveSx = 0, zwaveSxDevices = [], zwaveS0 = 0, zwaveS0Devices = [], zwaveS2Auth = 0, zwaveS2AuthDevices = [], zwaveS2Unauth = 0, zwaveS2UnauthDevices = [];
await Homey.devices.getDevices()
.then(result => {
let virtual = 0, ir = 0, other = 0, virtualNames = [], irNames = [];
Object.keys(result).forEach(function(key) {
if (result[key].driverUri === 'homey:manager:vdevice') {
if (result[key].driverId === 'infraredbasic') {
ir++;
irNames.push(result[key].name);
}
else {
virtual++
virtualNames.push(result[key].name);
}
}
else if (
result[key].driverUri === 'homey:app:com.arjankranenburg.virtual'
|| result[key].driverUri === 'homey:app:nl.qluster-it.DeviceCapabilities'
|| result[key].driverUri === 'homey:app:nl.fellownet.chronograph'
|| result[key].driverUri === 'homey:app:net.i-dev.betterlogic'
) {
virtual++
virtualNames.push(result[key].name);
}
else if (result[key].flags.includes('zwaveRoot')) {
zwave++;
zwaveDevices.push(result[key].name);
zwaveNodes.push(Number(result[key].settings.zw_node_id));
if (
result[key].settings.zw_battery === '✓'
|| result[key].energyObj.batteries
) {
zwaveBattery++;
zwaveBatteryDevices.push(result[key].name);
} else {
zwaveRouter++;
zwaveRouterDevices.push(result[key].name);
}
if (result[key].settings.zw_secure === '⨯') {
zwaveSx++;
zwaveSxDevices.push(result[key].name);
} else if (
result[key].settings.zw_secure === '✓'
|| result[key].settings.zw_secure === 'S0'
) {
zwaveS0++;
zwaveS0Devices.push(result[key].name);
} else if (result[key].settings.zw_secure === 'S2 (Authenticated)') {
zwaveS2Auth++;
zwaveS2AuthDevices.push(result[key].name);
} else if (result[key].settings.zw_secure === 'S2 (Unauthenticated)') {
zwaveS2Unauth++;
zwaveS2UnauthDevices.push(result[key].name);
}
}
else if (
!result[key].flags.includes('zwave')
&& !result[key].flags.includes('zigbee')
) {
other++;
}
});
if (showVirtualDevices) {
log('---------------------------------------------')
log('Virtual devices:');
log(virtualNames.sort((a, b) => a - b).join('\r\n'));
log('---------------------------------------------')
}
if (showIRDevices) {
log('---------------------------------------------')
log('Infrared devices:');
log(irNames.sort((a, b) => a - b).join('\r\n'));
log('---------------------------------------------')
}
allDevices += virtual + ir + other + zwave;
log(virtual, 'Virtual devices');
log(ir, 'Infrared (database) devices');
log(other, 'Other devices');
})
.catch(() => log('Failed: Getting Devices'));
await Homey.zwave.getState()
.then(result => {
let unknownNodes = result.zw_state.nodes.filter((el) => !zwaveNodes.includes(el)).sort((a, b) => a - b);
unknownNodes.shift();
if (showZwaveDevices) {
log('---------------------------------------------')
log('Z-Wave devices:');
log(zwaveDevices.join('\r\n'));
log('---------------------------------------------')
}
if (showZwaveRouterDevices) {
log('---------------------------------------------')
log('Z-Wave router devices:');
log(zwaveRouterDevices.sort((a, b) => a - b).join('\r\n'));
log('---------------------------------------------')
}
if (showZwaveUnsecureDevices) {
log('---------------------------------------------')
log('Z-Wave unsecure devices:');
log(zwaveSxDevices.sort((a, b) => a - b).join('\r\n'));
log('---------------------------------------------')
}
if (showZwaveSecureS0Devices) {
log('---------------------------------------------')
log('Z-Wave secure (S0) devices:');
log(zwaveS0Devices.sort((a, b) => a - b).join('\r\n'));
log('---------------------------------------------')
}
if (showZwaveSecureS2AuthenticatedDevices) {
log('---------------------------------------------')
log('Z-Wave secure (S2) authenticated devices:');
log(zwaveS2AuthDevices.sort((a, b) => a - b).join('\r\n'));
log('---------------------------------------------')
}
if (showZwaveSecureS2UnauthenticatedDevices) {
log('---------------------------------------------')
log('Z-Wave secure (S2) Unauthenticated devices:');
log(zwaveS2Unauth.sort((a, b) => a - b).join('\r\n'));
log('---------------------------------------------')
}
if (showZwaveBatteryDevices) {
log('---------------------------------------------')
log('Z-Wave battery devices:');
log(zwaveBatteryDevices.sort((a, b) => a - b).join('\r\n'));
log('---------------------------------------------')
}
if (showZwaveUnreachableNodes) {
log('---------------------------------------------')
log('Unreachable nodes:');
log('Node ID:', result.zw_state.noAckNodes.sort((a, b) => a - b).join('\r\nNode ID: '));
log('---------------------------------------------')
}
if (showZwaveUnknownNodes) {
log('---------------------------------------------')
log('Unknown nodes:');
log('Node ID:', unknownNodes.join('\r\nNode ID: '));
log('---------------------------------------------')
}
log(zwave, 'Z-Wave nodes', '(' + zwaveSx + ' Unsecure, ' + zwaveS0 + ' Secure (S0), ' + zwaveS2Auth + ' Secure (S2 Authenticated), ' + zwaveS2Unauth + ' Secure (S2 Unauthenticated), ' + zwaveRouter + ' router, ' + zwaveBattery + ' battery, ' + result.zw_state.noAckNodes.length + ' unreachable, ' + unknownNodes.length + ' Unknown node(s))')
})
.catch(() => log('Failed: Getting Z-Wave State'));
await Homey.zigBee.getState()
.then(result => {
let zigbeeDevices = [], router = 0, routerDevices = [], endDevice = 0, endDevices = [];
Object.keys(result.nodes).forEach(function(key) {
zigbeeDevices.push(result.nodes[key].name);
if (result.nodes[key].type === 'Router') {
router++;
routerDevices.push(result.nodes[key].name);
}
if (result.nodes[key].type === 'EndDevice') {
endDevice++;
endDevices.push(result.nodes[key].name);
}
});
if (showZigbeeNodes) {
log('---------------------------------------------')
log('ZigBee nodes:');
log(zigbeeDevices.join('\r\n'));
log('---------------------------------------------')
}
if (showZigbeeRouter) {
log('---------------------------------------------')
log('ZigBee routers:');
log(routerDevices.sort((a, b) => a - b).join('\r\n'));
log('---------------------------------------------')
}
if (showZigbeeEndDevice) {
log('---------------------------------------------')
log('ZigBee end devices:');
log(endDevices.sort((a, b) => a - b).join('\r\n'));
log('---------------------------------------------')
}
allDevices += Object.keys(result.nodes).length;
log(Object.keys(result.nodes).length, 'Zigbee nodes', '(' + router + ' router, ' + endDevice + ' end device)');
})
.catch(() => log('Failed: Getting ZigBee State'));
log(allDevices, 'Total devices')
return 'Overview finished';