Is there a way to dynamically define child apps in a parent based on whether or not the apps code is actually installed?
My child apps listing is a little long in the tooth. My thoughts are to make the child apps optional in HPM and only show those that are installed.
Not a neatly packaged one but @gavincampbell posted this code (or something very close) a while back for getting installed apps.
def getAppsList() {
def params = [
uri: "http://127.0.0.1:8080/app/list",
textParser: true,
headers: [
Cookie: state.cookie
]
]
def allAppsList = []
def allAppNames = []
try {
httpGet(params) { resp ->
def matcherText = resp.data.text.replace("\n","").replace("\r","")
def matcher = matcherText.findAll(/(<tr class="app-row" data-app-id="[^<>]+">.*?<\/tr>)/).each {
def allFields = it.findAll(/(<td .*?<\/td>)/) // { match,f -> return f }
def id = it.find(/data-app-id="([^"]+)"/) { match,i -> return i.trim() }
def title = allFields[0].find(/title="([^"]+)/) { match,t -> return t.trim() }
allAppsList += [id:id,title:title]
allAppNames << title
}
}
} catch (e) {
log.error "Error retrieving installed apps: ${e}"
log.error(getExceptionMessageWithLine(e))
}
state.allAppNames = allAppNames.sort { a, b -> a.toLowerCase() <=> b.toLowerCase() }
}
Shouldn’t be too hard to point it at the apps code tab and process similarly
3 Likes
@thebearmay ...I don't know if anyone has told you lately, but you are a gem.
@gavincampbell ...thanks for coming up with this excellent approach.
This is actually looking at the apps code list. I've never really paid attention until now, but /app/list/ is the code section and /installedapp/list/ is the normal apps page.
I did make a few tweaks as the IDE was complaining about the code as posted. I also dropped the ID portions as I don't need it for my use-case.
Revised Code
def getAppsList() {
def params = [
uri: "http://127.0.0.1:8080/app/list",
textParser: true,
headers: [
Cookie: state.cookie
]
]
def allAppNames = []
try {
httpGet(params) { resp ->
def matcherText = resp.data.text.replace("\n","").replace("\r","")
def matcher = matcherText.findAll(/(<tr class="app-row" data-app-id="[^<>]+">.*?<\/tr>)/).each {
def allFields = it.findAll(/(<td .*?<\/td>)/) // { match,f -> return f }
def title = allFields[0].find(/title="([^"]+)/) { match,t -> return t.trim() }
allAppNames.add(title)
}
}
} catch (e) {
log.error "Error retrieving installed apps: ${e}"
log.error(getExceptionMessageWithLine(e))
}
state.allAppNames = allAppNames.sort()
}
Followed by a simple IF statement in the dynamic page:
if ("Sensor Groups+_CO" in state.allAppNames) {
app(name: "coApp+", appName: "Sensor Groups+_CO", namespace: "rle.sg+", title: "Add a new CO Sensor Group+ Instance", multiple: true)
}
With the child app installed:
With the child app deleted:
2 Likes
Going one step farther...I dumped my child apps into a variable and was able to whittle down generating the entire child app list.
def childApps = ["Sensor Groups+_CO","Sensor Groups+_Contact","Sensor Groups+_Humidity","Sensor Groups+_Motion","Sensor Groups+_Smoke","Sensor Groups+_Switch","Sensor Groups+_Temp","Sensor Groups+_Water"]
logDebug "Installed apps are ${state.allAppNames}"
if(state.appInstalled == 'COMPLETE'){
section("${app.label}") {
paragraph "Provides options for combining multiple sensors into a single device to provide combined updates."
}
section("Child Apps") {
childApps.each { it ->
if (it in state.allAppNames) {
app(name: it+"App+", appName: it, namespace: "rle.sg+", title: "Add a new ${it} Instance", multiple: true)
} else {
logDebug "${it} not installed."
}
}
}
tomw
September 25, 2022, 5:18pm
5
I do it like this:
def isAppInstalled(name)
{
def result
try
{
def app = addChildApp("tomw", name, name)
deleteChildApp(app.id)
result = true
}
catch(hubitat.exception.NotFoundException e)
{
result = false
}
finally
{
return result
}
}
Is that just trying to create a child app to see if HE throws and error or not (indicating whether or not the app code is installed)?
tomw
September 25, 2022, 5:40pm
7
Yes. As long as they don't change the exception they raise, this will always work. I prefer it to string parsing the HTML page.
Here's how I use it in a dynamicPage:
if(isAppInstalled("Presence Debounce"))
{
app(name: "anyOpenApp", appName: "Presence Debounce", namespace: "tomw", title: "<b>Add a new Presence Debounce instance</b>", multiple: true)
}
1 Like
system
Closed
September 25, 2023, 5:41pm
8
This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.