DTH Works in Classic but Shows "Checking Status" in the new app

Greetings,

I am new to this platform working on my first personal project. I am trying to create a “device” that exposes the current price of electricity from ComEd’s Real-Time Pricing program (see https://hourlypricing.comed.com/live-prices/). Once I have this, I want to create automations that turn on/off high energy consumption devices based on the price (for example, my dehumidifier in the basement which has a smart plug should only run when electricity is cheap).

I have it working so that it shows up correctly in the Classic app but in the new app it simply shows “Checking Status” and no data. I’m 95% sure that I’m missing something simple. I think I need to add something so that it works with the new app, but I’m not sure how that works.

Here is my DTH so far:

metadata {
	definition (name: "Price Handler", namespace: "myappspace", author: "ABC123", cstHandler: true, vid: "generic-sensor") {
		capability "Sensor"
		capability "Health Check"
        
        attribute "price", "number"
	}


	simulator {
		// TODO: define status and messages here (if needed)
        status "getPrice": ""
	}

	tiles(scale: 2) {
		valueTile("priceTile", "device.price", decoration: "flat", width: 1, height: 1, canChangeIcon: true) {
        	state "price", label:'${currentValue} Cents'
        }
        
        main('priceTile')
 	}
}

def getPrice() {
    log.debug "Fetching Current Hour Price"
    Calendar calendar = Calendar.getInstance()
    def minute = calendar.get(Calendar.MINUTE)
    if ( minute <= 10 ) {
        return;
    }
	def params = [
       uri: "https://hourlypricing.comed.com?type=currenthouraverage",
       path: "/api",
       query: [type: "currenthouraverage"]
    ]
    try {
        httpGet(params) { resp ->
            def price = new groovy.json.JsonSlurper().parseText(resp.getData().toString()).price.get(0)
            log.debug "Current hour price: $price"
    		sendEvent(name: "price", value: price)
        }
    } catch (e) {
        log.error "Error getting current hour price: $e"
    }
}

// parse events into attributes
def parse(String description) {
	log.debug("Parse got message: '${description}'");
}

def initialize() {
    runEvery5Minutes(getPrice)
    log.debug "Schedule Set"
}

def installed() {
    initialize()
    getPrice()
}

def updated() {	
    initialize()
}

//For Health Check
def ping() {
	log.debug "ping()"	
}

I thought I found some information that I need to add the vid to the metadata and the HealthCheck (and the associated ‘ping’ method) to make it work with the new app but that didn’t seem to change anything.

Does anyone see what I’m missing? Any help or pointers to the documentation that I need to read to understand are deeply appreciated!

1 Like

You may have already seen this, but just in case not:

New app — which CUSTOM DTH’s will work?

I did see that - but setting a VID and adding capability Heath Check didn’t seem to do anything. There also didn’t seem to be a VID that was appropriate for my ‘fake’ device using the DTH. If there was something else in that article that I should try that I didn’t realize, please let me know.

I’m thinking that I might be misguided in trying to get it to work with the new app and that I can accomplish what I want using only the classic app. I’m going to work towards at the moment.

If someone else does have suggestions, I’m interested to hear. Thanks.

Check out Chris’s device handler - I’m using it successfully, but now trying to parse out the 5min pricing as it would be nice to shut off certain high drain appliances with a more detailed resolution of pricing.

By using it successfully - do you mean that you are able to see the current price tile render correctly on the Android SmartThings app? My version works correctly in the classic app - just not in the “new” app.

Also - I’ve updated mine since then so that the price I use is the max of either the last 3 5minute average prices or the value from the currentprice feed. You should be able to use my code for the 5 minute api.

 *  Price Handler
 *
 *  Copyright 2019 Kevin Reed
 *
 *  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.
 */
metadata {
	definition (name: "Price Handler", namespace: "cloudcats", author: "Kevin Reed", cstHandler: true, mnmn: "cloudcats", vid: "electricity-price") {
		capability "Sensor"
        
        attribute "price", "number"
	}


	simulator {
		// TODO: define status and messages here (if needed)
        status "updatePrice": ""
	}

	tiles(scale: 2) {
		valueTile("priceTile", "device.price", decoration: "flat", width: 6, height: 6, canChangeIcon: true) {
        	state("price", label:'${currentValue} Cents',
               backgroundColors:[
                   [value: 1.0,  color: "#2CAF40"],
                   [value: 2.0,  color: "#4EAE24"],
                   [value: 3.0,  color: "#6BAD20"],
                   [value: 4.0,  color: "#8AAD1D"],
                   [value: 5.0,  color: "#AAAC19"],
                   [value: 6.0,  color: "#AB8C16"],
                   [value: 7.0,  color: "#AB6812"],
                   [value: 8.0,  color: "#AA420F"],
                   [value: 9.0,  color: "#AA1C0B"],
                   [value: 10.0, color: "#A9081B"],
               ]
            )
        }
        
        main('priceTile')
 	}
}

def updatePrice() {
    Calendar calendar = Calendar.getInstance()
    def minute = calendar.get(Calendar.MINUTE)
	updateRecentPrice()
    if ( minute <= 15 ) {
        sendRecentPrice()
        return;
    }
    updateCurrentHourPrice()
    sendMaxPrice()
}

def updateRecentPrice() {
	def params = [
       uri: "https://hourlypricing.comed.com",
       path: "/api",
       query: [type: "5minutefeed"]
    ]
    try {
        httpGet(params) { resp ->
            def prices = new groovy.json.JsonSlurper().parseText(resp.getData().toString()).price;
            def price1 = Float.parseFloat(prices.get(0))
            def price2 = Float.parseFloat(prices.get(1))
            def price3 = Float.parseFloat(prices.get(2))
            def avgPrice = (price1+price2+price3)/3
            log.debug String.format("Recent price: %.1f", avgPrice)
            state.recentPrice = avgPrice
        }
    } catch (e) {
        log.error "Error getting crecent price: $e"
    }
}

def updateCurrentHourPrice() {
	def params = [
       uri: "https://hourlypricing.comed.com",
       path: "/api",
       query: [type: "currenthouraverage"]
    ]
    try {
        httpGet(params) { resp ->
            def price = new groovy.json.JsonSlurper().parseText(resp.getData().toString()).price.get(0)
            log.debug "Current hour price: $price"
            state.currentPrice = Float.parseFloat(price)
        }
    } catch (e) {
        log.error "Error getting current hour price: $e"
    }
}

def sendRecentPrice() {
    def maxPrice = state.recentPrice
    log.debug String.format("(Rec) Setting price to %.1f",maxPrice)
	sendEvent(name: "price", value: String.format("%.1f",maxPrice))
}

def sendMaxPrice() {
    def maxPrice = Math.max(state.recentPrice,state.currentPrice)
    log.debug String.format("(Max) Setting price to %.1f",maxPrice)
	sendEvent(name: "price", value: String.format("%.1f",maxPrice))
}

// parse events into attributes
def parse(String description) {
	log.debug("Parse got message: '${description}'");
}

def initialize() {
    runEvery5Minutes(updatePrice)
    log.debug "Schedule Set"
    state.currentPrice = 0.0
    state.recentPrice = 0.0
    updatePrice()
}

def installed() {
    initialize()
}

def updated() {	
    initialize()
}

And yes - I need to put mine into github and stop cutting and pasting :wink:

Big thanks for your work on your device handler; its bit outside of my abilities.

And yes, I’m still using the Classic app; I wont switch until they force me.