/** * Device Health Status - application for Hubitat Elevation hub * * https://community.hubitat.com/t/project-alpha-device-health-status/111817 * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License * for the specific language governing permissions and limitations under the License. * * Based on "Light Usage Table" Hubitat sample code by Bruce Ravenel * * ver. 1.0.0 2023-02-03 kkossev - first version: 'Light Usage Table' sample app code modification * ver. 1.0.1 2023-02-03 kkossev - added powerSource, battery, model, manufacturer, driver name; added option to skip the 'capability.healthCheck' filtering; * ver. 1.0.2 2023-02-03 FriedCheese2006 - Tweaks to Install Process * ver. 1.0.3 2023-02-03 tonesto7 - Added last activity date; kkossev - importUrl; documentationLink; app version; debug and info logs options; added controller type, driver type; added an option to filter battery-powered only devices, hide poweSource column; filterHealthCheckOnly bug fix; * -last activity thresholds and color options; battery threshold option; catching some exceptions when a device is deleted from HE, but was present in the list; added device status * ver. 1.0.4 2023-02-06 kkossev - added 'Device Status' red/green colors; added hideModelAndManufacturerColumns and hideVirtualAndUnknownDevices filtering options; app instance name can be changed; added Presence column * ver. 1.0.5 2023-02-08 kkossev - added toggle "Show only offline (INACTIVE / not present) devices" * ver. 1.0.6 2023-02-15 kkossev - IntelliJ lint; merged Tonesto7 pull request; * ver. 1.0.7 2023-02-16 FriedCheese2006 - Added DataTables for enhance table sorting/searching * ver. 1.0.8 2023-11-12 kkossev - added "MAT" controllerType * * TODO: */ import groovy.transform.Field def version() { "1.0.8" } def timeStamp() { "2023/11/12 10:45 AM" } @Field static final Boolean debug = false definition( name: "Device Health Status", namespace: "kkossev", author: "Krassimir Kossev", description: "Device Health Status", category: "Utility", iconUrl: "", iconX2Url: "", importUrl: "https://raw.githubusercontent.com/kkossev/Hubitat/main/Apps/Device%20Health%20Status.groovy", documentationLink: "https://community.hubitat.com/t/alpha-device-health-status/111817/1" ) preferences { page(name: "mainPage") } def mainPage() { if (state.devices == null) state.devices = [:] if (state.devicesList == null) state.devicesList = [] if (app.getInstallationState() == "COMPLETE") { hideDevices = true } else { hideDevices = false } dynamicPage(name: "mainPage", title: "Device Health Status (app ver. ${driverVersionAndTimeStamp()})", uninstall: true, install: true) { section("Device Selection", hideable: true, hidden: hideDevices) { input name: "devices", type: settings?.selectHealthCheckOnly == true ? "capability.healthCheck" : "capability.*", title: "Select devices", multiple: true, submitOnChange: true, width: 4 logDebug "Device Selection : start" devices.each { dev -> if (!state.devices["$dev.id"]) { //logDebug "Device Selection : new device ${state.devices["$dev.id"]}" } else { //logDebug "Device Selection : existing device ${state.devices["$dev.id"]}" } try { if (dev != null && dev?.status != null) { //log.trace 'status = ${dev.status} (device ${state.devices["$dev.id"]})' def hasBattery = dev.capabilities.find { it.toString().contains('Battery') } ? true : false def hasPowerSource = dev.capabilities.find { it.toString().contains('PowerSource') } ? true : false state.devices["$dev.id"] = [ healthStatus : dev.currentValue("healthStatus"), hasPowerSource: hasPowerSource, hasBattery : hasBattery ] state.devicesList += dev.id } else { logWarn "dev is null? state.devices[dev.id] is ${state.devices["$dev.id"]}" } } catch (e) { logWarn "exception catched when procesing device ${dev.id}" } } if (devices) { if (devices.id.sort() != state.devicesList.sort()) { //something was removed logDebug "Device Selection : something was changed" state.devicesList = devices.id Map newState = [:] devices.each { d -> newState["$d.id"] = state.devices["$d.id"] } state.devices = newState } else { logDebug "Device Selection : no changes" } } else { logWarn "Device Selection : devices = ${devices}" } logDebug "Device Selection : start" } // section "Device Selection" if (hideDevices) { section { updated() paragraph "" input name: "showOfflineOnly", type: "bool", title: "Show only offline (INACTIVE / not present) devices", submitOnChange: true, defaultValue: false paragraph "" paragraph displayTable() input "refresh", "button", title: "Refresh Table", width: 2 } section("Options", hideable: true, hidden: hideDevices) { label title: "Change this Device Health Status app instance name:", submitOnChange: true, required: false paragraph "" input("logEnable", "bool", title: "Debug logging.", defaultValue: false, required: false) input("txtEnable", "bool", title: "Description text logging.", defaultValue: false, required: false) paragraph "" paragraph "Device selection options:" input name: "selectHealthCheckOnly", type: "bool", title: "Select only devices that have 'Healtch Check' capability", submitOnChange: true, defaultValue: false paragraph "" paragraph "Table filtering options: columns :" input name: "hidePowerSourceColumn", type: "bool", title: "Hide powerSource column", submitOnChange: true, defaultValue: false input name: "hideLastActivityAtColumn", type: "bool", title: "Hide LastActivityAt column", submitOnChange: true, defaultValue: false input name: "hideModelAndManufacturerColumns", type: "bool", title: "Hide Model and Manufacturer columns", submitOnChange: true, defaultValue: false input name: "hidePresenceColumn", type: "bool", title: "Hide Presence column (the one that we are trying to depricate)", submitOnChange: true, defaultValue: true paragraph "" paragraph "Table filtering options: rows :" input name: "hideNotBatteryDevices", type: "bool", title: "Hide not battery-powered devices", submitOnChange: true, defaultValue: false input name: "hideNoHealthStatusAttributeDevices", type: "bool", title: "Hide devices without healthStatus attribute", submitOnChange: true, defaultValue: false input name: "hideVirtualAndUnknownDevices", type: "bool", title: "Hide virtual/unknown type devices", submitOnChange: true, defaultValue: false paragraph "" paragraph "Thresholds :" input name: "lastActivityGreen", type: "number", title: "Devices w/ lastActivity less than N hours will be shown in green", submitOnChange: true, defaultValue: 9 input name: "lastActivityRed", type: "number", title: "Devices w/ lastActivity more than N hours will be shown in red", submitOnChange: true, defaultValue: 25 input name: "batteryLowThreshold", type: "number", title: "Devices w/ Battery percentage below N % will be shown in red", submitOnChange: true, defaultValue: 33 } } else { section("CLICK DONE TO INSTALL APP AFTER SELECTING DEVICES") { paragraph "" } } } } String displayTable() { String str = "" //Import DataTables library str += "" str += "" str += "