[OBSOLETE] Smart Weather Station Tile Device

The Smart Weather Station Tile App under more and Convenience.

What products work with this that I can attach? Does this pull information from a PWS device such as the ones that work with wunderground?


It pulls data from the wunderground API. So if your PWS is hooked up to wunderground, you can get data from it. Davis Weather Station

Sorry its a Monday in my head… one quick clarification I would need my own PWS and I can’t just use either the API I have with Wunderground without my own personal station. IE I can’t connect to a neighbors unit.

When I open the app is says Device to connect too but no box to enter any API data.

Thank you

The Smart Weather Station Controller app just updates devices you have added to your account. I believe to add the actual device, you need to use the web ide (http://ide.smartthings.com) and add the Smart Weather Station Tile. That’s also where you put in your location data.

It doesn’t have to be a PWS you control. You should be able to use any location info the wunderground API can understand.

1 Like

Everything works perfect now thank you so much Dianaga.

Installed the device in the IDE as Smart Weather Tile Device set network id to Wunderground API and Zip code to the Station I wanted to use and after 5 min voila all is perfect!

Vert insterested in the is app but cannot figure out where to get the smart weather tile app to add in my developer account. Could i get a few more walk through steps?

  1. Login to https://ide.smartthings.com
  2. Go to devices tab (https://graph.api.smartthings.com/device/list)
  3. Click new device button in top right corner (https://graph.api.smartthings.com/device/create)
  4. Choose whatever you want for name and network id. Change type to SmartWeather Station Tile. Choose your location. Leave everything else alone.
  5. Click create.

That should give you a functioning weather tile.


Fantastic! worked great. 1 last question, where can i put the PWS variable to include my own station?

Weather Tile Device click on it then preferences, Zip Code worked for me 3rd from the bottom.

This one should display wind direction for you

 *  SmartWeather Station v2
 *  Author: SmartThings
 *  Date: 2014-10-29
// for the UI
metadata {
	// Automatically generated. Make future change here.
	definition (name: "SmartWeather Station Tile v2", namespace: "smartthings", author: "SmartThings") {
		capability "Illuminance Measurement"
		capability "Temperature Measurement"
		capability "Relative Humidity Measurement"
		capability "polling"
		attribute "localSunrise", "string"
		attribute "localSunset", "string"
		attribute "city", "string"
		attribute "timeZoneOffset", "string"
		attribute "weather", "string"
		attribute "wind", "string"
                attribute "windDir", "string"
		attribute "weatherIcon", "string"
		attribute "forecastIcon", "string"
		attribute "feelsLike", "string"
		attribute "percentPrecip", "string"
		attribute "alert", "string"
		attribute "alertKeys", "string"
		attribute "sunriseDate", "string"
		attribute "sunsetDate", "string"

		command "refresh"

	preferences {
		input "zipCode", "text", title: "Zip Code (optional)", required: false

	tiles {
		valueTile("temperature", "device.temperature") {
			state "default", label:'${currentValue}°',
                	[value: 19, color: "#9F8ACD"],
					[value: 31, color: "#153591"],
					[value: 44, color: "#1e9cbb"],
					[value: 59, color: "#90d2a7"],
					[value: 74, color: "#44b621"],
					[value: 84, color: "#f1d801"],
					[value: 95, color: "#d04e00"],
					[value: 96, color: "#bc2323"]

		valueTile("humidity", "device.humidity", decoration: "flat") {
			state "default", label:'${currentValue}% humidity'

		standardTile("weatherIcon", "device.weatherIcon", decoration: "flat") {
			state "chanceflurries", icon:"st.custom.wu1.chanceflurries", label: ""
			state "chancerain", icon:"st.custom.wu1.chancerain", label: ""
			state "chancesleet", icon:"st.custom.wu1.chancesleet", label: ""
			state "chancesnow", icon:"st.custom.wu1.chancesnow", label: ""
			state "chancetstorms", icon:"st.custom.wu1.chancetstorms", label: ""
			state "clear", icon:"st.custom.wu1.clear", label: ""
			state "cloudy", icon:"st.custom.wu1.cloudy", label: ""
			state "flurries", icon:"st.custom.wu1.flurries", label: ""
			state "fog", icon:"st.custom.wu1.fog", label: ""
			state "hazy", icon:"st.custom.wu1.hazy", label: ""
			state "mostlycloudy", icon:"st.custom.wu1.mostlycloudy", label: ""
			state "mostlysunny", icon:"st.custom.wu1.mostlysunny", label: ""
			state "partlycloudy", icon:"st.custom.wu1.partlycloudy", label: ""
			state "partlysunny", icon:"st.custom.wu1.partlysunny", label: ""
			state "rain", icon:"st.custom.wu1.rain", label: ""
			state "sleet", icon:"st.custom.wu1.sleet", label: ""
			state "snow", icon:"st.custom.wu1.snow", label: ""
			state "sunny", icon:"st.custom.wu1.sunny", label: ""
			state "tstorms", icon:"st.custom.wu1.tstorms", label: ""
			state "cloudy", icon:"st.custom.wu1.cloudy", label: ""
			state "partlycloudy", icon:"st.custom.wu1.partlycloudy", label: ""
			state "nt_chanceflurries", icon:"st.custom.wu1.nt_chanceflurries", label: ""
			state "nt_chancerain", icon:"st.custom.wu1.nt_chancerain", label: ""
			state "nt_chancesleet", icon:"st.custom.wu1.nt_chancesleet", label: ""
			state "nt_chancesnow", icon:"st.custom.wu1.nt_chancesnow", label: ""
			state "nt_chancetstorms", icon:"st.custom.wu1.nt_chancetstorms", label: ""
			state "nt_clear", icon:"st.custom.wu1.nt_clear", label: ""
			state "nt_cloudy", icon:"st.custom.wu1.nt_cloudy", label: ""
			state "nt_flurries", icon:"st.custom.wu1.nt_flurries", label: ""
			state "nt_fog", icon:"st.custom.wu1.nt_fog", label: ""
			state "nt_hazy", icon:"st.custom.wu1.nt_hazy", label: ""
			state "nt_mostlycloudy", icon:"st.custom.wu1.nt_mostlycloudy", label: ""
			state "nt_mostlysunny", icon:"st.custom.wu1.nt_mostlysunny", label: ""
			state "nt_partlycloudy", icon:"st.custom.wu1.nt_partlycloudy", label: ""
			state "nt_partlysunny", icon:"st.custom.wu1.nt_partlysunny", label: ""
			state "nt_sleet", icon:"st.custom.wu1.nt_sleet", label: ""
			state "nt_rain", icon:"st.custom.wu1.nt_rain", label: ""
			state "nt_sleet", icon:"st.custom.wu1.nt_sleet", label: ""
			state "nt_snow", icon:"st.custom.wu1.nt_snow", label: ""
			state "nt_sunny", icon:"st.custom.wu1.nt_sunny", label: ""
			state "nt_tstorms", icon:"st.custom.wu1.nt_tstorms", label: ""
			state "nt_cloudy", icon:"st.custom.wu1.nt_cloudy", label: ""
			state "nt_partlycloudy", icon:"st.custom.wu1.nt_partlycloudy", label: ""
		valueTile("feelsLike", "device.feelsLike", decoration: "flat") {
			state "default", label:'feels like ${currentValue}°'

		valueTile("wind", "device.wind", decoration: "flat") {
			state "default", label:'wind ${currentValue} mph'
        		valueTile("windDir", "device.windDir", decoration: "flat") {
			state "default", label:'${currentValue}'
		valueTile("weather", "device.weather", decoration: "flat") {
			state "default", label:'${currentValue}'

		valueTile("city", "device.city", decoration: "flat") {
			state "default", label:'${currentValue}'

		valueTile("percentPrecip", "device.percentPrecip", decoration: "flat") {
			state "default", label:'${currentValue}% precip'

		standardTile("refresh", "device.weather", decoration: "flat") {
			state "default", label: "", action: "refresh", icon:"st.secondary.refresh"

		valueTile("alert", "device.alert", width: 3, height: 1, decoration: "flat") {
			state "default", label:'${currentValue}'

		valueTile("rise", "device.localSunrise", decoration: "flat") {
			state "default", label:'${currentValue}'

		valueTile("set", "device.localSunset", decoration: "flat") {
			state "default", label:'${currentValue}'

		valueTile("light", "device.illuminance", decoration: "flat") {
			state "default", label:'${currentValue} lux'

		main(["temperature", "weatherIcon","feelsLike"])
		details(["temperature", "weatherIcon","feelsLike","wind","windDir","weather", "city","percentPrecip", "refresh","alert", "humidity","rise","set","light"])}

// parse events into attributes
def parse(String description) {
	log.debug "Parsing '${description}'"

// handle commands
def poll() {
	log.debug "Executing 'poll', location: ${location.name}"

	// Current conditions
	def obs = get("conditions")?.current_observation
	if (obs) {
		def weatherIcon = obs.icon_url.split("/")[-1].split("\\.")[0]

		if(getTemperatureScale() == "C") {
			send(name: "temperature", value: Math.round(obs.temp_c), unit: "C")
			send(name: "feelsLike", value: Math.round(obs.feelslike_c as Double), unit: "C")
		} else {
			send(name: "temperature", value: Math.round(obs.temp_f), unit: "F")
			send(name: "feelsLike", value: Math.round(obs.feelslike_f as Double), unit: "F")
		send(name: "humidity", value: obs.relative_humidity[0..-2] as Integer, unit: "%")
		send(name: "weather", value: obs.weather)
        send(name: "windDir", value: obs.wind_dir)
		send(name: "weatherIcon", value: weatherIcon, displayed: false)
		send(name: "wind", value: Math.round(obs.wind_mph) as String, unit: "MPH") // as String because of bug in determining state change of 0 numbers

		if (obs.local_tz_offset != device.currentValue("timeZoneOffset")) {
			send(name: "timeZoneOffset", value: obs.local_tz_offset, isStateChange: true)

		def cityValue = "${obs.display_location.city}, ${obs.display_location.state}"
		if (cityValue != device.currentValue("city")) {
			send(name: "city", value: cityValue, isStateChange: true)

		// Sunrise / sunset
		def a = get("astronomy")?.moon_phase
		def today = localDate("GMT${obs.local_tz_offset}")
		def ltf = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm")
		def utf = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")

		def sunriseDate = ltf.parse("${today} ${a.sunrise.hour}:${a.sunrise.minute}")
		def sunsetDate = ltf.parse("${today} ${a.sunset.hour}:${a.sunset.minute}")

        def tf = new java.text.SimpleDateFormat("h:mm a")
        def localSunrise = "${tf.format(sunriseDate)}"
        def localSunset = "${tf.format(sunsetDate)}"
        send(name: "localSunrise", value: localSunrise, descriptionText: "Sunrise today is at $localSunrise")
        send(name: "localSunset", value: localSunset, descriptionText: "Sunset today at is $localSunset")

		send(name: "illuminance", value: estimateLux(sunriseDate, sunsetDate, weatherIcon))

		// Forecast
		def f = get("forecast")
		def f1= f?.forecast?.simpleforecast?.forecastday
		if (f1) {
			def icon = f1[0].icon_url.split("/")[-1].split("\\.")[0]
			def value = f1[0].pop as String // as String because of bug in determining state change of 0 numbers
			send(name: "percentPrecip", value: value, unit: "%")
			send(name: "forecastIcon", value: icon, displayed: false)
		else {
			log.warn "Forecast not found"

		// Alerts
		def alerts = get("alerts")?.alerts
		def newKeys = alerts?.collect{it.type + it.date_epoch} ?: []
		log.debug "WUSTATION: newKeys: $newKeys"
		log.trace device.currentState("alertKeys")
		def oldKeys = device.currentState("alertKeys")?.jsonValue
		log.debug "WUSTATION: oldKeys: $oldKeys"

		def noneString = "no current weather alerts"
		if (!newKeys && oldKeys == null) {
			send(name: "alertKeys", value: newKeys.encodeAsJSON(), displayed: false)
			send(name: "alert", value: noneString, descriptionText: "${device.displayName} has no current weather alerts", isStateChange: true)
		else if (newKeys != oldKeys) {
			if (oldKeys == null) {
				oldKeys = []
			send(name: "alertKeys", value: newKeys.encodeAsJSON(), displayed: false)

			def newAlerts = false
			alerts.each {alert ->
				if (!oldKeys.contains(alert.type + alert.date_epoch)) {
					def msg = "${alert.description} from ${alert.date} until ${alert.expires}"
					send(name: "alert", value: pad(alert.description), descriptionText: msg, isStateChange: true)
					newAlerts = true

			if (!newAlerts && device.currentValue("alert") != noneString) {
				send(name: "alert", value: noneString, descriptionText: "${device.displayName} has no current weather alerts", isStateChange: true)
	else {
		log.warn "No response from Weather Underground API"

def refresh() {

def configure() {

private pad(String s, size = 25) {
	def n = (size - s.size()) / 2
	if (n > 0) {
		def sb = ""
		n.times {sb += " "}
		sb += s
		n.times {sb += " "}
		return sb
	else {
		return s

private get(feature) {
	getWeatherFeature(feature, zipCode)

private localDate(timeZone) {
	def df = new java.text.SimpleDateFormat("yyyy-MM-dd")
	df.format(new Date())

private send(map) {
	log.debug "WUSTATION: event: $map"

private estimateLux(sunriseDate, sunsetDate, weatherIcon) {
	def lux = 0
	def now = new Date().time
	if (now > sunriseDate.time && now < sunsetDate.time) {
		switch(weatherIcon) {
			case 'tstorms':
				lux = 200
			case ['cloudy', 'fog', 'rain', 'sleet', 'snow', 'flurries',
				'chanceflurries', 'chancerain', 'chancesleet',
				'chancesnow', 'chancetstorms']:
				lux = 1000
			case 'mostlycloudy':
				lux = 2500
			case ['partlysunny', 'partlycloudy', 'hazy']:
				lux = 7500
				//sunny, clear
				lux = 10000

		//adjust for dusk/dawn
		def afterSunrise = now - sunriseDate.time
		def beforeSunset = sunsetDate.time - now
		def oneHour = 1000 * 60 * 60

		if(afterSunrise < oneHour) {
			lux = (long)(lux * (afterSunrise/oneHour))
		} else if (beforeSunset < oneHour) {
			lux = (long)(lux * (beforeSunset/oneHour))
	else {
		//night - always set to 10 for now
		//could do calculations for dusk/dawn too
		lux = 10


Whenever this is called on stock weather device


This error is thrown:

org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object ‘temperature’ with class ‘physicalgraph.device.cache.AttributeDTO’ to class ‘physicalgraph.device.Attribute’

Anyone knows what’s up with this?

Thank you very much! You should submit this revision to ST! @mager
Did you just have to add a line or two to the old SmartWeather Station Tile code? I see the attribute “windDir”, “string” line. I don’t know anything about code but maybe I can learn a little.

What is the easiest way to replace my current code? I have added / updated code before when it was listed under “My SmartApps” in the IDE but the SmartWeather Station Tile is not listed under “My SmartApps” it’s under “My Devices”. I also use the SmartWeather Station Controller of course.
Under “My Devices” can I use the EDIT button to get to the old code? Or do I need to use the DELETE button and do away with that device and enter this new code in “My SmartApps” (don’t think this would work with my ActiON Dashboard).

I use ActiON Dashboard which shows this weather, maybe in the future it will show the wind.



Yup, just had to add a few lines to reference the wind direction condition from Weather Underground API and also to add an additional tile http://www.wunderground.com/weather/api/d/docs?d=data/conditions&MR=1

As you can see on that page listed above, you could theoretically create tiles for all kinds of condition information for wind_degrees, wind_gust_mph, solarradiation, UV, etc.

Go into My Device Types in the IDE and select New SmartDevice in the upper right corner.

Then select the “From Code” option on the New SmartDevice screen

Copy/paste the code from above and click Create at the bottom of the screen. (The create process takes 20-30 seconds, so don’t be alarmed if it looks like the page is frozen.)

On the next screen that loads, select “Publish”, then “For Me”.

This created a new custom device type that you will then assign to a specific device. Now go to My Devices in the IDE and find your current SmartWeather Tile. Click on it, then click Edit and change the Type to SmartWeather Tile v2 (located towards the bottom of the list).

Click Update, then refresh the SmartWeather Tile in the SmartThings app. It should populate the new wind direction value on a new tile. If not, force close the SmartThings app and reopen.

Thank you very much and very cool, this helps a lot. I’m surprised it had to be another tile, I thought it would be the same tile as the wind speed. It bumped my humidity tile down to the next page, not a big deal. I tried to tap and hold a tile to rearrange but it does not allow it. I was going to bring the humidity tile back up and drop the “feels like _” down.

If anyone wants to see the change:

And lower page:

Thank you!

@Dave no problem, glad I could help!

I actually rearranged the tiles in the custom device type due to personal preference, but you could do the same with yours to put the tiles in whatever order you like. Go back into the SmartWeather Tile v2 device in My Device Types and edit line 149-

details(["temperature", "weatherIcon","feelsLike","wind","windDir","weather", "city","percentPrecip", "refresh","alert", "humidity","rise","set","light"])}

Whatever order you put the tile names in is the order of how they are displayed in the device. So replace your line 149 with the following-

details(["temperature", "weatherIcon","humidity","wind","windDir","weather", "city","percentPrecip", "refresh","alert","feelsLike","rise","set","light"])}

Sweet! I would like to learn this stuff and you did just teach me some! I owe U a beer!

I was able to update the order of my tiles. I ended up dropping the city down and bringing the humidity up. I figured it’s always going to be the same city so no need to always see it. If I watch the IDE Log is there anyway to get the PWS ID? I’m pretty sure I know which PWS is being used but wanted to verify if easy.

This is cool, wish this was a default installed app.

Do you know what that yellow circle on the corner indicates @Dianoga? I can only select one at a time.

This code doesn’t work anymore


No signature of method: script14148161440891502062458.metadata() is applicable for argument types: (script14148161440891502062458$_run_closure1) values: [script14148161440891502062458$_run_closure1@3316d9b7] Possible solutions: getMetadata(), getState(), setState(java.lang.Object), metaClass(groovy.lang.Closure)

The yellow circle denotes which of the “sub-tiles” will appear as the main tile for the device in the higher level menu/page.

Thanks. Do you know why it doesn’t update the information automatically? I need to manually go in and refresh it every few hours.