/* Copyright 2020 csromei
*
* 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: "Thermostat Tracker",
namespace: "Craig.Romei",
author: "Craig Romei",
description: "Track Thermostat usage",
category: "Tracking",
iconUrl: "https://raw.githubusercontent.com/napalmcsr/SmartThingsStuff/master/smartapps/keenect/clipart-thermometer-thermometer-clipart-free-6-thermometer-clip-art-clipartix-free-clipart.jpg",
iconX2Url: "https://raw.githubusercontent.com/napalmcsr/SmartThingsStuff/master/smartapps/keenect/clipart-thermometer-thermometer-clipart-free-6-thermometer-clip-art-clipartix-free-clipart.jpg",
iconX3Url : "https://raw.githubusercontent.com/napalmcsr/SmartThingsStuff/master/smartapps/keenect/clipart-thermometer-thermometer-clipart-free-6-thermometer-clip-art-clipartix-free-clipart.jpg"
)
preferences {
page(name: "pageConfig") // Doing it this way elimiates the default app name/mode options.
page(name: "pageStatus")
}
def pageConfig()
{
dynamicPage(name: "", title: "", install: true, uninstall: true, refreshInterval:0)
{
section("Report")
{
href "pageStatus", title: "Thermostat Usage", description: "Tap to see Thermostat usage"
input "DashboardTileUpdate", "capability.sensor", title: "Display Tile:", required: false
input name : "TStatStatesToReport", title: "Thermostat States to display:",multiple: true,required : true, type : "enum", options: getTstatStates(),submitOnChange : false,defaultValue : "1"
}
section("Thermostat")
{
input "tstat", "capability.thermostat", title: "Thermostat:", required: true
}
section("Logging")
{
input name : "logLevel",title : "IDE logging level",multiple : false,required : true,type : "enum",options : getLogLevels(),submitOnChange : false,defaultValue : "0"
}
section() {
label title: "Enter a name for this automation", required: false
}
}
}
def pageStatus(){
dynamicPage(
name : "Status"
,title : "Thermostat Usage"
,install : false
,uninstall : false
)
{
section(){
def reportString ="Day"+"\t\t\t"
if (TStatStatesToReport.contains("1")){
reportString +="idle"+"\t\t"
}
if (TStatStatesToReport.contains("2")){
reportString +="cooling"+"\t"
}
if (TStatStatesToReport.contains("3")){
reportString +="heating"+"\t"
}
if (TStatStatesToReport.contains("4")){
reportString +="fan only"+"\t"
}
if (TStatStatesToReport.contains("5")){
reportString +="pend cool"
}
if (TStatStatesToReport.contains("6")){
reportString +="\t"+"pend heat"
}
if (TStatStatesToReport.contains("7")){
reportString +="\t"+ "vent econ"
}
reportString +="\n" + "Today" +"\t\t"
if (TStatStatesToReport.contains("1")){
reportString +=convtime(state.StatusMapToday["idle"])+"\t"
}
if (TStatStatesToReport.contains("2")){
reportString +=convtime(state.StatusMapToday["cooling"]) +"\t"
}
if (TStatStatesToReport.contains("3")){
reportString +=convtime(state.StatusMapToday["heating"]) +"\t"
}
if (TStatStatesToReport.contains("4")){
reportString +=convtime(state.StatusMapToday["fan only"]) +"\t"
}
if (TStatStatesToReport.contains("5")){
reportString +=convtime(state.StatusMapToday["pending cool"]) +"\t\t"
}
if (TStatStatesToReport.contains("6")){
reportString +=convtime(state.StatusMapToday["pending heat"]) +"\t\t"
}
if (TStatStatesToReport.contains("7")){
reportString +=convtime(state.StatusMapToday["vent economizer"])
}
reportString +="\n"
for(int i = 0;i<=6;i++)
{
reportString += i+" day(s) ago"+"\t"
if (TStatStatesToReport.contains("1")){
reportString +=convtime(state.Last7Days[i]["idle"])+"\t"
}
if (TStatStatesToReport.contains("2")){
reportString +=convtime(state.Last7Days[i]["cooling"]) +"\t"
}
if (TStatStatesToReport.contains("3")){
reportString += convtime(state.Last7Days[i]["heating"]) +"\t"
}
if (TStatStatesToReport.contains("4")){
reportString +=convtime(state.Last7Days[i]["fan only"]) +"\t"
}
if (TStatStatesToReport.contains("5")){
reportString += convtime(state.Last7Days[i]["pending cool"]) +"\t\t"
}
if (TStatStatesToReport.contains("6")){
reportString += convtime(state.Last7Days[i]["pending heat"]) +"\t\t"
}
if (TStatStatesToReport.contains("7")){
reportString += convtime(state.Last7Days[i]["vent economizer"])
}
reportString += "\n"
}
paragraph reportString
}
}
}
def installed()
{
initialize()
}
def updated()
{
unsubscribe()
initialize()
}
def initialize()
{
infolog "Initializing"
def now = new Date().getTime().intdiv(1000)
unsubscribe()
debuglog "Getting Thermostat running State"
state.mainTstatState = state.mainTstatState ?: getMainTstatState()
state.stateChangeTime = state.stateChangeTime ?: now
subscribe(tstat, "thermostatOperatingState", tstatStateHandler)
debuglog "${TimeToRun}"
schedule("0 0 0 * * ?", Timehandler)
if(!state.StatusMapToday){
debuglog "Initializing a new Day"
state.StatusMapToday = [:]
InitializeNewDay()
}
if(!state.Last7Days)
{
state.Last7Days = new Map[7]
for(int i = 6;i>=0;i--)
{
state.Last7Days[i] = [:]
}
}
if(DashboardTileUpdate)
{
CreateVerticalDashboardNow()
CreateVerticalDashboardHistory()
}
infolog "initialize- complete"
}
def tstatStateHandler(evt){
infolog "tstatStateHandler- evt name: ${evt.name}, value: ${evt.value}"
UpdateTimeRunning()
state.mainTstatState = evt.value.toUpperCase()
if(DashboardTileUpdate)
{
CreateVerticalDashboardNow()
}
debuglog "tstatStateHandler- state.mainTstatState : ${state.mainTstatState}"
infolog "tstatStateHandler- complete"
}
def UpdateTimeRunning()
{
def now = new Date().getTime().intdiv(1000)
def timeRunning = now - state.stateChangeTime.toInteger()
debuglog "UpdateTimeRunning- Time Running: ${timeRunning}"
switch (state.mainTstatState){
case "HEATING" :
state.StatusMapToday["heating"] += timeRunning
break
case "COOLING" :
state.StatusMapToday["cooling"] += timeRunning
break
case "IDLE" :
state.StatusMapToday["idle"] += timeRunning
break
case "FAN ONLY" :
state.StatusMapToday["fan only"] += timeRunning
break
case "VENT ECONOMIZER" :
state.StatusMapToday["vent economizer"] += timeRunning
break
case "PENDING HEAT" :
state.StatusMapToday["pending heat"] += timeRunning
break
case "PENDING COOL" :
state.StatusMapToday["pending cool"] += timeRunning
break
default :
infolog "UpdateTimeRunning- Error, bad tstat state"
break
}
state.stateChangeTime = now
}
def Timehandler()
{
infolog "Timehandler - started"
UpdateTimeRunning()
for(int i = 5;i>=0;i--)
{
state.Last7Days[i+1]=state.Last7Days[i].clone()
}
state.Last7Days[0] = state.StatusMapToday.clone()
InitializeNewDay()
if(DashboardTileUpdate)
{
CreateVerticalDashboardNow()
CreateVerticalDashboardHistory()
DashboardTileUpdate.SetDailyCooling(state.Last7Days[0]["cooling"]/(60*60))
DashboardTileUpdate.SetDailyIdle(state.Last7Days[0]["idle"]/(60*60))
DashboardTileUpdate.SetDailyFan(state.Last7Days[0]["fan only"]/(60*60))
DashboardTileUpdate.SetDailyHeating(state.Last7Days[0]["heating"]/(60*60))
DashboardTileUpdate.SetDailyPendCool(state.Last7Days[0]["pending cool"]/(60*60))
DashboardTileUpdate.SetDailyVentEcon(state.Last7Days[0]["vent economizer"]/(60*60))
DashboardTileUpdate.SetDailyPendHeat(state.Last7Days[0]["pending heat"]/(60*60))
}
infolog "Timehandler - complete"
}
def InitializeNewDay()
{
state.StatusMapToday["idle"] = 0
state.StatusMapToday["cooling"] = 0
state.StatusMapToday["heating"] = 0
state.StatusMapToday["fan only"] = 0
state.StatusMapToday["vent economizer"] = 0
state.StatusMapToday["pending heat"] = 0
state.StatusMapToday["pending cool"] = 0
}
def getMainTstatState(){
def TstatState = tstat.currentValue("thermostatOperatingState")
if (TstatState!=null){
TstatState = TstatState.toUpperCase()
} else {
TstatState = "NULL"
}
debuglog "getMainTstatState Main TstatState : ${TstatState}"
return TstatState
}
def convtime(seconds)
{
if(!seconds)
{
seconds = 0
}
def hour = seconds.intdiv(60*60)
// hour = Math.round(hour)
def minutes = (seconds%(60*60))/60
minutes = Math.round(minutes)
return String.format('%02d',hour)+":"+String.format('%02d',minutes)
}
def CreateVerticalDashboardNow()
{
debuglog "CreateVerticalDashboardNow - Start"
debuglog "${TStatStatesToReport}"
def reportString ="Today
"
if (TStatStatesToReport.contains("1")){
reportString +="idle:"+"\t\t\t"+convtime(state.StatusMapToday["idle"])+"
"
}
if (TStatStatesToReport.contains("2")){
reportString +="cooling:"+"\t\t"+convtime(state.StatusMapToday["cooling"]) +"
"
}
if (TStatStatesToReport.contains("3")){
reportString += "heating"+"\t\t"+convtime(state.StatusMapToday["heating"]) +"
"
}
if (TStatStatesToReport.contains("4")){
reportString += "fan only"+"\t\t"+convtime(state.StatusMapToday["fan only"]) +"
"
}
if (TStatStatesToReport.contains("5")){
reportString += "pend cool"+"\t"+convtime(state.StatusMapToday["pending cool"]) +"
"
}
if (TStatStatesToReport.contains("6")){
reportString += "pend heat"+"\t"+convtime(state.StatusMapToday["pending heat"]) +"
"
}
if (TStatStatesToReport.contains("7")){
reportString += "vent econ"+"\t"+convtime(state.StatusMapToday["vent economizer"]) +"
"
}
DashboardTileUpdate.SetToday(reportString)
debuglog "CreateVerticalDashboardNow - ${reportString}"
}
def CreateVerticalDashboardHistory()
{
debuglog "CreateVerticalDashboardNow - Start"
def reportString = ""
for(int i = 0;i<=6;i++)
{
if(i==0)
{
reportString = "Yesterday
"
}
else
{
reportString = (i+1)+" days ago
"
}
if (TStatStatesToReport.contains("1")){
reportString +="idle:"+"\t\t\t"+convtime(state.Last7Days[i]["idle"])+"
"
}
if (TStatStatesToReport.contains("2")){
reportString +="cooling:"+"\t\t"+convtime(state.Last7Days[i]["cooling"]) +"
"
}
if (TStatStatesToReport.contains("3")){
reportString += "heating"+"\t\t"+convtime(state.Last7Days[i]["heating"]) +"
"
}
if (TStatStatesToReport.contains("4")){
reportString += "fan only"+"\t\t"+convtime(state.Last7Days[i]["fan only"]) +"
"
}
if (TStatStatesToReport.contains("5")){
reportString += "pend cool"+"\t"+convtime(state.Last7Days[i]["pending cool"]) +"
"
}
if (TStatStatesToReport.contains("6")){
reportString += "pend heat"+"\t"+convtime(state.Last7Days[i]["pending heat"]) +"
"
}
if (TStatStatesToReport.contains("7")){
reportString += "vent econ"+"\t"+convtime(state.Last7Days[i]["vent economizer"]) +"
"
}
switch (i){
case 0 :
DashboardTileUpdate.SetYesterday(reportString)
break
case 1 :
DashboardTileUpdate.SetTwoDaysAgo(reportString)
break
case 2 :
DashboardTileUpdate.SetThreeDaysAgo(reportString)
break
case 3 :
DashboardTileUpdate.SetFourDaysAgo(reportString)
break
case 4 :
DashboardTileUpdate.SetFiveDaysAgo(reportString)
break
case 5 :
DashboardTileUpdate.SetSixDaysAgo(reportString)
break
case 6 :
DashboardTileUpdate.SetSevenDaysAgo(reportString)
break
default :
debuglog "CreateVerticalDashboardNow - Not a valid day!"
break
}
}
}
def getTstatStates(){
return[["1":"idle"],["2":"cooling"],["3":"heating"],["4":"fan only"],["5":"pending cool"],["6":"pending heat"],["7":"vent economizer"]]
}
def debuglog(statement)
{
def logL = 0
if (logLevel) logL = logLevel.toInteger()
if (logL == 0) {return}//bail
else if (logL >= 2)
{
log.debug(statement)
}
}
def infolog(statement)
{
def logL = 0
if (logLevel) logL = logLevel.toInteger()
if (logL == 0) {return}//bail
else if (logL >= 1)
{
log.info(statement)
}
}
def getLogLevels(){
return [["0":"None"],["1":"Running"],["2":"NeedHelp"]]
}
def setVersion(){
state.version = "2.2.0" // Version number of this app
state.InternalName = "TstatTracker" // this is the name used in the JSON file for this app
}