DynamicPage with refreshInterval not updating when first or only preferences page

I’m trying to write a smartapp, but if I use a dynamicPage(…, refreshInterval:5,…) as the first preferences page, the page never refreshes.

definition(
    name: "TestApp",
    namespace: "raven42",
    author: "David Hegland",
    description: "testing",
    category: "",
    iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
    iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
    iconX3Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png")

preferences {
    page(name: "testFunc", title: "Test Func", content: "testFunc")
}

def testFunc() {
    log.debug 'testFunc()'
    dynamicPage(name: "testFunc", title: "Test Func", nextPage: "", refreshInterval: 5, install: true, uninstall: true) {
        section("Example...") {
        }
    }
}

If I use this code, I only ever see a single testFunc() log message. I’ve tried different refreshIntervals and never see another log entry from the app.

If changed to the following:

preferences {
    page(name: "init", title: "Initial page", content: "init", nextPage: "testFunc")
    page(name: "testFunc", title: "Test Func", content: "testFunc")
}

def init() {
	log.debug 'init()'
    dynamicPage(name: "init", title: "Initial page", nextPage: "testFunc", install: false, uninstall: true) {
    	section("Click next to proceed.") { }
    }
}

def testFunc() {
    log.debug 'testFunc()'
    dynamicPage(name: "testFunc", title: "Test Func", nextPage: "", refreshInterval: 5, install: true, uninstall: true) {
        section("Example...") { }
    }
}

Then now the second page (testFunc) does refresh correctly every 5 seconds.

However now there is another issue where now there is no cancel button to uninstall the app despite uninstall:true being set.

Welcome, @raven42! Can you give me more details about the purpose of your SmartApp, please?
For example, why the refreshInterval is needed.
The code you shared is from a Groovy SmartApp, which is part of our legacy platform. It’s important you look at the announcement below so you can take precautions.

I’m writing an app to do a LAN discovery of some devices on my network. So the first thing I do is kick off a SSDP poll event, then set the preferences page to a refreshInterval of 5 so the smartapp can check for the response and then then when the preferences page refreshed, it will have the the data populated by the ssdpParser routine. Basic code flow is like this (simplified for posting here). Also, I am doing this all in the new app and the current IDE from the smartthings hub page, is there a new one somewhere that I should be using? I have not been able to find anything about something else new.

preferences {
    page(name: "deviceDiscovery")
    page(name: "nodeDiscovery")
}

def deviceDiscovery() {
    def deviceRefreshCount = !state.deviceRefreshCount ? 0 : state.deviceRefreshCount as int

    if (!state.subscribed) {
        subscribe(location, "ssdpTerm.urn:<device-type>", ssdpHandler)
        state.subscribed = true
    }

    if ((hubRefreshCount % 5) == 0) {
        queryDevices()
    }
    def devices = getDevices()
    def deviceNames = devices.collect { it.value.name }

    return dynamicPage("deviceDiscovery", title: "Discovering Devices", nextPage:"nodeDiscovery", refreshInterval:5, install:false, uninstall:true) {
        section ("Device Selection") {
            input "selectedDevice", "enum", required:true, title:"Select Device\n(${deviceNames?.size() ?: 0} found), multiple:false, options:deviceNames
        }
    }
}

def nodeDiscovery() {
    // similar for the nodes on the device
}

def queryDiscovery() {
    sendHubCommand(new physicalgraph.device.HubAction("lan discovery urn:...", physicalgraph.device.Protocol.LAN))
}

def ssdpHandler(evt) {
    def description = evt.description
    def parsedEvent = parseLanMessage(description)
    def devices = getDevices()

    // Check if device is already on the list
    if (!(devices."${parsedEvent.ssdpUSN.toString()}")) {
        parsedEvent << ["name", parsedEvent.ssdpUSN.toString()]
        devices << ["${parsedEvent.ssdpUSN.toString()}":parseEvent]
    }
}

def getDevices() {
    if (!state.devices) { state.devices = [:] }
    state.devices
}

I see, an alternative could be adding a boolean input as follows:

input(name: "refreshDev", type: "boolean", title: "Refresh", submitOnChange:true)

Using the submitOnChange:true parameter, everytime this control changes (true/false) the app page will refresh and so the devices list.

Just to let you know, using your code from above I had some issues to open the SmartApp configuration because:

  1. Here the ending " symbol is missing.
  1. Here you didn’t include the property “name”.
dynamicPage(name: "deviceDiscovery", title: "Discovering Devices" //...

Thanks for the reply. I’ll give that a shot.