UncheckedException during SmartApp install


(Randall Olson) #1

I am getting the following exception in my logs when installing a SmartApp I’ve written. The SmartApp is just a simple test for creating child devices.

86159d83-f72c-42d6-af99-3191572726a3
9:30:26 AM:
error
physicalgraph.exception.UncheckedException: java.lang.Exception: Throwable caught while executing. 

There is no other description of the exception or information about what is going wrong. The exception happens after the refresh() call in the initialize() method. I would appreciate it if anyone had any insight as to why I am getting the exception. Code below.

Custom DeviceType:

metadata {
    definition (name: "Proxy Switch", namespace: "rolson16", author: "Randall Olson") {
        capability "Actuator"
        capability "Switch"
        capability "Polling"
        capability "Refresh"
        
        command "setSwitchState"
    }

    // simulator metadata
    simulator { }

    // tile definitions
    tiles {
        standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
            state "on", label: '${name}', action: "switch.off", icon: "st.switches.light.on", backgroundColor: "#79b821"
            state "off", label: '${name}', action: "switch.on", icon: "st.switches.light.off", backgroundColor: "#ffffff"
        }
        standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
            state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
        }

        main "switch"
        details(["switch","refresh"])
    }
}

def parse(String description) { }

def setSwitchState(value) {
    sendEvent(name:"switch", value: value, displayed: false)
    log.debug "${device.currentState("switch").value}"
    return null
}

def on() {
    parent.changeSwitchState(this, "on")
    sendEvent(name:"switch", value: "on", displayed: false)
}

def off() {
    parent.changeSwitchState(this, "off")
    sendEvent(name:"switch", value: "off", displayed: false)
}

def poll() {
    refresh()
}

def refresh() {
    parent.refresh()
}

ServiceManager SmartApp:

/**
 *  Proxy Switch Handler
 *
 *  Copyright 2015 Randall Olson
 *
 *  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.
 *
 */
definition(
    name: "Proxy Switch Handler",
    namespace: "rolson16",
    author: "Randall Olson",
    description: "Creates and manages proxy switches, allowing a single switch to appear in and be controlled from multiple groups.",
    category: "Convenience",
    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 {
    section("Select switches....") {
        input "switches", "capability.switch", required: true, multiple: true
    }
}

def installed() {
    log.debug "Installed with settings: ${settings}"

    state.mapping = []
    initialize()
}

def updated() {
    log.debug "Updated with settings: ${settings}"

    unsubscribe()
    initialize()
}

def initialize() {
    // Find all switches to remove from the mapping
    state.mapping.findAll{ map ->
        !switches.any{it.deviceNetworkId == map.switch.deviceNetworkId}
    }.collect { it.proxyId }.each { deleteChildDevice(it) }
    
    // Update existing mapping, removing any that were removed in the preferences
    state.mapping = state.mapping.findAll{ map ->
                     switches.any{it.deviceNetworkId == map.switch.deviceNetworkId}
                 }.collect{ [switch: it.switch, proxyId: it.proxyId] }
    
    // Create new additions
    def mappedSwitches = state.mapping.each { }.collect { it.switch.deviceNetworkId }
    switches.findAll { s ->
        !mappedSwitches.any{it == s.deviceNetworkId}
    }.each { s ->
        def dni = ["proxyswitch",s.displayName + "(p)",now()].join("|")
        def d = addChildDevice("rolson16","Proxy Switch",dni,null,[name: s.displayName + " (p)", completedSetup: true])
        state.mapping << [switch: s, proxyId: dni]
    }
    
    state.mapping.each { map ->
        subscribe(map.switch, "switch", switchHandler)
    }
    
    refresh()
}

def uninstalled() {
    unschedule()
    def deleteDevices = getAllChildDevices()
    deleteDevices.each { deleteChildDevice(it.deviceNetworkId) }
}

def switchHandler(evt) {
    def map = state.mapping.find { m ->
        m.switch.deviceNetworkId = evt.deviceId
    }
    
    def cd = getChildDevice(map.proxyId)
    cd.setSwitchState(evt.value)
}

def changeSwitchState (device, value) {
    def map = state.mapping.find { m ->
        m.proxyId == device.deviceNetworkId
    }
    if (value == "on") {
        map.switch.on()
    } else {
        map.switch.off()
    }
}

def refresh() {
    state.mapping.each{ map ->
        def d = getChildDevice(map.proxyId)
        d.setSwitchState(map.switch.currentState("switch").value)
    }
}

(Mike Maxwell) #2

I’d suggest you’re debugging too much code all in one shot.
some things I would do…
-comment out the refresh call
-verify child devices are being created
-uncomment refresh, replace the code within the loop with a log.debug to verify your state maps contain what you think they contain…

as an FYI, I’ve not been able to execute deleteChildDevice without generating an error, advise if you are.

as an additional FYI, there is no need to explicitly delete the child devices with the uninstall method, they are deleted correctly.


(Randall Olson) #3

Thanks for the response, Mike.

-I tried commenting out the refresh() call with the same results.
-I was able to confirm my code was creating a child device, though I don’t get a chance to see it in the mobile app.
-I also confirmed that my maps contain the proper data.

I did another test to confirm that the state is getting set properly in my child device during the refresh. The SmartApp seems to process correctly all the way through the initialize() method.

Only thing I can really think of is maybe I am creating my child devices incorrectly or the document type is bad so that they cannot be properly attached to the hub/location/UI. I haven’t found any really good documentation on addChildDevice.


(Mike Maxwell) #4

well then start commenting out the sections in the initialize until you find the culprit, since it wasn’t refresh…
Feel free to troll through this app, if it’s any help…


(Randall Olson) #5

Ok, it appears to be a problem with the way I am working with my child devices. I got something similar working in another app. Now if I can only figure out why setLocationMode() doesn’t work when called…

Thanks Mike for the responses and suggestions!