Smart Apps to Display Activity or Sensor Information

I am interested in having a SmartApp that displays activity/sensor information about specific devices.
For example,

  1. Temperatures from all sensors
  2. Activity for all window sensors in one page
    Can this functionality be achieved by a SmartApp?

Use case example: I have a few ST Multi sensors; and Aeon motion sensors all of which report temperature, and I would like to see the temperatures from all sensors in one single page.
Thanks

1 Like

SmartApps don’t display data. They just control actions. If you’re looking to see that information outside of the mobile app, you can make a SmartApp to send that data to other services.

I don’t think there is a reasonable way to do what you’re suggesting within the application.

Thanks @Dianoga, I suspected as much but was not certain.
My original thought was that this could be implemented in the preferences page of the SmartApp.
Say, two sections in the preferences, first where you select your sensors, and the second where this
information (activity/sensor info) is displayed. What are the roadblocks to this approach?

Separately, if ST opens up Dashboard Apps, such SmartApps will be great to have IMHO.

2 Likes

That’s actually a clever approach I hadn’t thought of. And it should work.

Thanks @Dianoga.
Two questions:

  1. Can this be implemented in one single page (either with hardcoded device names instead of having to choose them from a list)?
  2. Any chance you can provide me with some sample code (I am still learning the ropes, and will take me some time to come up with it myself) (I should be able to start with some sample code though).

While I am at this, one more question - can tiles be used inside the preferences page of a SmartApp?

Many many thanks, appreciate it.

I don’t think it can be done on a single page. You might be able to hardcode in the device ids, but I’m not sure. I’ve never tried it.

I’ll try to put together some sample code, but I don’t know when it will be.

Tiles can’t be used in SmartApps

Here is my first draft, two pages in preferences - first page to select sensors, and second page to list all the readings. Any pointers to make the second preferences page prettier?
(Like how can I make text bold/colorful/rich with temperature tiles/icons etc?)
Also, once the temperature sensors are chosen, any way to skip to the second page?

/** * Temperature Report * * Author: kmugh * Date: 2014-06-26 */
definition(
    name: "TempReport",
    namespace: "kmugh.app",
    author: "kmugh",
    category: "My Apps",
    description: "List temperatures from all sensors. Push notification/SMS",
    iconUrl: "https://s3.amazonaws.com/smartthings-device-icons/Weather/weather2-icn.png",
    iconX2Url: "https://s3.amazonaws.com/smartthings-device-icons/Weather/weather2-icn@2x.png"
)

preferences 
{
    page(name: "chooseTempSensors", title: "Choose Temp Sensors")
    page(name: "listATemperatures", title: "Temperatures")
}

def chooseTempSensors() 
{
    return dynamicPage(name: "chooseTempSensors", title: "Choose Required Temperature Sensors", nextPage:"listATemperatures", uninstall:false) {
        section("Monitor the temperature...") 
        {
            input "temperatureSensors", "capability.temperatureMeasurement", title: "Choose Temp Sensors", required: true, multiple: true
        }

        section( "Notifications" ) 
        {
            input "enablePushNotification", "enum", title: "Send a push notification? (Default: No)", metadata:[values:["No","Yes"]], required:false
            input "enableSMSNotification", "enum", title: "Send an SMS notification? (Default: No)", metadata:[values:["No","Yes"]], required:false
            input "phone", "phone", title: "Phone number for text message?", required: false
        }

        section("Duration in minutes") 
        {
            input "timerInterval", "number", title: "Time (minutes) (Defaults to 60 minutes)", required:false
        }
    }
}

def listATemperatures() 
{
    return dynamicPage(name: "listATemperatures", title: "List of Temperatures", install:true, uninstall:true) {
        def msgText = "Temperatures from " + temperatureSensors.size() + " sensors:\n"
        for (tempSens in temperatureSensors)
        {
            msgText = msgText + getHumanLabel(tempSens.displayName) + ": " + tempSens.currentValue("temperature") + "°F  \n"
        }
        section("${msgText}")
    }
}

def subscribeAndSchedule()
{
    state.count = 0;
    state.messageText = ""
    state.sensorCount = temperatureSensors.size()

    subscribe(temperatureSensors, "temperature", tempEventsManager)
    schedule(now() + ((timerInterval == null) ? 60 : timerInterval) * 60 * 1000, sendTempReport)
}

def installed() 
{
    log.debug "Installed with settings: ${settings}"
    log.debug "Number of temperature sensors: ${temperatureSensors.size()}"

    subscribeAndSchedule()
}

def tempEventsManager(evt)
{
}

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

    unsubscribe()
    unschedule()

   subscribeAndSchedule()
}

def subscribeToEvents() 
{	
}

def sendTempReport()
{  
    def messageText = ""
    for (tempSens in temperatureSensors)
    {
        messageText = messageText + getHumanLabel(tempSens.displayName) + ": " + tempSens.currentValue("temperature") + "°F  \n"
    }

    log.debug messageText

    if ((enablePushNotification == "") ? 0 : ((enablePushNotification == "Yes") ? 1 : 0))
    {
        log.debug( "sending push message" )
        sendPush(messageText)
    }

    ((enableSMSNotification == "") ? 0 : ((enableSMSNotification == "Yes") ? 1 : 0))
    {
        if (phone)
        {
            log.debug( "sending text message" )
            sendSms(phone, messageText)
        }
    }

    unsubscribe()
    unschedule()

   subscribeAndSchedule()
}

def getHumanLabel(stringIn)
{
     return stringIn
}

I can’t speak to prettiness, but to skip the first page, you could put some login in there to check if devices have been picked. If so, return the second page instead of the first. I think that would work…

Thanks a lot @Dianoga.

Added the dynamic page handling to skip the first page if sensors are already defined.
Only drawback is I need to uninstall the app and reinstall for any new sensors.

Have a temperature snapshot here, and a battery charge snapshot here.

Anyone knows how to render dynamically generated html content within a section in the preferences?

def html = """
    <!DOCTYPE html>
    <html>
    <head>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>${getVendorName()} Connection</title>
    <style type="text/css">
        * { box-sizing: border-box; }
        @font-face {
            font-family: 'Swiss 721 W01 Thin';
            src: url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-thin-webfont.eot');
            src: url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-thin-webfont.eot?#iefix') format('embedded-opentype'),
                 url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-thin-webfont.woff') format('woff'),
                 url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-thin-webfont.ttf') format('truetype'),
                 url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-thin-webfont.svg#swis721_th_btthin') format('svg');
            font-weight: normal;
            font-style: normal;
        }
        @font-face {
            font-family: 'Swiss 721 W01 Light';
            src: url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-light-webfont.eot');
            src: url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-light-webfont.eot?#iefix') format('embedded-opentype'),
                 url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-light-webfont.woff') format('woff'),
                 url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-light-webfont.ttf') format('truetype'),
                 url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-light-webfont.svg#swis721_lt_btlight') format('svg');
            font-weight: normal;
            font-style: normal;
        }
        .container {
            width: 100%;
            padding: 40px;
            /*background: #eee;*/
            text-align: center;
        }
        img {
            vertical-align: middle;
        }
        img:nth-child(2) {
            margin: 0 30px;
        }
        p {
            font-size: 2.2em;
            font-family: 'Swiss 721 W01 Thin';
            text-align: center;
            color: #666666;
            margin-bottom: 0;
        }
    /*
        p:last-child {
            margin-top: 0px;
        }
    */
        span {
            font-family: 'Swiss 721 W01 Light';
        }
    </style>
    </head>
    <body>
        <div class="container">
            <img src=""" + getVendorIcon() + """ alt="Vendor icon" />
            <img src="https://s3.amazonaws.com/smartapp-icons/Partner/support/connected-device-icn%402x.png" alt="connected device icon" />
            <img src="https://s3.amazonaws.com/smartapp-icons/Partner/support/st-logo%402x.png" alt="SmartThings logo" />
            <p>We have located your """ + getVendorName() + """ account.</p>
            <p>Tap 'Done' to process your credentials.</p>
		</div>
    </body>
    </html>
    """
render contentType: 'text/html', data: html

@Dianoga
I tried the following (based on your code above) under preferences{}, but I am neither seeing the HTML render, nor seeing sections added after the html section:

        section ("HERE")
        {
            def rawHTML = """
                <!DOCTYPE html>
                <html>
                <head>
                	<title>Connection Test</title>
                </head>
                <body>
                	<p>Just a test</p>
                </body>
                </html>
                """
            render contentType: 'text/html', data: rawHTML
        }
        section("This section is invisible/missing")
        {
                paragraph "Where is this section!"
        }

What am I doing wrong?

Sorry, that would go inside a method that you call via page(). Does that make sense?

@Dianoga, could I get a code snippet (that way I can’t make any mistakes :smile: )
Many many thanks, sincerely appreciate it.

def chooseTempSensors() {
    def html = 'your html'
    render contentType: 'text/html', data: html
}

Roughly that should work. I think.

@Dianoga, any special handling for dynamic pages?

I am using this:

preferences
{
    ....
    return dynamicPage(name: "showTemperaturePage", content: "renderHTMLPage")
}

def renderHTMLPage
{
    def html = "..."
    render contentType: "text/html", data: html
}

But not able to get it to work, the app quits right after I click on it.

As I stare at my code more, I’m not actually sure how to do it. @wackware would probably know.

@wackware @Dianoga Any thoughts on how to get this to work? Appreciate the help.