/** * Total Comfort API * * Based on Code by Eric Thomas * * 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 * lgk v 2.5 addded looking of humidifier settings * 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. * */ preferences { input("username", "text", title: "Username", description: "Your Total Comfort User Name") input("password", "password", title: "Password", description: "Your Total Comfort password") input("honeywelldevice", "text", title: "Device ID", description: "Your Device ID") } metadata { definition (name: "Total Comfort API", namespace: "Total Comfort API", author: "Eric Thomas, modified lg kahn") { capability "Polling" capability "Thermostat" capability "Refresh" capability "Temperature Measurement" capability "Sensor" capability "Relative Humidity Measurement" command "heatLevelUp" command "heatLevelDown" command "coolLevelUp" command "coolLevelDown" attribute "outdoorHumidity", "number" attribute "outdoorTemperature", "number" } simulator { // TODO: define status and reply messages here } tiles { valueTile("temperature", "device.temperature", width: 2, height: 2, canChangeIcon: true) { state("temperature", label: '${currentValue}°F', icon: "http://cdn.device-icons.smartthings.com/Weather/weather2-icn@2x.png", unit:"F", backgroundColors: [ [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"] ] ) } standardTile("thermostatMode", "device.thermostatMode", inactiveLabel: false, canChangeIcon: true) { state "off", label:'${name}', action:"thermostat.cool", icon: "st.Outdoor.outdoor19" state "cool", label:'${name}', action:"thermostat.heat", icon: "st.Weather.weather7", backgroundColor: '#1e9cbb' state "heat", label:'${name}', action:"thermostat.auto", icon: "st.Weather.weather14", backgroundColor: '#E14902' state "auto", label:'${name}', action:"thermostat.off", icon: "st.Weather.weather3", backgroundColor: '#44b621' } standardTile("thermostatFanMode", "device.thermostatFanMode", inactiveLabel: false, canChangeIcon: true) { state "auto", label:'${name}', action:"thermostat.fanAuto", icon: "st.Appliances.appliances11", backgroundColor: '#44b621' state "circulate", label:'${name}', action:"thermostat.fanCirculate", icon: "st.Appliances.appliances11", backgroundColor: '#44b621' state "on", label:'${name}', action:"thermostat.fanOn", icon: "st.Appliances.appliances11", backgroundColor: '#44b621' } controlTile("coolSliderControl", "device.coolingSetpoint", "slider", height: 3, width: 1, inactiveLabel: false) { state "setCoolingSetpoint", label:'Set temperarure to', action:"thermostat.setCoolingSetpoint", backgroundColors:[ [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("coolingSetpoint", "device.coolingSetpoint", inactiveLabel: false) { state "default", label:'Cool\n${currentValue}°F', unit:"F", backgroundColors: [ [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("heatingSetpoint", "device.heatingSetpoint", inactiveLabel: false) { state "default", label:'Heat\n${currentValue}°F', unit:"F", backgroundColors: [ [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"] ] } //tile added for operating state - Create the tiles for each possible state, look at other examples if you wish to change the icons here. standardTile("thermostatOperatingState", "device.thermostatOperatingState", inactiveLabel: false) { state "heating", label:'${name}', backgroundColor : '#E14902' state "cooling", label:'${name}', backgroundColor : '#1e9cbb' state "idle", label:'${name}' } standardTile("refresh", "device.thermostatMode", inactiveLabel: false, decoration: "flat") { state "default", action:"polling.poll", icon:"st.secondary.refresh" } standardTile("heatLevelUp", "device.heatingSetpoint", canChangeIcon: false, inactiveLabel: false) { state "heatLevelUp", label:' ', action:"heatLevelUp", icon:"st.thermostat.thermostat-up" } standardTile("heatLevelDown", "device.heatingSetpoint", canChangeIcon: false, inactiveLabel: false) { state "heatLevelDown", label:' ', action:"heatLevelDown", icon:"st.thermostat.thermostat-down" } standardTile("coolLevelUp", "device.heatingSetpoint", canChangeIcon: false, inactiveLabel: false) { state "coolLevelUp", label:' ', action:"coolLevelUp", icon:"st.thermostat.thermostat-up" } standardTile("coolLevelDown", "device.heatingSetpoint", canChangeIcon: false, inactiveLabel: false) { state "coolLevelDown", label:' ', action:"coolLevelDown", icon:"st.thermostat.thermostat-down" } valueTile("relativeHumidity", "device.relativeHumidity", inactiveLabel: false) { state "default", label:'Humidity\n${currentValue}%', icon: "http://cdn.device-icons.smartthings.com/Weather/weather12-icn@2x.png", unit:"%", backgroundColors : [ [value: 01, color: "#724529"], [value: 11, color: "#724529"], [value: 21, color: "#724529"], [value: 35, color: "#44b621"], [value: 49, color: "#44b621"], [value: 50, color: "#1e9cbb"] ] } standardTile("thermostatMode", "device.thermostatMode", inactiveLabel: false, canChangeIcon: true) { } /* lgk new tiles for outside temp and hummidity */ valueTile("outdoorTemperature", "device.outdoorTemperature", width: 1, height: 1, canChangeIcon: true) { state("temperature", label: 'Outdoor\n ${currentValue}°F', icon: "http://cdn.device-icons.smartthings.com/Weather/weather2-icn@2x.png", unit:"F", backgroundColors: [ [value: -31, color: "#003591"], [value: 00, color: "#cccccc"], [value: 31, color: "#153500"], [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("outdoorHumidity", "device.outdoorHumidity", inactiveLabel: false){ state "default", label:'Outdoor\n ${currentValue}%', icon: "http://cdn.device-icons.smartthings.com/Weather/weather12-icn@2x.png", unit:"%", backgroundColors : [ [value: 01, color: "#724529"], [value: 11, color: "#724529"], [value: 21, color: "#724529"], [value: 35, color: "#44b621"], [value: 49, color: "#44b621"], [value: 70, color: "#449c00"], [value: 90, color: "#009cbb"] ] } main "temperature" details(["temperature", "thermostatMode", "thermostatFanMode", "heatLevelUp", "heatingSetpoint" , "heatLevelDown", "coolLevelUp", "coolingSetpoint", "coolLevelDown" ,"thermostatOperatingState", "refresh","relativeHumidity","outdoorTemperature","outdoorHumidity"]) } } def coolLevelUp(){ int nextLevel = device.currentValue("coolingSetpoint") + 1 if( nextLevel > 99){ nextLevel = 99 } log.debug "Setting cool set point up to: ${nextLevel}" setCoolingSetpoint(nextLevel) } def coolLevelDown(){ int nextLevel = device.currentValue("coolingSetpoint") - 1 if( nextLevel < 50){ nextLevel = 50 } log.debug "Setting cool set point down to: ${nextLevel}" setCoolingSetpoint(nextLevel) } def heatLevelUp(){ int nextLevel = device.currentValue("heatingSetpoint") + 1 if( nextLevel > 90){ nextLevel = 90 } log.debug "Setting heat set point up to: ${nextLevel}" setHeatingSetpoint(nextLevel) } def heatLevelDown(){ int nextLevel = device.currentValue("heatingSetpoint") - 1 if( nextLevel < 40){ nextLevel = 40 } log.debug "Setting heat set point down to: ${nextLevel}" setHeatingSetpoint(nextLevel) } // parse events into attributes def parse(String description) { } // handle commands def setHeatingSetpoint(temp) { data.SystemSwitch = 'null' data.HeatSetpoint = temp data.CoolSetpoint = 'null' data.HeatNextPeriod = 'null' data.CoolNextPeriod = 'null' data.StatusHeat='1' data.StatusCool='1' data.FanMode = 'null' setStatus() if(data.SetStatus==1) { sendEvent(name: 'heatingSetpoint', value: temp as Integer) } } def setCoolingSetpoint(temp) { data.SystemSwitch = 'null' data.HeatSetpoint = 'null' data.CoolSetpoint = temp data.HeatNextPeriod = 'null' data.CoolNextPeriod = 'null' data.StatusHeat='1' data.StatusCool='1' data.FanMode = 'null' setStatus() if(data.SetStatus==1) { sendEvent(name: 'coolingSetpoint', value: temp as Integer) } } def setTargetTemp(temp) { data.SystemSwitch = 'null' data.HeatSetpoint = temp data.CoolSetpoint = temp data.HeatNextPeriod = 'null' data.CoolNextPeriod = 'null' data.StatusHeat='1' data.StatusCool='1' data.FanMode = 'null' setStatus() } def off() { setThermostatMode(2) } def auto() { setThermostatMode(4) } def heat() { setThermostatMode(1) } def emergencyHeat() { } def cool() { setThermostatMode(3) } def setThermostatMode(mode) { data.SystemSwitch = mode data.HeatSetpoint = 'null' data.CoolSetpoint = 'null' data.HeatNextPeriod = 'null' data.CoolNextPeriod = 'null' data.StatusHeat=1 data.StatusCool=1 data.FanMode = 'null' setStatus() def switchPos if(mode==1) switchPos = 'heat' if(mode==2) switchPos = 'off' if(mode==3) switchPos = 'cool' /* lgk modified my therm has pos 5 for auto vision pro */ if(mode==4 || swithPos == 5) switchPos = 'auto' if(data.SetStatus==1) { sendEvent(name: 'thermostatMode', value: switchPos) } } def fanOn() { setThermostatFanMode(1) } def fanAuto() { setThermostatFanMode(0) } def fanCirculate() { setThermostatFanMode(2) } def setThermostatFanMode(mode) { data.SystemSwitch = 'null' data.HeatSetpoint = 'null' data.CoolSetpoint = 'null' data.HeatNextPeriod = 'null' data.CoolNextPeriod = 'null' data.StatusHeat='null' data.StatusCool='null' data.FanMode = mode setStatus() def fanMode if(mode==0) fanMode = 'auto' if(mode==1) fanMode = 'on' if(mode==1) fanMode = 'circulate' if(data.SetStatus==1) { sendEvent(name: 'thermostatFanMode', value: fanMode) } } def poll() { refresh() } def setStatus() { data.SetStatus = 0 login() log.debug "Executing 'setStatus'" def today= new Date() log.debug "https://www.mytotalconnectcomfort.com/portal/Device/SubmitControlScreenChanges" def params = [ uri: "https://www.mytotalconnectcomfort.com/portal/Device/SubmitControlScreenChanges", headers: [ 'Accept': 'application/json, text/javascript, */*; q=0.01', 'DNT': '1', 'Accept-Encoding': 'gzip,deflate,sdch', 'Cache-Control': 'max-age=0', 'Accept-Language': 'en-US,en,q=0.8', 'Connection': 'keep-alive', 'Host': 'rs.alarmnet.com', 'Referer': "https://www.mytotalconnectcomfort.com/portal/Device/Control/${settings.honeywelldevice}", 'X-Requested-With': 'XMLHttpRequest', 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36', 'Cookie': data.cookiess ], body: [ DeviceID: "${settings.honeywelldevice}", SystemSwitch : data.SystemSwitch ,HeatSetpoint : data.HeatSetpoint, CoolSetpoint: data.CoolSetpoint, HeatNextPeriod: data.HeatNextPeriod,CoolNextPeriod:data.CoolNextPeriod,StatusHeat:data.StatusHeat,StatusCool:data.StatusCool,FanMode:data.FanMode] ] httpPost(params) { response -> log.debug "Request was successful, $response.status" } log.debug "SetStatus is 1 now" data.SetStatus = 1 } def getStatus() { log.debug "Executing 'getStatus'" def today= new Date() log.debug "https://www.mytotalconnectcomfort.com/portal/Device/CheckDataSession/${settings.honeywelldevice}?_=$today.time" def params = [ uri: "https://www.mytotalconnectcomfort.com/portal/Device/CheckDataSession/${settings.honeywelldevice}", headers: [ 'Accept': '*/*', 'DNT': '1', 'Cache' : 'false', 'dataType': 'json', 'Accept-Encoding': 'plain', 'Cache-Control': 'max-age=0', 'Accept-Language': 'en-US,en,q=0.8', 'Connection': 'keep-alive', 'Referer': 'https://www.mytotalconnectcomfort.com/portal', 'X-Requested-With': 'XMLHttpRequest', 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36', 'Cookie': data.cookiess ], ] httpGet(params) { response -> log.debug "Request was successful, $response.status" // log.debug "ld = $response.data.latestData" def curTemp = response.data.latestData.uiData.DispTemperature def fanMode = response.data.latestData.fanData.fanMode def switchPos = response.data.latestData.uiData.SystemSwitchPosition def coolSetPoint = response.data.latestData.uiData.CoolSetpoint def heatSetPoint = response.data.latestData.uiData.HeatSetpoint def statusCool = response.data.latestData.uiData.StatusCool def statusHeat = response.data.latestData.uiData.StatusHeat def curHumidity = response.data.latestData.uiData.IndoorHumidity def Boolean hasOutdoorHumid = response.data.latestData.uiData.OutdoorHumidityAvailable def Boolean hasOutdoorTemp = response.data.latestData.uiData.OutdoorTemperatureAvailable def curOutdoorHumidity = response.data.latestData.uiData.OutdoorHumidity def curOutdoorTemp = response.data.latestData.uiData.OutdoorTemperature /* ?2?:?48?:?50? ?PM: debug ld = [fanData:[fanModeCirculateAllowed:true, fanModeAutoAllowed:true, fanModeFollowScheduleAllowed:false, fanModeOnAllowed:true, fanMode:0], drData:[Load:127.5, HeatSetpLimit:0, OptOutable:false, DeltaHeatSP:-0.01, CoolSetpLimit:0, Phase:-1, DeltaCoolSP:-0.01], uiData:[OutdoorTemperature:60.0000, TemporaryHoldUntilTime:0, ScheduleHeatSp:68.0000, DeviceID:454832, DispTemperatureAvailable:true, VacationHold:0, VacationHoldUntilTime:0, CoolSetpoint:75.0000, ScheduleCoolSp:75.0000, SwitchHeatAllowed:true, CoolNextPeriod:64, IndoorHumidity:49.0000, SwitchAutoAllowed:true, SetpointChangeAllowed:true, HeatLowerSetptLimit:40.0000, OutdoorHumidStatus:0, SwitchOffAllowed:true, OutdoorHumidityAvailable:true, StatusCool:0, OutdoorTemperatureAvailable:true, StatusHeat:0, CurrentSetpointStatus:0, HoldUntilCapable:true, CoolUpperSetptLimit:99.0000, SwitchCoolAllowed:true, OutdoorHumidity:51.0000, DualSetpointStatus:false, SwitchEmergencyHeatAllowed:false, Commercial:false, CoolLowerSetptLimit:50.0000, OutdoorHumiditySensorNotFault:true, IndoorHumiditySensorAvailable:true, ScheduleCapable:true, DisplayUnits:F, DispTemperature:71.0000, Deadband:3.0000, HeatUpperSetptLimit:90.0000, IsInVacationHoldMode:false, OutdoorTemperatureSensorNotFault:true, HeatSetpoint:68.0000, DispTemperatureStatus:0, HeatNextPeriod:64, IndoorHumiditySensorNotFault:true, OutdoorTempStatus:0, IndoorHumidStatus:0, SystemSwitchPosition:4], canControlHumidification:false, hasFan:true] log.trace("IndoorHumidity: ${response.data.latestData.uiData.IndoorHumidity}") log.trace("OutdoorTemp = ${response.data.latestData.uiData.OutdoorTemperature}") log.trace("fanMode: ${response.data.latestData.fanData.fanMode}") log.trace("SystenSwitchPosition: ${response.data.latestData.uiData.SystemSwitchPosition}") log.trace("StatusCool: ${response.data.latestData.uiData.StatusCool}") log.trace("StatusHeat: ${response.data.latestData.uiData.StatusHeat}") log.trace("IndoorHumiditySensorAvailable: ${response.data.latestData.uiData.IndoorHumiditySensorAvailable}") log.trace("IndoorHumidityAvailable: ${response.data.latestData.uiData.IndoorHumidityAvailable}") log.debug "OutdoorHumidityAvailable: response.data.latestData.uiData.OutdoorHumidityAvailable" log.debug "OutdoorTemperatureAvailable: $response.data.latestData.uiData.OutdoorTemperatureAvailable" log.debug "OutdoorHumiditySensorNotFault = $response.data.latestData.uiData.OutdoorHumiditySensorNotFault" log.debug "OutdoorTemperatureSensorNotFault = $response.data.latestData.uiData.OutdoorTemperatureSensorNotFault" log.debug "IndoorHumiditySensorNotFault: $response.data.latestData.uiData.IndoorHumiditySensorNotFault" log.debug "IndoorHumidStatus: $response.data.latestData.uiData.IndoorHumidStatus" log.debug "OutdoorHumidStatus: $response.data.latestData.uiData.OutdoorHumidStatus" log.debug "OutdoorHumidity: = $response.data.latestData.uiData.OutdoorHumidity" log.debug "OutdoorTemperature = $response.data.latestData.uiData.OutdoorTemperature" log.debug "got curOutdoorTemp = $curOutdoorTemp" log.debug "got curOutdoorHumidity = $curOutdoorHumidity" log.debug "hasOutdoorHumid = $hasOutdoorHumid" log.debug "hasOutdoorTemp = $hasOutdoorTemp" */ //Operating State Section //Set the operating state to off def operatingState = "idle" // lgk operating state not working here.. shows both on ie 1 when heat doesnt go on to 67 and heat till 76 and current is 73 //Check the status of heat and cool if(statusCool == 1 && (switchPos == 3 || switchPos == 5 || swithPos == 4)) { operatingState = "cooling" } else if (statusHeat == 1 && (switchPos == 1 || switchPos == 5 || switchPos == 4)) { operatingState = "heating" } else if (statusCool == 0 && statusHeat == 0) { operatingState = "idle" } else { operatingState = "unknown" } log.trace("Set operating State to: ${operatingState}") //End Operating State // log.debug curTemp // log.debug fanMode // log.debug switchPos //fan mode 0=auto, 2=circ, 1=on if(fanMode==0) fanMode = 'auto' if(fanMode==1) fanMode = 'on' if(fanMode==2) fanMode = 'circulate' if(switchPos==1) switchPos = 'heat' if(switchPos==2) switchPos = 'off' if(switchPos==3) switchPos = 'cool' if(switchPos==4 || switchPos==5) switchPos = 'auto' //Send events sendEvent(name: 'thermostatOperatingState', value: operatingState) sendEvent(name: 'thermostatFanMode', value: fanMode) sendEvent(name: 'thermostatMode', value: switchPos) sendEvent(name: 'coolingSetpoint', value: coolSetPoint as Integer) sendEvent(name: 'heatingSetpoint', value: heatSetPoint as Integer) sendEvent(name: 'temperature', value: curTemp as Integer, state: switchPos) sendEvent(name: 'relativeHumidity', value: curHumidity as Integer) if (hasOutdoorHumid) { sendEvent(name: 'outdoorHumidity', value: curOutdoorHumidity as Integer) } if (hasOutdoorTemp) { sendEvent(name: 'outdoorTemperature', value: curOutdoorTemp as Integer) } } } def getHumidifierStatus() { /* $.ajax({ url: humUrl, type: 'POST', cache: false, dataType: "json", success: function(data) { /portal/Device/Menu/GetHumData/454832'; */ def params = [ uri: "https://www.mytotalconnectcomfort.com/portal/Device/Menu/GetHumData/${settings.honeywelldevice}", headers: [ 'Accept': '*/*', 'DNT': '1', 'dataType': 'json', 'cache': 'false', 'Accept-Encoding': 'plain', 'Cache-Control': 'max-age=0', 'Accept-Language': 'en-US,en,q=0.8', 'Connection': 'keep-alive', 'Host': 'rs.alarmnet.com', 'Referer': 'https://www.mytotalconnectcomfort.com/portal/Menu/${settings.honeywelldevice}', 'X-Requested-With': 'XMLHttpRequest', 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36', 'Cookie': data.cookiess ], ] httpGet(params) { response -> log.debug "GetHumidity Request was successful, $response.status" log.debug "response = $response.data" log.debug "ld = $response.data.latestData" log.debug "humdata = $response.data.latestData.humData" log.trace("lowerLimit: ${response.data.latestData.humData.lowerLimit}") log.trace("upperLimit: ${response.data.humData.upperLimit}") log.trace("SetPoint: ${response.data.humData.Setpoint}") log.trace("DeviceId: ${response.data.humData.DeviceId}") log.trace("IndoorHumidity: ${response.data.humData.IndoorHumidity}") } } def api(method, args = [], success = {}) { } // Need to be logged in before this is called. So don't call this. Call api. def doRequest(uri, args, type, success) { } def refresh() { log.debug "Executing 'refresh'" login() //getHumidifierStatus() getStatus() } def login() { log.debug "Executing 'login'" def params = [ uri: 'https://www.mytotalconnectcomfort.com/portal', headers: [ 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Encoding': 'sdch', 'Host': 'www.mytotalconnectcomfort.com', 'DNT': '1', 'Origin': 'www.mytotalconnectcomfort.com/portal/', 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36' ], body: [timeOffset: '240', UserName: "${settings.username}", Password: "${settings.password}", RememberMe: 'false'] ] data.cookiess = '' httpPost(params) { response -> log.debug "Request was successful, $response.status" log.debug response.headers response.getHeaders('Set-Cookie').each { String cookie = it.value.split(';|,')[0] log.debug "Adding cookie to collection: $cookie" if(cookie != ".ASPXAUTH_TH_A=") { data.cookiess = data.cookiess+cookie+';' } } log.debug "cookies: $data.cookiess" } } def isLoggedIn() { if(!data.auth) { log.debug "No data.auth" return false } def now = new Date().getTime(); return data.auth.expires_in > now }