Help with basic DTH

I’m trying to create a simple DTH that just puts data from The Weather Company into state attributes. Don’t really need tiles or anything for now, just need the data. I’ve got the below, but the state isn’t populated for temperature (as a test). I’m sure it’s because I don’t really know what I’m doing…

   metadata {
 	definition (name: "TWC Weather Device", namespace: "lnjustin", author: "Justin Leonard") {
 	capability "Configuration"
 	capability "Refresh"
    attribute "dayOfWeek","string"
    attribute "dayOrNight","string"
    attribute "precip1Hour","number"
    attribute "precip6Hour","number"
    attribute "precip24Hour","number"
    attribute "relativeHumidity","number"
    attribute "temperature","number"
    attribute "temperatureMax24Hour","number"
    attribute "temperatureMin24Hour","number"
    attribute "validTimeLocal","string"
    attribute "validTimeUtc","number"
    attribute "windSpeed","number"
    attribute "qpfToday","number"
    attribute "qpfTomorrow","number"
    attribute "temperatureMaxToday","number"
    attribute "temperatureMaxTomorrow","number"
    attribute "temperatureMinToday","number"
    attribute "temperatureMinTomorrow","number"
    attribute "precipChanceTodayDay","number"
    attribute "precipChanceTodayNight","number"
    attribute "precipChanceTomorrowDay","number"
    attribute "precipChanceTomorrowNight","number"
    attribute "relativeHumidityTodayDay","number"
    attribute "relativeHumidityTodayNight","number"
    attribute "relativeHumidityTomorrowDay","number"
    attribute "relativeHumidityTomorrowNight","number"
    attribute "windSpeedTodayDay","number"
    attribute "windSpeedTodayNight","number"
    attribute "windSpeedTomorrowDay","number"
    attribute "windSpeedTomorrowNight","number"
     }

 }


def installed()
{
    // clear existing state info
    state.clear()
    
    // update system info
    refresh()
}

def refresh()
{
   def twcConditions = [:]
    try {
    	twcConditions = getTwcConditions()
    } catch (e) {
    	LOG("Error getting TWC Conditions: ${e}",1,null,'error')
        return null
    }
    if (twcConditions) {
    	sendEvent("name":"temperature", "value":twcConditions.temperature)

       // wxalerts[0]['phenomena']
    }
}

def updated()
{
    configure()
}

The first thing that jumps out to me is the following line:

sendEvent("name":"temperature", "value":twcConditions.temperature)

should be something like

sendEvent(name: "temperature", value: twcConditions.temperature)

The name and value should not be in double quotes.

Ah, good catch. I searched documentation and couldn’t figure out what the actual call flow looks like for a device handler. What method is called first, and what’s the flow from there?

You should have something like this (parse) at a minimum I believe:

def parse(String description) {
	log.trace "parse($description)"
}

Even if it does nothing, I believe it needs to be there. The parse is called first btw, but only after installed (first time install only), and/or then updated (if a user changes preferences). Refresh is called via tiles or another method.

Here’s an example of a DTH you can reference that all it does is populate attributes so that a SmartApp can reference them, like IFTTT or Webcore.

https://raw.githubusercontent.com/jsconstantelos/SmartThings/master/devicetypes/smartthings/water-heater-mode-selector.src/water-heater-mode-selector.groovy

Broadly:

installed() is called when you first install a device and if you ‘update’ a device in the IDE.

updated() is called when you first install a device and if you ‘update’ a device in the IDE, but only if you have genuinely changed something (like the device name). It is also called when you update the settings in the mobile app.

parse() is called when ST receives a message from your device. Typically you return a createEvent() map from parse to set attributes.

A number of other methods are ‘commands’ that are associated with capabilities and only used if those capabilities are claimed in your handler.

refresh() is associated with the Refresh capability. It is intended for you to send queries to the device to get it to send it’s current status. The responses will typically come via parse() though you can handle LAN based queries and responses in place. It is down to you to schedule regular runs of refresh() if required, or it can be called from external apps.

configure() is associated with the Configure capability. If you have that capability the method does get called automatically after installed(), otherwise you call it yourself as required. The intended use is to send configuration instructions to the device.

ping() is associated with Health Check. If ST hasn’t seen any activity from your device for a period you define, it will call this method before marking the device offline. You’d use it to do the same sort of thing as refresh() really as you want the device to make contact.

Otherwise commands are generally called by apps as required (and also the UI in the mobile app). So e.g. if an app wants to turn a switch on it results in on() being called. The general idea is that you have the command method return a sequence of Zigbee or Z-Wave commands, or a hubAction, that ST then sends to the device, which will typically trigger a response via parse(). However sometimes you don’t need to contact the device, or you don’t expect a response, so you can call sendEvent() to set attributes.