Ok so this basic SmartApp to test seems to do what it should…
definition(
name: "Test1",
namespace: "nickb512",
author: "nickb512",
description: "",
category: "",
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
iconX3Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png"
)
preferences {
section("Device"){
input "theswitch", "capability.switch", title: "Switch", multiple: false, required: false
}
}
def installed() {
updated()
}
def updated() {
unsubscribe()
subscribe(app, checkSwitch)
}
def checkSwitch(evt) {
log.debug("checkSwitch()")
if (theswitch) log.debug("The switch is selected");
}
So there is a chance I’m going code blind. But here is my code, only thing missing is log() writes the test to log.debug but also posts it to a database of mine (so I can see why ST turned the heating on at 3am randomly, as it does). Good chance its something stupid I’m missing, but a second (or third, or fourth etc) pair of eyes would be appreciated…
definition(
name: "HWS Controller",
namespace: "nickb512",
author: "nickb512",
description: "Smart Home Thermostat",
category: "Green Living",
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
iconX3Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png")
preferences {
section("The GUI"){
input "theGui", "capability.sensor", title: "GUI Device", multiple: true, required: true
}
section("Hot Water System"){
input "hwSwitch", "capability.switch", title: "Master Hot Water Switch", multiple: false, required: true
input "hwRelay", "capability.switch", title: "Hot Water Boiler Relay", multiple: false, required: true
input "hwTemp", "capability.temperatureMeasurement", title: "Hot Water Temperature", multiple: false, required: true
}
section("Central Heating System"){
input "theSwitch", "capability.switch", title: "Master Central Heating Switch", multiple: false, required: true
input "theRelay", "capability.switch", title: "Central Heating Boiler Relay", multiple: false, required: true
}
section("Zone 1"){
input "theStat1", "capability.thermostat", title: "Thermostat", multiple: false, required: false
input "theTemp1", "capability.temperatureMeasurement", title: "Temp Sensor", multiple: false, required: false
}
section("Zone 2"){
input "theStat2", "capability.thermostat", title: "Thermostat", multiple: false, required: false
input "theTemp2", "capability.temperatureMeasurement", title: "Temp Sensor", multiple: false, required: false
}
section("Zone 3"){
input "theStat3", "capability.thermostat", title: "Thermostat", multiple: false, required: false
input "theTemp3", "capability.temperatureMeasurement", title: "Temp Sensor", multiple: false, required: false
}
section("Zone 4"){
input "theStat4", "capability.thermostat", title: "Thermostat", multiple: false, required: false
input "theTemp4", "capability.temperatureMeasurement", title: "Temp Sensor", multiple: false, required: false
}
section("Zone 5"){
input "theStat5", "capability.thermostat", title: "Thermostat", multiple: false, required: false
input "theTemp5", "capability.temperatureMeasurement", title: "Temp Sensor", multiple: false, required: false
}
}
def installed() {
log("Installed with settings: ${settings}")
initialize()
}
def updated() {
log("Updated with settings: ${settings}")
unsubscribe()
initialize()
}
def initialize() {
unsubscribe()
subscribe(app, checkCallForHeat)
subscribe(hwSwitch, "switch", checkHotWater)
subscribe(theSwitch, "switch", checkCallForHeat)
if (theStat1) subscribe(theStat1, "thermostatMode", checkCallForHeat)
if (theStat1) subscribe(theStat1, "thermostatSetpoint", checkCallForHeat)
if (theTemp1) subscribe(theTemp1, "temperature", checkCallForHeat)
if (theStat2) subscribe(theStat2, "thermostatMode", checkCallForHeat)
if (theStat2) subscribe(theStat2, "thermostatSetpoint", checkCallForHeat)
if (theTemp2) subscribe(theTemp2, "temperature", checkCallForHeat)
if (theStat3) subscribe(theStat3, "thermostatMode", checkCallForHeat)
if (theStat3) subscribe(theStat3, "thermostatSetpoint", checkCallForHeat)
if (theTemp3) subscribe(theTemp3, "temperature", checkCallForHeat)
if (theStat4) subscribe(theStat4, "thermostatMode", checkCallForHeat)
if (theStat4) subscribe(theStat4, "thermostatSetpoint", checkCallForHeat)
if (theTemp4) subscribe(theTemp4, "temperature", checkCallForHeat)
if (theStat5) subscribe(theStat5, "thermostatMode", checkCallForHeat)
if (theStat5) subscribe(theStat5, "thermostatSetpoint", checkCallForHeat)
if (theTemp5) subscribe(theTemp5, "temperature", checkCallForHeat)
subscribe(theGui, "button", guiButtonHandler)
subscribe(theSwitch, "timer", chTimerHandler)
subscribe(hwSwitch, "timer", hwTimerHandler)
subscribe(hwTemp, "temperature", hwTempHandler)
}
def checkHotWater(evt) {
log("checkHotWater()")
if (hwSwitch.currentValue("switch") == "on") {
if (hwRelay.currentValue("switch") == "on") {
log("Hot water required and relay on, no change")
} else {
log("Hot water required and relay off, turning relay on")
hwRelay.on()
}
} else {
if (hwRelay.currentValue("switch") == "on") {
log("Hot water not required and relay on, turning relay off")
hwRelay.off()
} else {
log("Hot water not required and relay off, no change")
}
}
}
def checkCallForHeat(evt) {
log("checkCallForHeat()")
boolean callForHeat = false
String zone1state = "idle"
String zone2state = "idle"
String zone3state = "idle"
String zone4state = "idle"
String zone5state = "idle"
if (theTemp1) double zone1NewTemp = theTemp1.currentValue("temperature").toDouble()
if (theTemp2) double zone2NewTemp = theTemp2.currentValue("temperature").toDouble()
if (theTemp3) double zone3NewTemp = theTemp3.currentValue("temperature").toDouble()
if (theTemp4) double zone4NewTemp = theTemp4.currentValue("temperature").toDouble()
if (theTemp5) double zone5NewTemp = theTemp5.currentValue("temperature").toDouble()
if (theStat1) double zone1OldTemp = theStat1.currentValue("temperature").toDouble()
if (theStat2) double zone2OldTemp = theStat2.currentValue("temperature").toDouble()
if (theStat3) double zone3OldTemp = theStat3.currentValue("temperature").toDouble()
if (theStat4) double zone4OldTemp = theStat4.currentValue("temperature").toDouble()
if (theStat5) double zone5OldTemp = theStat5.currentValue("temperature").toDouble()
if (theStat1) double zone1Setpoint = theStat1.currentValue("thermostatSetpoint").toDouble()
if (theStat2) double zone2Setpoint = theStat2.currentValue("thermostatSetpoint").toDouble()
if (theStat3) double zone3Setpoint = theStat3.currentValue("thermostatSetpoint").toDouble()
if (theStat4) double zone4Setpoint = theStat4.currentValue("thermostatSetpoint").toDouble()
if (theStat5) double zone5Setpoint = theStat5.currentValue("thermostatSetpoint").toDouble()
log(zone1NewTemp)
log(zone2NewTemp)
log(zone3NewTemp)
log(zone4NewTemp)
log(zone5NewTemp)
if (theSwitch.currentValue("switch") == "on") {
log("Master switch on, checking zones")
if (theStat1) {
if (theStat1.currentValue("thermostatMode") == "heat") {
if (zone1NewTemp < zone1Setpoint) {
callForHeat = true
zone1state = "heating";
log("Zone 1 Call for Heat")
} else {
log("Zone 1 satisfied")
}
} else {
log("Zone 1 off")
}
}
if (theStat2) {
if (theStat2.currentValue("thermostatMode") == "heat") {
if (zone2NewTemp < zone2Setpoint) {
callForHeat = true
zone2state = "heating";
log("Zone 2 Call for Heat")
} else {
log("Zone 2 satisfied")
}
} else {
log("Zone 2 off")
}
}
if (theStat3) {
if (theStat3.currentValue("thermostatMode") == "heat") {
if (zone3NewTemp < zone3Setpoint) {
callForHeat = true
zone3state = "heating";
log("Zone 3 Call for Heat")
} else {
log("Zone 3 satisfied")
}
} else {
log("Zone 3 off")
}
}
if (theStat4) {
if (theStat4.currentValue("thermostatMode") == "heat") {
if (zone4NewTemp < zone4Setpoint) {
callForHeat = true
zone4state = "heating";
log("Zone 4 Call for Heat")
} else {
log("Zone 4 satisfied")
}
} else {
log("Zone 4 off")
}
}
if (theStat5) {
if (theStat5.currentValue("thermostatMode") == "heat") {
if (zone5NewTemp < zone5Setpoint) {
callForHeat = true
zone5state = "heating";
log("Zone 5 Call for Heat")
} else {
log("Zone 5 satisfied")
}
} else {
log("Zone 5 off")
}
}
} else {
log("Master switch off")
}
if (callForHeat) {
if (theRelay.currentValue("switch") == "on") {
log("Heat required and relay on, no change")
} else {
log("Heat required and relay off, turning relay on")
theRelay.on()
}
} else {
if (theRelay.currentValue("switch") == "on") {
log("Heat not required and relay on, turning relay off")
theRelay.off()
} else {
log("Heat not required and relay off, no change")
}
}
if (theStat1) {
if (zone1NewTemp != zone1OldTemp && theStat1.hasCommand("setTemp")) theStat1.setTemp(zone1NewTemp)
if (theStat1.currentValue("thermostatOperatingState") != zone1state && theStat1.hasCommand("setState")) theStat1.setState(zone1state)
}
if (theStat2) {
if (zone2NewTemp != zone2OldTemp && theStat2.hasCommand("setTemp")) theStat2.setTemp(zone2NewTemp)
if (theStat2.currentValue("thermostatOperatingState") != zone2state && theStat2.hasCommand("setState")) theStat2.setState(zone2state)
}
if (theStat3) {
if (zone3NewTemp != zone3OldTemp && theStat3.hasCommand("setTemp")) theStat3.setTemp(zone3NewTemp)
if (theStat3.currentValue("thermostatOperatingState") != zone3state && theStat3.hasCommand("setState")) theStat3.setState(zone3state)
}
if (theStat4) {
if (zone4NewTemp != zone4OldTemp && theStat4.hasCommand("setTemp")) theStat4.setTemp(zone4NewTemp)
if (theStat4.currentValue("thermostatOperatingState") != zone4state && theStat4.hasCommand("setState")) theStat4.setState(zone4state)
}
if (theStat5) {
if (zone5NewTemp != zone5OldTemp && theStat5.hasCommand("setTemp")) theStat5.setTemp(zone5NewTemp)
if (theStat5.currentValue("thermostatOperatingState") != zone5state && theStat5.hasCommand("setState")) theStat5.setState(zone5state)
}
theGui.each { gui ->
log("Updating GUI")
if (theTemp1 && zone1NewTemp != gui.currentValue("z1temp") && gui.hasCommand("z1temp")) gui.z1temp(zone1NewTemp)
if (theTemp2 && zone2NewTemp != gui.currentValue("z2temp") && gui.hasCommand("z2temp")) gui.z2temp(zone2NewTemp)
if (theTemp3 && zone3NewTemp != gui.currentValue("z3temp") && gui.hasCommand("z3temp")) gui.z3temp(zone3NewTemp)
if (theTemp4 && zone4NewTemp != gui.currentValue("z4temp") && gui.hasCommand("z4temp")) gui.z4temp(zone4NewTemp)
if (theTemp5 && zone5NewTemp != gui.currentValue("z5temp") && gui.hasCommand("z5temp")) gui.z5temp(zone5NewTemp)
if (theStat1 && zone1Setpoint != gui.currentValue("z1set") && gui.hasCommand("z1set")) gui.z1set(zone1Setpoint)
if (theStat2 && zone1Setpoint != gui.currentValue("z2set") && gui.hasCommand("z2set")) gui.z2set(zone2Setpoint)
if (theStat3 && zone1Setpoint != gui.currentValue("z3set") && gui.hasCommand("z3set")) gui.z3set(zone3Setpoint)
if (theStat4 && zone1Setpoint != gui.currentValue("z4set") && gui.hasCommand("z4set")) gui.z4set(zone4Setpoint)
if (theStat5 && zone1Setpoint != gui.currentValue("z5set") && gui.hasCommand("z5set")) gui.z5set(zone5Setpoint)
}
}
def guiButtonHandler(evt) {
log("guiButtonHandler()")
switch (evt.value) {
case "choff":
ch.off()
break;
case "chon":
ch.on()
break;
case "ch30m":
ch.on30m()
break;
case "ch1h":
ch.on1h()
break;
case "ch2h":
ch.on2h()
break;
case "hwoff":
hw.off()
break;
case "hwon":
hw.on()
break;
case "hw30m":
hw.on30m()
break;
case "hw1h":
hw.on1h()
break;
case "hw2h":
hw.on2h()
break;
case "z1set":
theStat1.thermostatSetpoint(evt.data.setpoint)
break;
case "z2set":
theStat2.thermostatSetpoint(evt.data.setpoint)
break;
case "z3set":
theStat3.thermostatSetpoint(evt.data.setpoint)
break;
case "z4set":
theStat4.thermostatSetpoint(evt.data.setpoint)
break;
case "z5set":
theStat5.thermostatSetpoint(evt.data.setpoint)
break;
}
}
def chTimerHandler(evt) {
log("chTimerHandler()")
theGui.chstate(evt.value)
}
def hwTimerHandler(evt) {
log("hwTimerHandler()")
theGui.hwstate(evt.value)
}
def hwTempHandler(evt) {
log("hwTempHandler()")
theGui.hwtemp(evt.value)
}